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