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 2009 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
34 emlxs_ip_handle_event(emlxs_hba_t *hba, RING *rp, 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 (rp->ringno != FC_IP_RING) {
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[FC_IP_RING] &
146 				    NLP_RPI_XRI)) {
147 					ndlp->nlp_Xri = 0;
148 					(void) emlxs_create_xri(port, rp, 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
178 emlxs_ip_handle_unsol_req(emlxs_port_t *port, RING *rp, 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_PORT_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 			    getPaddr(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[FC_IP_RING] & NLP_RPI_XRI)) {
235 				(void) emlxs_create_xri(port, rp, 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_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
301 emlxs_ip_handle_rcv_seq_list(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
302 {
303 	emlxs_port_t *port = &PPORT;
304 	IOCB *cmd;
305 	uint64_t bdeAddr;
306 	MATCHMAP *mp = NULL;
307 #ifdef SLI3_SUPPORT
308 	HBQE_t *hbqE;
309 	uint32_t hbq_id;
310 	uint32_t hbqe_tag;
311 #endif /* SLI3_SUPPORT */
312 
313 	/*
314 	 * No action required for now.
315 	 */
316 	cmd = &iocbq->iocb;
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 ringno=0x%x", cmd->ulpCommand, cmd->ulpIoTag,
323 	    cmd->ulpStatus, cmd->un.ulpWord[4], rp->ringno);
324 
325 	if (cmd->ulpStatus) {
326 		goto out;
327 	}
328 #ifdef SLI3_SUPPORT
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->hbq_table[hbq_id];
337 
338 		HBASTATS.IpUbPosted--;
339 
340 		if (hbqe_tag >= hbq->HBQ_numEntries) {
341 			mp = NULL;
342 		} else {
343 			mp = hba->hbq_table[hbq_id].HBQ_PostBufs[hbqe_tag];
344 		}
345 	} else
346 #endif /* SLI3_SUPPORT */
347 	{
348 		/* Check for valid buffer */
349 		if (!(cmd->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID)) {
350 			bdeAddr =
351 			    getPaddr(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 #ifdef SLI3_SUPPORT
360 	if (hba->flag & FC_HBQ_ENABLED) {
361 		emlxs_update_HBQ_index(hba, hbq_id);
362 	} else
363 #endif /* SLI3_SUPPORT */
364 	{
365 		if (mp) {
366 			(void) emlxs_mem_put(hba, MEM_IPBUF, (uint8_t *)mp);
367 		}
368 		(void) emlxs_post_buffer(hba, rp, 1);
369 	}
370 
371 	HBASTATS.IpDropped++;
372 
373 	return (0);
374 
375 }  /* emlxs_ip_handle_rcv_seq_list() */
376 
377 
378 
379 /*
380  * Process a create_xri command completion.
381  */
382 extern int32_t
383 emlxs_handle_create_xri(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
384 {
385 	emlxs_port_t *port = &PPORT;
386 	IOCB *cmd;
387 	NODELIST *ndlp;
388 	fc_packet_t *pkt;
389 	emlxs_buf_t *sbp;
390 
391 	cmd = &iocbq->iocb;
392 
393 	sbp = (emlxs_buf_t *)iocbq->sbp;
394 
395 	if (!sbp) {
396 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
397 		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x",
398 		    cmd->ulpCommand, cmd->ulpIoTag, cmd->ulpStatus,
399 		    cmd->un.ulpWord[4]);
400 
401 		return (EIO);
402 	}
403 
404 	/* check for first xmit completion in sequence */
405 	ndlp = (NODELIST *)sbp->node;
406 
407 	if (cmd->ulpStatus) {
408 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
409 		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x",
410 		    cmd->ulpCommand, cmd->ulpIoTag, cmd->ulpStatus,
411 		    cmd->un.ulpWord[4]);
412 
413 		mutex_enter(&EMLXS_RINGTX_LOCK);
414 		ndlp->nlp_flag[rp->ringno] &= ~NLP_RPI_XRI;
415 		mutex_exit(&EMLXS_RINGTX_LOCK);
416 
417 		return (EIO);
418 	}
419 
420 	mutex_enter(&EMLXS_RINGTX_LOCK);
421 	ndlp->nlp_Xri = cmd->ulpContext;
422 	ndlp->nlp_flag[rp->ringno] &= ~NLP_RPI_XRI;
423 	mutex_exit(&EMLXS_RINGTX_LOCK);
424 
425 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
426 	    "create_xri completed: DID=0x%x Xri=0x%x iotag=0x%x",
427 	    ndlp->nlp_DID, ndlp->nlp_Xri, cmd->ulpIoTag);
428 
429 	pkt = sbp->pkt;
430 	emlxs_pkt_free(pkt);
431 
432 	return (0);
433 
434 }  /* emlxs_handle_create_xri()  */
435 
436 
437 /*
438  * Issue an iocb command to create an exchange with the remote Nport
439  * specified by the NODELIST entry.
440  */
441 extern int32_t
442 emlxs_create_xri(emlxs_port_t *port, RING *rp, NODELIST *ndlp)
443 {
444 	emlxs_hba_t *hba = HBA;
445 	IOCB *icmd;
446 	IOCBQ *iocbq;
447 	fc_packet_t *pkt;
448 	emlxs_buf_t *sbp;
449 	uint16_t iotag;
450 
451 	/* Check if an XRI has already been requested */
452 	mutex_enter(&EMLXS_RINGTX_LOCK);
453 	if (ndlp->nlp_Xri != 0 || (ndlp->nlp_flag[rp->ringno] & NLP_RPI_XRI)) {
454 		mutex_exit(&EMLXS_RINGTX_LOCK);
455 		return (0);
456 	}
457 	ndlp->nlp_flag[rp->ringno] |= NLP_RPI_XRI;
458 	mutex_exit(&EMLXS_RINGTX_LOCK);
459 
460 	if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
461 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
462 		    "create_xri failed: Unable to allocate pkt. did=0x%x",
463 		    ndlp->nlp_DID);
464 
465 		goto fail;
466 	}
467 
468 	sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
469 	iocbq = &sbp->iocbq;
470 
471 	/* Get the iotag by registering the packet */
472 	iotag = emlxs_register_pkt(rp, sbp);
473 
474 	if (!iotag) {
475 		/*
476 		 * No more command slots available, retry later
477 		 */
478 		emlxs_pkt_free(pkt);
479 
480 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
481 		    "create_xri failed: Unable to allocate IOTAG. did=0x%x",
482 		    ndlp->nlp_DID);
483 
484 		goto fail;
485 	}
486 
487 	icmd = &iocbq->iocb;
488 	icmd->ulpIoTag = iotag;
489 	icmd->ulpContext = ndlp->nlp_Rpi;
490 	icmd->ulpLe = 1;
491 	icmd->ulpCommand = CMD_CREATE_XRI_CR;
492 	icmd->ulpOwner = OWN_CHIP;
493 
494 	/* Initalize iocbq */
495 	iocbq->port = (void *)port;
496 	iocbq->node = (void *)ndlp;
497 	iocbq->ring = (void *)rp;
498 
499 	mutex_enter(&sbp->mtx);
500 	sbp->node = (void *)ndlp;
501 	sbp->ring = rp;
502 	mutex_exit(&sbp->mtx);
503 
504 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
505 	    "create_xri sent: DID=0x%x Xri=0x%x iotag=0x%x", ndlp->nlp_DID,
506 	    ndlp->nlp_Xri, iotag);
507 
508 	emlxs_sli_issue_iocb_cmd(hba, rp, iocbq);
509 
510 	return (0);
511 
512 fail:
513 
514 	/* Clear the XRI flag */
515 	mutex_enter(&EMLXS_RINGTX_LOCK);
516 	ndlp->nlp_flag[rp->ringno] &= ~NLP_RPI_XRI;
517 	mutex_exit(&EMLXS_RINGTX_LOCK);
518 
519 	return (1);
520 
521 }  /* emlxs_create_xri() */
522