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 if (IpDropped) {
282 HBASTATS.IpDropped++;
283 }
284
285 if (IpBcastReceived) {
286 HBASTATS.IpBcastReceived++;
287 }
288
289 if (IpSeqReceived) {
290 HBASTATS.IpSeqReceived++;
291 }
292
293 return (0);
294
295 } /* emlxs_ip_handle_unsol_req() */
296
297
298 extern int32_t
emlxs_ip_handle_rcv_seq_list(emlxs_hba_t * hba,CHANNEL * cp,IOCBQ * iocbq)299 emlxs_ip_handle_rcv_seq_list(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
300 {
301 emlxs_port_t *port = &PPORT;
302 IOCB *cmd;
303 uint64_t bdeAddr;
304 MATCHMAP *mp = NULL;
305 HBQE_t *hbqE;
306 uint32_t hbq_id;
307 uint32_t hbqe_tag;
308 RING *rp;
309
310 /*
311 * No action required for now.
312 */
313 cmd = &iocbq->iocb;
314 rp = &hba->sli.sli3.ring[cp->channelno];
315
316 HBASTATS.IpRcvEvent++;
317
318 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
319 "Receive sequence list: cmd=0x%x iotag=0x%x status=0x%x "
320 "w4=0x%x channelno=0x%x", cmd->ULPCOMMAND, cmd->ULPIOTAG,
321 cmd->ULPSTATUS, cmd->un.ulpWord[4], cp->channelno);
322
323 if (cmd->ULPSTATUS) {
324 goto out;
325 }
326
327 hbqE = (HBQE_t *)&iocbq->iocb;
328 hbq_id = hbqE->unt.ext.HBQ_tag;
329 hbqe_tag = hbqE->unt.ext.HBQE_tag;
330
331 if (hba->flag & FC_HBQ_ENABLED) {
332 HBQ_INIT_t *hbq;
333
334 hbq = &hba->sli.sli3.hbq_table[hbq_id];
335
336 HBASTATS.IpUbPosted--;
337
338 if (hbqe_tag >= hbq->HBQ_numEntries) {
339 mp = NULL;
340 } else {
341 mp = hba->sli.sli3.hbq_table
342 [hbq_id].HBQ_PostBufs[hbqe_tag];
343 }
344 } else {
345 /* Check for valid buffer */
346 if (!(cmd->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID)) {
347 bdeAddr =
348 PADDR(cmd->un.cont64[0].addrHigh,
349 cmd->un.cont64[0].addrLow);
350 mp = emlxs_mem_get_vaddr(hba, rp, bdeAddr);
351 }
352 }
353
354 out:
355
356 if (hba->flag & FC_HBQ_ENABLED) {
357 emlxs_update_HBQ_index(hba, hbq_id);
358 } else {
359 if (mp) {
360 emlxs_mem_put(hba, MEM_IPBUF, (void *)mp);
361 }
362 (void) emlxs_post_buffer(hba, rp, 1);
363 }
364
365 HBASTATS.IpDropped++;
366
367 return (0);
368
369 } /* emlxs_ip_handle_rcv_seq_list() */
370
371
372
373 /*
374 * Process a create_xri command completion.
375 */
376 extern int32_t
emlxs_handle_create_xri(emlxs_hba_t * hba,CHANNEL * cp,IOCBQ * iocbq)377 emlxs_handle_create_xri(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
378 {
379 emlxs_port_t *port = &PPORT;
380 IOCB *cmd;
381 NODELIST *ndlp;
382 fc_packet_t *pkt;
383 emlxs_buf_t *sbp;
384 int32_t rval = 0;
385
386 cmd = &iocbq->iocb;
387
388 sbp = (emlxs_buf_t *)iocbq->sbp;
389
390 if (!sbp) {
391 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
392 "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
393 "NULL sbp found.",
394 cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
395 cmd->un.ulpWord[4]);
396
397 return (EIO);
398 }
399
400 /* check for first xmit completion in sequence */
401 ndlp = (NODELIST *)sbp->node;
402
403 if (!ndlp) {
404 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
405 "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
406 "NULL node found.",
407 cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
408 cmd->un.ulpWord[4]);
409
410 rval = EIO;
411 goto done;
412 }
413
414 if (cmd->ULPSTATUS) {
415 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
416 "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
417 "Completion error.",
418 cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
419 cmd->un.ulpWord[4]);
420
421 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
422 ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
423 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
424
425 rval = EIO;
426 goto done;
427 }
428
429 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
430 ndlp->nlp_Xri = cmd->ULPCONTEXT;
431 ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
432 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
433
434 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
435 "create_xri completed: DID=0x%x Xri=0x%x iotag=0x%x",
436 ndlp->nlp_DID, ndlp->nlp_Xri, cmd->ULPIOTAG);
437
438 done:
439 pkt = sbp->pkt;
440 if (pkt) {
441 emlxs_pkt_free(pkt);
442 }
443
444 return (rval);
445
446 } /* emlxs_handle_create_xri() */
447
448
449 /*
450 * Issue an iocb command to create an exchange with the remote Nport
451 * specified by the NODELIST entry.
452 */
453 extern int32_t
emlxs_create_xri(emlxs_port_t * port,CHANNEL * cp,NODELIST * ndlp)454 emlxs_create_xri(emlxs_port_t *port, CHANNEL *cp, NODELIST *ndlp)
455 {
456 emlxs_hba_t *hba = HBA;
457 IOCB *icmd;
458 IOCBQ *iocbq;
459 fc_packet_t *pkt;
460 emlxs_buf_t *sbp;
461 uint16_t iotag;
462
463 /* Check if an XRI has already been requested */
464 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
465 if (ndlp->nlp_Xri != 0 ||
466 (ndlp->nlp_flag[cp->channelno] & NLP_RPI_XRI)) {
467 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
468 return (0);
469 }
470 ndlp->nlp_flag[cp->channelno] |= NLP_RPI_XRI;
471 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
472
473 if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
474 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
475 "create_xri failed: Unable to allocate pkt. did=0x%x",
476 ndlp->nlp_DID);
477
478 goto fail;
479 }
480
481 sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
482 iocbq = &sbp->iocbq;
483
484 /* Clear the PACKET_ULP_OWNED flag */
485 sbp->pkt_flags &= ~PACKET_ULP_OWNED;
486
487 /* Get the iotag by registering the packet */
488 iotag = emlxs_register_pkt(cp, sbp);
489
490 if (!iotag) {
491 /*
492 * No more command slots available, retry later
493 */
494 emlxs_pkt_free(pkt);
495
496 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
497 "create_xri failed: Unable to allocate IOTAG. did=0x%x",
498 ndlp->nlp_DID);
499
500 goto fail;
501 }
502
503 icmd = &iocbq->iocb;
504 icmd->ULPIOTAG = iotag;
505 icmd->ULPCONTEXT = ndlp->nlp_Rpi;
506 icmd->ULPLE = 1;
507 icmd->ULPCOMMAND = CMD_CREATE_XRI_CR;
508 icmd->ULPOWNER = OWN_CHIP;
509
510 /* Initalize iocbq */
511 iocbq->port = (void *)port;
512 iocbq->node = (void *)ndlp;
513 iocbq->channel = (void *)cp;
514
515 mutex_enter(&sbp->mtx);
516 sbp->node = (void *)ndlp;
517 sbp->channel = cp;
518 mutex_exit(&sbp->mtx);
519
520 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
521 "create_xri sent: DID=0x%x Xri=0x%x iotag=0x%x", ndlp->nlp_DID,
522 ndlp->nlp_Xri, iotag);
523
524 EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
525
526 return (0);
527
528 fail:
529
530 /* Clear the XRI flag */
531 mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
532 ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
533 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
534
535 return (1);
536
537 } /* emlxs_create_xri() */
538