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