1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <emlxs.h>
29 
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_IP_C);
32 
33 
34 extern int32_t
35 emlxs_ip_handle_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
36 {
37 	emlxs_port_t *port = &PPORT;
38 	IOCB *cmd;
39 	emlxs_buf_t *sbp;
40 	NODELIST *ndlp;
41 
42 	cmd = &iocbq->iocb;
43 
44 	HBASTATS.IpEvent++;
45 
46 	sbp = (emlxs_buf_t *)iocbq->sbp;
47 
48 	if (!sbp) {
49 		HBASTATS.IpStray++;
50 
51 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
52 		    "cmd=0x%x iotag=0x%x status=0x%x perr=0x%x",
53 		    (uint32_t)cmd->ULPCOMMAND, (uint32_t)cmd->ULPIOTAG,
54 		    cmd->ULPSTATUS, cmd->un.ulpWord[4]);
55 
56 		return (EIO);
57 	}
58 
59 	if (cp->channelno != hba->channel_ip) {
60 		HBASTATS.IpStray++;
61 
62 		return (0);
63 	}
64 
65 	port = sbp->iocbq.port;
66 
67 	switch (cmd->ULPCOMMAND) {
68 		/*
69 		 * Error: Abnormal BCAST command completion  (Local error)
70 		 */
71 	case CMD_XMIT_BCAST_CN:
72 	case CMD_XMIT_BCAST64_CN:
73 
74 		HBASTATS.IpBcastCompleted++;
75 		HBASTATS.IpBcastError++;
76 
77 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
78 		    "XMIT BCAST completion error cmd=0x%x status=0x%x "
79 		    "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS,
80 		    cmd->un.ulpWord[4], cmd->un.ulpWord[5]);
81 
82 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
83 		    cmd->un.grsp.perr.statLocalError, 1);
84 
85 		break;
86 
87 		/*
88 		 * Error: Abnormal XMIT SEQUENCE command completion
89 		 * (Local error)
90 		 */
91 	case CMD_XMIT_SEQUENCE_CR:
92 	case CMD_XMIT_SEQUENCE64_CR:
93 
94 		HBASTATS.IpSeqCompleted++;
95 		HBASTATS.IpSeqError++;
96 
97 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
98 		    "XMIT SEQUENCE CR completion error: cmd=%x status=0x%x "
99 		    "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS,
100 		    cmd->un.ulpWord[4], cmd->un.ulpWord[5]);
101 
102 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
103 		    cmd->un.grsp.perr.statLocalError, 1);
104 
105 		break;
106 
107 		/*
108 		 * Normal BCAST completion
109 		 */
110 	case CMD_XMIT_BCAST_CX:
111 	case CMD_XMIT_BCAST64_CX:
112 
113 		HBASTATS.IpBcastCompleted++;
114 		HBASTATS.IpBcastGood++;
115 
116 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
117 		    "XMIT BCAST CN completion: cmd=%x status=0x%x [%08x,%08x]",
118 		    cmd->ULPCOMMAND, cmd->ULPSTATUS, cmd->un.ulpWord[4],
119 		    cmd->un.ulpWord[5]);
120 
121 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
122 		    cmd->un.grsp.perr.statLocalError, 1);
123 
124 		break;
125 
126 		/*
127 		 * Normal XMIT SEQUENCE completion
128 		 */
129 	case CMD_XMIT_SEQUENCE_CX:
130 	case CMD_XMIT_SEQUENCE64_CX:
131 
132 		HBASTATS.IpSeqCompleted++;
133 
134 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
135 		    "XMIT SEQUENCE CR completion: cmd=%x status=0x%x"
136 		    "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS,
137 		    cmd->un.ulpWord[4], cmd->un.ulpWord[5]);
138 
139 		if (cmd->ULPSTATUS) {
140 			HBASTATS.IpSeqError++;
141 
142 			if ((cmd->ULPSTATUS == IOSTAT_LOCAL_REJECT) &&
143 			    ((cmd->un.ulpWord[4] & 0xff) == IOERR_NO_XRI)) {
144 				ndlp = (NODELIST *)sbp->node;
145 				if ((cmd->ULPCONTEXT == ndlp->nlp_Xri) &&
146 				    !(ndlp->nlp_flag[hba->channel_ip] &
147 				    NLP_RPI_XRI)) {
148 					ndlp->nlp_Xri = 0;
149 					(void) emlxs_create_xri(port, cp, ndlp);
150 				}
151 			}
152 		} else {
153 			HBASTATS.IpSeqGood++;
154 		}
155 
156 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
157 		    cmd->un.grsp.perr.statLocalError, 1);
158 
159 		break;
160 
161 	default:
162 
163 		HBASTATS.IpStray++;
164 
165 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_ip_msg,
166 		    "Invalid iocb: cmd=0x%x", cmd->ULPCOMMAND);
167 
168 		break;
169 
170 	}	/* switch(cmd->ULPCOMMAND) */
171 
172 
173 	return (0);
174 
175 } /* emlxs_ip_handle_event() */
176 
177 
178 extern int32_t
179 emlxs_ip_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
180     MATCHMAP *mp, uint32_t size)
181 {
182 	emlxs_hba_t *hba = HBA;
183 	fc_unsol_buf_t *ubp;
184 	IOCB *cmd;
185 	NETHDR *nd;
186 	NODELIST *ndlp;
187 	uint8_t *mac;
188 	emlxs_ub_priv_t *ub_priv;
189 	uint32_t sid;
190 	uint32_t i;
191 	uint32_t IpDropped = 1;
192 	uint32_t IpBcastReceived = 0;
193 	uint32_t IpSeqReceived = 0;
194 
195 	cmd = &iocbq->iocb;
196 	ubp = NULL;
197 
198 	for (i = 0; i < MAX_VPORTS; i++) {
199 		port = &VPORT(i);
200 
201 		if (!(port->flag & EMLXS_PORT_BOUND) ||
202 		    !(port->flag & EMLXS_PORT_IP_UP)) {
203 			continue;
204 		}
205 
206 		ubp =
207 		    (fc_unsol_buf_t *)emlxs_ub_get(port, size,
208 		    FC_TYPE_IS8802_SNAP, 0);
209 
210 		if (!ubp) {
211 			/* Theoretically we should never get here. */
212 			/* There should be one DMA buffer for every ub */
213 			/* buffer. If we are out of ub buffers */
214 			/* then some how this matching has been corrupted */
215 
216 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg,
217 			    "Buffer not found. paddr=%lx",
218 			    PADDR(cmd->un.cont64[0].addrHigh,
219 			    cmd->un.cont64[0].addrLow));
220 
221 			continue;
222 		}
223 
224 		bcopy(mp->virt, ubp->ub_buffer, size);
225 
226 		ub_priv = ubp->ub_fca_private;
227 		nd = (NETHDR *)ubp->ub_buffer;
228 		mac = nd->fc_srcname.IEEE;
229 		ndlp = emlxs_node_find_mac(port, mac);
230 
231 		if (ndlp) {
232 			sid = ndlp->nlp_DID;
233 
234 			if ((ndlp->nlp_Xri == 0) &&
235 			    !(ndlp->nlp_flag[hba->channel_ip] & NLP_RPI_XRI)) {
236 				(void) emlxs_create_xri(port, cp, ndlp);
237 			}
238 		}
239 
240 		/*
241 		 * If no node is found, then check if this is a
242 		 * broadcast frame
243 		 */
244 		else if (cmd->un.xrseq.w5.hcsw.Fctl & BC) {
245 			sid = cmd->un.ulpWord[4] & 0x00ffffff;
246 		}
247 
248 		else {
249 			/* We have to drop this frame because we do not have */
250 			/* the S_ID of the request */
251 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg,
252 			    "Node not found. mac=%02x%02x%02x%02x%02x%02x",
253 			    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
254 
255 			(void) emlxs_fca_ub_release((opaque_t)port, 1,
256 			    &ubp->ub_token);
257 
258 			continue;
259 		}
260 
261 		if (cmd->un.xrseq.w5.hcsw.Fctl & BC) {
262 			IpBcastReceived++;
263 		} else {
264 			IpSeqReceived++;
265 		}
266 
267 		/*
268 		 * Setup frame header
269 		 */
270 		ubp->ub_frame.r_ctl = cmd->un.xrseq.w5.hcsw.Rctl;
271 		ubp->ub_frame.type = cmd->un.xrseq.w5.hcsw.Type;
272 		ubp->ub_frame.s_id = sid;
273 		ubp->ub_frame.ox_id = ub_priv->token;
274 		ubp->ub_frame.rx_id = cmd->ULPCONTEXT;
275 		ubp->ub_class = FC_TRAN_CLASS3;
276 
277 		emlxs_ub_callback(port, ubp);
278 		IpDropped = 0;
279 	}
280 	port = &PPORT;
281 
282 out:
283 
284 	if (IpDropped) {
285 		HBASTATS.IpDropped++;
286 	}
287 
288 	if (IpBcastReceived) {
289 		HBASTATS.IpBcastReceived++;
290 	}
291 
292 	if (IpSeqReceived) {
293 		HBASTATS.IpSeqReceived++;
294 	}
295 
296 	return (0);
297 
298 } /* emlxs_ip_handle_unsol_req() */
299 
300 
301 extern int32_t
302 emlxs_ip_handle_rcv_seq_list(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
303 {
304 	emlxs_port_t *port = &PPORT;
305 	IOCB *cmd;
306 	uint64_t bdeAddr;
307 	MATCHMAP *mp = NULL;
308 	HBQE_t *hbqE;
309 	uint32_t hbq_id;
310 	uint32_t hbqe_tag;
311 	RING *rp;
312 
313 	/*
314 	 * No action required for now.
315 	 */
316 	cmd = &iocbq->iocb;
317 	rp = &hba->sli.sli3.ring[cp->channelno];
318 
319 	HBASTATS.IpRcvEvent++;
320 
321 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
322 	    "Receive sequence list: cmd=0x%x iotag=0x%x status=0x%x "
323 	    "w4=0x%x channelno=0x%x", cmd->ULPCOMMAND, cmd->ULPIOTAG,
324 	    cmd->ULPSTATUS, cmd->un.ulpWord[4], cp->channelno);
325 
326 	if (cmd->ULPSTATUS) {
327 		goto out;
328 	}
329 
330 	hbqE = (HBQE_t *)&iocbq->iocb;
331 	hbq_id = hbqE->unt.ext.HBQ_tag;
332 	hbqe_tag = hbqE->unt.ext.HBQE_tag;
333 
334 	if (hba->flag & FC_HBQ_ENABLED) {
335 		HBQ_INIT_t *hbq;
336 
337 		hbq = &hba->sli.sli3.hbq_table[hbq_id];
338 
339 		HBASTATS.IpUbPosted--;
340 
341 		if (hbqe_tag >= hbq->HBQ_numEntries) {
342 			mp = NULL;
343 		} else {
344 			mp = hba->sli.sli3.hbq_table
345 			    [hbq_id].HBQ_PostBufs[hbqe_tag];
346 		}
347 	} else {
348 		/* Check for valid buffer */
349 		if (!(cmd->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID)) {
350 			bdeAddr =
351 			    PADDR(cmd->un.cont64[0].addrHigh,
352 			    cmd->un.cont64[0].addrLow);
353 			mp = emlxs_mem_get_vaddr(hba, rp, bdeAddr);
354 		}
355 	}
356 
357 out:
358 
359 	if (hba->flag & FC_HBQ_ENABLED) {
360 		emlxs_update_HBQ_index(hba, hbq_id);
361 	} else {
362 		if (mp) {
363 			emlxs_mem_put(hba, MEM_IPBUF, (void *)mp);
364 		}
365 		(void) emlxs_post_buffer(hba, rp, 1);
366 	}
367 
368 	HBASTATS.IpDropped++;
369 
370 	return (0);
371 
372 } /* emlxs_ip_handle_rcv_seq_list() */
373 
374 
375 
376 /*
377  * Process a create_xri command completion.
378  */
379 extern int32_t
380 emlxs_handle_create_xri(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
381 {
382 	emlxs_port_t *port = &PPORT;
383 	IOCB *cmd;
384 	NODELIST *ndlp;
385 	fc_packet_t *pkt;
386 	emlxs_buf_t *sbp;
387 
388 	cmd = &iocbq->iocb;
389 
390 	sbp = (emlxs_buf_t *)iocbq->sbp;
391 
392 	if (!sbp) {
393 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
394 		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x",
395 		    cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
396 		    cmd->un.ulpWord[4]);
397 
398 		return (EIO);
399 	}
400 
401 	/* check for first xmit completion in sequence */
402 	ndlp = (NODELIST *)sbp->node;
403 
404 	if (cmd->ULPSTATUS) {
405 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
406 		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x",
407 		    cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
408 		    cmd->un.ulpWord[4]);
409 
410 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
411 		ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
412 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
413 
414 		return (EIO);
415 	}
416 
417 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
418 	ndlp->nlp_Xri = cmd->ULPCONTEXT;
419 	ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
420 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
421 
422 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
423 	    "create_xri completed: DID=0x%x Xri=0x%x iotag=0x%x",
424 	    ndlp->nlp_DID, ndlp->nlp_Xri, cmd->ULPIOTAG);
425 
426 	pkt = sbp->pkt;
427 	emlxs_pkt_free(pkt);
428 
429 	return (0);
430 
431 } /* emlxs_handle_create_xri()  */
432 
433 
434 /*
435  * Issue an iocb command to create an exchange with the remote Nport
436  * specified by the NODELIST entry.
437  */
438 extern int32_t
439 emlxs_create_xri(emlxs_port_t *port, CHANNEL *cp, NODELIST *ndlp)
440 {
441 	emlxs_hba_t *hba = HBA;
442 	IOCB *icmd;
443 	IOCBQ *iocbq;
444 	fc_packet_t *pkt;
445 	emlxs_buf_t *sbp;
446 	uint16_t iotag;
447 
448 	/* Check if an XRI has already been requested */
449 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
450 	if (ndlp->nlp_Xri != 0 ||
451 	    (ndlp->nlp_flag[cp->channelno] & NLP_RPI_XRI)) {
452 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
453 		return (0);
454 	}
455 	ndlp->nlp_flag[cp->channelno] |= NLP_RPI_XRI;
456 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
457 
458 	if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
459 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
460 		    "create_xri failed: Unable to allocate pkt. did=0x%x",
461 		    ndlp->nlp_DID);
462 
463 		goto fail;
464 	}
465 
466 	sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
467 	iocbq = &sbp->iocbq;
468 
469 	/* Clear the PACKET_ULP_OWNED flag */
470 	sbp->pkt_flags &= ~PACKET_ULP_OWNED;
471 
472 	/* Get the iotag by registering the packet */
473 	iotag = emlxs_register_pkt(cp, sbp);
474 
475 	if (!iotag) {
476 		/*
477 		 * No more command slots available, retry later
478 		 */
479 		emlxs_pkt_free(pkt);
480 
481 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
482 		    "create_xri failed: Unable to allocate IOTAG. did=0x%x",
483 		    ndlp->nlp_DID);
484 
485 		goto fail;
486 	}
487 
488 	icmd = &iocbq->iocb;
489 	icmd->ULPIOTAG = iotag;
490 	icmd->ULPCONTEXT = ndlp->nlp_Rpi;
491 	icmd->ULPLE = 1;
492 	icmd->ULPCOMMAND = CMD_CREATE_XRI_CR;
493 	icmd->ULPOWNER = OWN_CHIP;
494 
495 	/* Initalize iocbq */
496 	iocbq->port = (void *)port;
497 	iocbq->node = (void *)ndlp;
498 	iocbq->channel = (void *)cp;
499 
500 	mutex_enter(&sbp->mtx);
501 	sbp->node = (void *)ndlp;
502 	sbp->channel = cp;
503 	mutex_exit(&sbp->mtx);
504 
505 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
506 	    "create_xri sent: DID=0x%x Xri=0x%x iotag=0x%x", ndlp->nlp_DID,
507 	    ndlp->nlp_Xri, iotag);
508 
509 	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
510 
511 	return (0);
512 
513 fail:
514 
515 	/* Clear the XRI flag */
516 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
517 	ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
518 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
519 
520 	return (1);
521 
522 } /* emlxs_create_xri() */
523