5045 use atomic_{inc,dec}_* instead of atomic_add_*
[illumos-gate.git] / usr / src / uts / common / io / fibre-channel / fca / fcoei / fcoei_eth.c
blobac1a4809acf7bff4cc0b58f48d45286f9bb46bb5
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * The following notice accompanied the original version of this file:
25 * BSD LICENSE
27 * Copyright(c) 2007 Intel Corporation. All rights reserved.
28 * All rights reserved.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
34 * * Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * * Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in
38 * the documentation and/or other materials provided with the
39 * distribution.
40 * * Neither the name of Intel Corporation nor the names of its
41 * contributors may be used to endorse or promote products derived
42 * from this software without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
47 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
48 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
62 * This file defines interface functions between fcoe and fcoei driver.
65 #include <sys/conf.h>
66 #include <sys/ddi.h>
67 #include <sys/stat.h>
68 #include <sys/pci.h>
69 #include <sys/sunddi.h>
70 #include <sys/modctl.h>
71 #include <sys/file.h>
72 #include <sys/cred.h>
73 #include <sys/byteorder.h>
74 #include <sys/atomic.h>
75 #include <sys/scsi/scsi.h>
76 #include <sys/mac_client.h>
77 #include <sys/modhash.h>
80 * LEADVILLE header files
82 #include <sys/fibre-channel/fc.h>
83 #include <sys/fibre-channel/impl/fc_fcaif.h>
86 * COMSTAR header files
88 #include <sys/stmf_defines.h>
91 * FCOE header files
93 #include <sys/fcoe/fcoe_common.h>
96 * Driver's own header files
98 #include <fcoei.h>
101 * Forward declaration of internal functions
103 static void fcoei_process_unsol_els_req(fcoe_frame_t *frm);
104 static void fcoei_process_sol_els_rsp(fcoe_frame_t *frm);
105 static void fcoei_process_unsol_abts_req(fcoe_frame_t *frame);
106 static void fcoei_process_sol_abts_acc(fcoe_frame_t *frame);
107 static void fcoei_process_sol_abts_rjt(fcoe_frame_t *frame);
108 static void fcoei_process_sol_ct_rsp(fcoe_frame_t *frame);
109 static void fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frame);
110 static void fcoei_process_sol_fcp_resp(fcoe_frame_t *frm);
112 static void fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size);
113 static void fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch,
114 int size);
117 * fcoei_rx_frame
118 * Unsolicited frame is received
120 * Input:
121 * frame = unsolicited frame that is received
123 * Return:
124 * N/A
126 * Comment:
127 * N/A
129 static void
130 fcoei_rx_frame(fcoe_frame_t *frm)
132 if (!(FRM2SS(frm)->ss_flags & SS_FLAG_LV_BOUND)) {
134 * Release the frame and netb
136 FCOEI_LOG(__FUNCTION__, "not bound now");
137 frm->frm_eport->eport_free_netb(frm->frm_netb);
138 frm->frm_eport->eport_release_frame(frm);
139 return;
142 FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_UNSOL_FRAME;
143 FRM2IFM(frm)->ifm_ae.ae_obj = frm;
145 mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
146 list_insert_tail(&FRM2SS(frm)->ss_event_list, &FRM2IFM(frm)->ifm_ae);
147 if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
148 cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
150 mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
154 * fcoei_release_sol_frame
155 * Release the solicited frame that has just been sent out
157 * Input:
158 * frame = solicited frame that has been sent out
160 * Returns:
161 * N/A
163 * Comments:
164 * After FCOE sends solicited frames out, it will call this to notify
165 * FCOEI of the completion.
167 static void
168 fcoei_release_sol_frame(fcoe_frame_t *frm)
171 * For request-type frames, it's safe to be handled out of
172 * watchdog, because it needn't update anything
174 switch (FRM2IFM(frm)->ifm_rctl) {
175 case R_CTL_SOLICITED_DATA:
176 case R_CTL_COMMAND:
177 case R_CTL_ELS_REQ:
178 case R_CTL_UNSOL_CONTROL:
179 case R_CTL_LS_ABTS:
180 FRM2SS(frm)->ss_eport->eport_release_frame(frm);
181 break;
183 default:
184 FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_SOL_FRAME;
185 FRM2IFM(frm)->ifm_ae.ae_obj = frm;
187 mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
188 list_insert_tail(&FRM2SS(frm)->ss_event_list,
189 &FRM2IFM(frm)->ifm_ae);
190 if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
191 cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
193 mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
194 break;
199 * fcoei_process_unsol_xfer_rdy
200 * XFER_RDY is received
202 * Input:
203 * frm = XFER_RDY frame
205 * Returns:
206 * N/A
208 * Comments:
209 * N/A
211 static void
212 fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frm)
214 uint16_t sol_oxid;
215 fcoei_exchange_t *xch;
216 int rcv_buf_size;
217 int offset;
218 int left_size;
219 int data_size;
220 int frm_num;
221 int idx;
222 fcoe_frame_t *nfrm;
224 sol_oxid = FRM_OXID(frm);
225 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
226 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
227 return;
231 * rcv_buf_size is the total size of data that should be transferred
232 * in this sequence.
233 * offset is based on the exchange not the sequence.
235 xch->xch_rxid = FRM_RXID(frm);
236 rcv_buf_size = FCOE_B2V_4(frm->frm_payload + 4);
237 offset = FCOE_B2V_4(frm->frm_payload);
238 ASSERT(xch->xch_resid >= rcv_buf_size);
241 * Local variables initialization
243 left_size = rcv_buf_size;
244 data_size = FRM2SS(frm)->ss_fcp_data_payload_size;
245 frm_num = (rcv_buf_size + data_size - 1) / data_size;
247 for (idx = 0; idx < frm_num - 1; idx++) {
249 * The first (frm_num -1) frames are always full
251 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
252 FRM2SS(frm)->ss_eport, data_size + FCFH_SIZE, NULL);
253 if (nfrm == NULL) {
254 FCOEI_LOG(__FUNCTION__, "can't alloc frame");
255 return;
259 * Copy the data payload that will be transferred
261 bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
262 nfrm->frm_payload, nfrm->frm_payload_size);
264 FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
265 FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
266 FFM_F_CTL(0x010008, nfrm);
267 FFM_OXID(xch->xch_oxid, nfrm);
268 FFM_RXID(xch->xch_rxid, nfrm);
269 FFM_S_ID(FRM_D_ID(frm), nfrm);
270 FFM_D_ID(FRM_S_ID(frm), nfrm);
271 FFM_SEQ_CNT(idx, nfrm);
272 FFM_PARAM(offset, nfrm);
273 fcoei_init_ifm(nfrm, xch);
276 * Submit the frame
278 xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
281 * Update offset and left_size
283 offset += data_size;
284 left_size -= data_size;
288 * Send the last data frame of this sequence
290 data_size = left_size;
291 nfrm = xch->xch_ss->ss_eport->eport_alloc_frame(
292 xch->xch_ss->ss_eport, data_size + FCFH_SIZE, NULL);
293 if (nfrm != NULL) {
294 fcoei_init_ifm(nfrm, xch);
295 } else {
296 ASSERT(0);
297 return;
301 * Copy the data payload that will be transferred
303 bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
304 nfrm->frm_payload, nfrm->frm_payload_size);
307 * Set ifm_rctl for fcoei_handle_sol_frame_done
309 FRM2IFM(nfrm)->ifm_rctl = R_CTL_SOLICITED_DATA;
312 * FFM
314 FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
315 FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
316 FFM_F_CTL(0x090008, nfrm);
317 FFM_OXID(xch->xch_oxid, nfrm);
318 FFM_RXID(xch->xch_rxid, nfrm);
319 FFM_S_ID(FRM_D_ID(frm), nfrm);
320 FFM_D_ID(FRM_S_ID(frm), nfrm);
321 FFM_SEQ_CNT(idx, nfrm);
322 FFM_PARAM(offset, nfrm);
325 * Submit the frame
327 xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
330 * Sequence is a transaction, so we need only update
331 * xch_remained_bytes in the end.
333 xch->xch_resid -= rcv_buf_size;
337 * fcoei_process_unsol_els_req
338 * els req frame is received
340 * Input:
341 * frm = ELS request frame
343 * Returns:
344 * N/A
346 * Comments:
347 * We will not create exchange data structure at this time,
348 * and we should create unsolicited buffer, which will only
349 * contain the exchange's request payload.
351 static void
352 fcoei_process_unsol_els_req(fcoe_frame_t *frm)
354 fc_unsol_buf_t *ub;
355 fc_rscn_t *rscn;
356 uint32_t offset;
357 fcoei_exchange_t *xch_tmp;
360 * Get the unsol rxid first
362 FCOEI_SET_UNSOL_FRM_RXID(frm, xch_tmp);
365 * Do proper ub initialization
367 ub = (fc_unsol_buf_t *)kmem_zalloc(sizeof (fc_unsol_buf_t), KM_SLEEP);
368 ub->ub_class = FC_TRAN_CLASS3;
369 ub->ub_bufsize = frm->frm_payload_size;
370 ub->ub_buffer = kmem_alloc(frm->frm_payload_size, KM_SLEEP);
371 ub->ub_port_handle = FRM2SS(frm);
372 ub->ub_token = (uint64_t)(long)ub;
375 * header conversion
376 * Caution: ub_buffer is big endian, but ub_frame should be host-format
377 * RSCN is one exception.
379 FCOEI_FRM2FHDR(frm, &ub->ub_frame);
382 * If it's FLOGI, and our FLOGI failed last time,
383 * then we post online event
385 if ((FRM2SS(frm)->ss_flags & SS_FLAG_FLOGI_FAILED) &&
386 (frm->frm_payload[0] == LA_ELS_FLOGI)) {
387 frm->frm_eport->eport_flags |=
388 EPORT_FLAG_IS_DIRECT_P2P;
389 FRM2SS(frm)->ss_bind_info.port_statec_cb(FRM2SS(frm)->ss_port,
390 FC_STATE_ONLINE);
393 switch (frm->frm_payload[0]) {
394 case LA_ELS_RSCN:
396 * Only RSCN need byte swapping
398 rscn = (fc_rscn_t *)(void *)ub->ub_buffer;
399 rscn->rscn_code = frm->frm_payload[0];
400 rscn->rscn_len = frm->frm_payload[1];
401 rscn->rscn_payload_len =
402 FCOE_B2V_2(frm->frm_payload + 2);
404 offset = 4;
405 for (int i = 0; i < rscn->rscn_payload_len - 4; i += 4) {
406 *(uint32_t *)((intptr_t)(uint8_t *)ub->ub_buffer +
407 offset) = FCOE_B2V_4(frm->frm_payload + offset);
408 offset += 4;
410 break;
412 default:
413 bcopy(frm->frm_payload, ub->ub_buffer, frm->frm_payload_size);
414 break;
418 * Pass this unsol ELS up to Leadville
420 FRM2SS(frm)->ss_bind_info.port_unsol_cb(FRM2SS(frm)->ss_port, ub, 0);
424 * fcoei_search_abort_xch
425 * Find the exchange that should be aborted
427 * Input:
428 * key = oxid of the exchange
429 * val = the exchange
430 * arg = the soft state
432 * Returns:
433 * MH_WALK_TERMINATE = found it, terminate the walk
434 * MH_WALK_CONTINUE = not found, continue the walk
436 * Comments:
437 * N/A
439 /* ARGSUSED */
440 static uint32_t
441 fcoei_search_abort_xch(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
443 fcoei_walk_arg_t *wa = (fcoei_walk_arg_t *)arg;
444 fcoei_exchange_t *xch = (fcoei_exchange_t *)val;
446 if (xch->xch_oxid == wa->wa_oxid) {
447 wa->wa_xch = xch;
448 ASSERT(xch->xch_oxid == CMHK(key));
449 return (MH_WALK_TERMINATE);
452 return (MH_WALK_CONTINUE);
456 * fcoei_process_unsol_abts_req
457 * ABTS request is received
459 * Input:
460 * frm = ABTS request frame
462 * Returns:
463 * N/A
465 * Comments:
466 * The remote side wants to abort one unsolicited exchange.
468 static void
469 fcoei_process_unsol_abts_req(fcoe_frame_t *frm)
471 fcoei_exchange_t *xch = NULL;
472 fcoe_frame_t *nfrm;
473 int payload_size;
474 fcoei_walk_arg_t walk_arg;
477 * According to spec, the responder could want to ABTS xch too
479 if (FRM_SENDER_IS_XCH_RESPONDER(frm)) {
480 uint16_t sol_oxid = FRM_OXID(frm);
481 (void) mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
482 FMHK(sol_oxid), (mod_hash_val_t *)&xch);
483 } else {
485 * it's a unsolicited exchange, and we need find it out from
486 * unsolicited hash table. But at this time, RXID in frame could
487 * still be 0xFFFF in most cases, so we need do exaustive search
489 walk_arg.wa_xch = NULL;
490 walk_arg.wa_oxid = FRM_OXID(frm);
491 mod_hash_walk(FRM2SS(frm)->ss_unsol_rxid_hash,
492 fcoei_search_abort_xch, &walk_arg);
493 xch = walk_arg.wa_xch;
496 if (xch == NULL) {
497 payload_size = 4;
498 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
499 FRM2SS(frm)->ss_eport,
500 payload_size + FCFH_SIZE, NULL);
501 if (nfrm == NULL) {
502 FCOEI_LOG(__FUNCTION__, "can't alloc frame");
503 return;
506 bzero(nfrm->frm_payload, nfrm->frm_payload_size);
507 nfrm->frm_payload[1] = 0x05;
508 nfrm->frm_payload[3] = 0xAA;
509 FFM_R_CTL(R_CTL_LS_BA_RJT, nfrm);
510 fcoei_init_ifm(nfrm, xch);
511 } else {
513 * We should complete the exchange with frm as NULL,
514 * and we don't care its success or failure
516 fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE, FC_REASON_ABTX);
519 * Construct ABTS ACC frame
521 payload_size = 12;
522 nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
523 FRM2SS(frm)->ss_eport, payload_size + FCFH_SIZE, NULL);
524 if (nfrm == NULL) {
525 FCOEI_LOG(__FUNCTION__, "can't alloc frame");
526 return;
529 bzero(nfrm->frm_payload, nfrm->frm_payload_size);
530 nfrm->frm_payload[4] = 0xFF & (xch->xch_oxid >> 8);
531 nfrm->frm_payload[5] = 0xFF & (xch->xch_oxid);
532 nfrm->frm_payload[6] = 0xFF & (xch->xch_rxid >> 8);
533 nfrm->frm_payload[7] = 0xFF & (xch->xch_rxid);
534 nfrm->frm_payload[10] = 0xFF;
535 nfrm->frm_payload[11] = 0xFF;
537 FFM_R_CTL(R_CTL_LS_BA_ACC, nfrm);
538 fcoei_init_ifm(nfrm, xch);
541 FFM_D_ID(FRM_S_ID(frm), nfrm);
542 FFM_S_ID(FRM_D_ID(frm), nfrm);
543 FFM_TYPE(FRM_TYPE(frm), nfrm);
544 FFM_F_CTL(FRM_F_CTL(frm), nfrm);
545 FFM_OXID(FRM_OXID(frm), nfrm);
546 FFM_RXID(FRM_RXID(frm), nfrm);
547 FRM2SS(frm)->ss_eport->eport_tx_frame(nfrm);
551 * fcoei_process_sol_fcp_resp
552 * FCP response is received
554 * Input:
555 * frm = FCP response frame
557 * Returns:
558 * N/A
560 * Comments:
561 * N/A
563 static void
564 fcoei_process_sol_fcp_resp(fcoe_frame_t *frm)
566 uint16_t sol_oxid;
567 uint32_t actual_size;
568 fcoei_exchange_t *xch = NULL;
569 fc_packet_t *fpkt = NULL;
570 mod_hash_val_t val;
571 uint32_t i_fcp_status;
574 * Firstly, we search the related exchange
576 sol_oxid = FRM_OXID(frm);
577 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
578 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
579 PRT_FRM_HDR(__FUNCTION__, frm);
580 FCOEI_LOG(__FUNCTION__, "can't find the corresponding xch: "
581 "oxid/%x %lu - %lu", sol_oxid,
582 CURRENT_CLOCK, frm->frm_clock);
583 return;
584 } else {
585 fpkt = xch->xch_fpkt;
589 * Decide the actual response length
591 actual_size = fpkt->pkt_rsplen;
592 if (actual_size > frm->frm_payload_size) {
593 actual_size = frm->frm_payload_size;
597 * Update the exchange and hash table
599 (void) mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
600 FMHK(xch->xch_oxid), &val);
601 ASSERT((fcoei_exchange_t *)val == xch);
602 xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
605 * Upate fpkt related elements
607 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
610 * we should set pkt_reason and pkt_state carefully
612 fpkt->pkt_state = FC_PKT_SUCCESS;
613 fpkt->pkt_reason = 0;
616 * First we zero the first 12 byte of dest
618 bzero(xch->xch_fpkt->pkt_resp, 12);
619 i_fcp_status = BE_IN32(frm->frm_payload + 8);
620 if (i_fcp_status != 0) {
621 fcoei_fill_fcp_resp(frm->frm_payload,
622 (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
626 * Update pkt_resp_resid
628 fpkt->pkt_data_resid = xch->xch_resid;
629 if ((xch->xch_resid != 0) && ((xch->xch_resid % 0x200) == 0) &&
630 ((xch->xch_fpkt->pkt_datalen % 0x200) == 0) &&
631 (i_fcp_status == 0)) {
632 FCOEI_LOG(__FUNCTION__, "frame lost no pause ? %x/%x",
633 xch->xch_resid, xch->xch_fpkt->pkt_datalen);
634 fpkt->pkt_state = FC_PKT_LOCAL_RJT;
635 fpkt->pkt_reason = FC_REASON_UNDERRUN;
639 * Notify LV it's over
641 if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
642 FCOEI_LOG(__FUNCTION__, "BEFORE WAKEUP: %p-%p", fpkt, xch);
643 sema_v(&xch->xch_sema);
644 FCOEI_LOG(__FUNCTION__, "AFTERE WAKEUP: %p-%p", fpkt, xch);
645 } else {
646 xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
651 * fcoei_process_sol_els_rsp
652 * ELS response is received
654 * Input:
655 * frm = ELS response frame
657 * Returns:
658 * N/A
660 * Comments:
661 * N/A
663 static void
664 fcoei_process_sol_els_rsp(fcoe_frame_t *frm)
666 uint16_t sol_oxid = 0;
667 uint32_t actual_size = 0;
668 fcoei_exchange_t *xch;
669 fc_packet_t *fpkt;
672 * Look for the related exchange
674 xch = NULL;
675 fpkt = NULL;
676 sol_oxid = FRM_OXID(frm);
677 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
678 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
679 PRT_FRM_HDR(__FUNCTION__, frm);
680 FCOEI_LOG(__FUNCTION__, "can't find the "
681 "corresponding xch: oxid/%x", sol_oxid);
682 return;
685 xch->xch_rxid = FRM_RXID(frm);
686 fpkt = xch->xch_fpkt;
689 * Decide the actual response length
691 actual_size = frm->frm_payload_size;
692 if (actual_size > fpkt->pkt_rsplen) {
693 FCOEI_LOG(__FUNCTION__, "pkt_rsplen is smaller"
694 "0x(%x - %x)", actual_size, fpkt->pkt_rsplen);
695 actual_size = fpkt->pkt_rsplen;
699 * Upate fpkt related elements
701 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
702 fcoei_fill_els_fpkt_resp(frm, xch, actual_size);
705 * we should set pkt_reason and pkt_state carefully now
706 * Need to analyze pkt_reason according to the response.
707 * Leave it untouched now.
709 if (((ls_code_t *)(void *)xch->xch_fpkt->pkt_resp)->ls_code ==
710 LA_ELS_RJT) {
711 fcoei_complete_xch(xch, NULL, FC_PKT_FABRIC_RJT,
712 FC_REASON_INVALID_PARAM);
713 } else {
714 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
719 * fcoei_process_sol_ct_rsp
720 * CT response is received
722 * Input:
723 * frm = CT response frame
725 * Returns:
726 * N/A
728 * Comments:
729 * N/A
731 static void
732 fcoei_process_sol_ct_rsp(fcoe_frame_t *frm)
734 uint16_t sol_oxid = 0;
735 uint32_t actual_size = 0;
736 fcoei_exchange_t *xch;
737 fc_packet_t *fpkt;
740 * Look for the related exchange
742 xch = NULL;
743 fpkt = NULL;
744 sol_oxid = FRM_OXID(frm);
745 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
746 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
747 FCOEI_LOG(__FUNCTION__, "can't find the "
748 "corresponding xch: oxid/%x", sol_oxid);
749 return;
752 xch->xch_rxid = FRM_RXID(frm);
753 fpkt = xch->xch_fpkt;
756 * Decide the actual response length
758 actual_size = fpkt->pkt_rsplen;
759 if (actual_size > frm->frm_payload_size) {
760 FCOEI_LOG(__FUNCTION__, "payload is smaller"
761 "0x(%x - %x)", actual_size, frm->frm_payload_size);
762 actual_size = frm->frm_payload_size;
766 * Update fpkt related elements
767 * Caution: we needn't do byte swapping for CT response
769 FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
770 bcopy(FPLD, (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
773 * Complete it with frm as NULL
775 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
779 * fcoei_process_sol_abts_acc
780 * ABTS accpet is received
782 * Input:
783 * frm = ABTS accept frame
785 * Returns:
786 * N/A
788 * Comments:
789 * We will always finish the abortion of solicited exchanges,
790 * so we will not depend on the response from the remote side.
791 * We just log one message.
793 static void
794 fcoei_process_sol_abts_acc(fcoe_frame_t *frm)
796 FCOEI_LOG(__FUNCTION__, "the remote side has agreed to "
797 "abort the exchange: oxid-%x, rxid-%x",
798 FCOE_B2V_2(frm->frm_payload + 4),
799 FCOE_B2V_2(frm->frm_payload + 6));
803 * fcoei_process_sol_abts_rjt
804 * ABTS reject is received
806 * Input:
807 * frm = ABTS reject frame
809 * Returns:
810 * N/A
812 * Comments:
813 * We will alwayas finish the abortion of solicited exchanges,
814 * so we will not depend on the response from the remote side.
815 * We just log one message.
817 static void
818 fcoei_process_sol_abts_rjt(fcoe_frame_t *frm)
820 FCOEI_LOG(__FUNCTION__, "the remote side rejected "
821 "our request to abort one exchange.: %p", frm);
825 * fcoei_fill_els_fpkt_resp
826 * Fill fpkt ELS response in host format according frm payload
828 * Input:
829 * src = frm payload in link format
830 * dest = fpkt ELS response in host format
831 * size = Maximum conversion size
832 * els_op = ELS opcode
834 * Returns:
835 * N/A
837 * Comments:
838 * fpkt->pkt_resp must be mapped to one data structure, and it's
839 * different from the content in the raw frame
841 static void
842 fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch, int size)
844 uint8_t *src = frm->frm_payload;
845 uint8_t *dest = (uint8_t *)xch->xch_fpkt->pkt_resp;
846 ls_code_t *els_code = (ls_code_t *)(void *)dest;
847 la_els_logi_t *els_logi = (la_els_logi_t *)(void *)dest;
848 la_els_adisc_t *els_adisc = (la_els_adisc_t *)(void *)dest;
849 la_els_rls_acc_t *els_rls;
850 la_els_rnid_acc_t *els_rnid;
851 struct fcp_prli_acc *prli_acc;
852 int offset;
854 els_code->ls_code = FCOE_B2V_1(src);
855 if (els_code->ls_code == LA_ELS_RJT) {
856 FCOEI_LOG(__FUNCTION__, "size :%d", size);
857 return;
860 switch (((ls_code_t *)(void *)xch->xch_fpkt->pkt_cmd)->ls_code) {
861 case LA_ELS_FLOGI:
862 bcopy((char *)frm->frm_hdr - 22,
863 frm->frm_eport->eport_efh_dst, ETHERADDRL);
864 if (frm->frm_payload[8] & 0x10) {
866 * We are in fabric p2p mode
868 uint8_t src_addr[ETHERADDRL];
869 frm->frm_eport->eport_flags &=
870 ~EPORT_FLAG_IS_DIRECT_P2P;
871 FCOE_SET_DEFAULT_OUI(src_addr);
872 bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
873 frm->frm_eport->eport_set_mac_address(
874 frm->frm_eport, src_addr, 1);
875 } else {
877 * We are in direct p2p mode
879 frm->frm_eport->eport_flags |=
880 EPORT_FLAG_IS_DIRECT_P2P;
883 if (!(FRM2SS(frm)->ss_eport->eport_flags &
884 EPORT_FLAG_IS_DIRECT_P2P)) {
885 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
888 /* FALLTHROUGH */
890 case LA_ELS_PLOGI:
891 if (FRM2SS(frm)->ss_eport->eport_flags &
892 EPORT_FLAG_IS_DIRECT_P2P) {
893 FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
894 FRM2SS(frm)->ss_p2p_info.d_id = FRM_S_ID(frm);
897 offset = offsetof(la_els_logi_t, common_service);
898 els_logi->common_service.fcph_version = FCOE_B2V_2(src +
899 offset);
900 offset += 2;
901 els_logi->common_service.btob_credit = FCOE_B2V_2(src +
902 offset);
903 offset += 2;
904 els_logi->common_service.cmn_features = FCOE_B2V_2(src +
905 offset);
906 offset += 2;
907 els_logi->common_service.rx_bufsize = FCOE_B2V_2(src +
908 offset);
909 offset += 2;
910 els_logi->common_service.conc_sequences = FCOE_B2V_2(src +
911 offset);
912 offset += 2;
913 els_logi->common_service.relative_offset = FCOE_B2V_2(src +
914 offset);
915 offset += 2;
916 els_logi->common_service.e_d_tov = FCOE_B2V_4(src +
917 offset);
920 * port/node WWN
922 offset = offsetof(la_els_logi_t, nport_ww_name);
923 bcopy(src + offset, &els_logi->nport_ww_name, 8);
924 offset = offsetof(la_els_logi_t, node_ww_name);
925 bcopy(src + offset, &els_logi->node_ww_name, 8);
928 * class_3
930 offset = offsetof(la_els_logi_t, class_3);
931 els_logi->class_3.class_opt = FCOE_B2V_2(src + offset);
932 offset += 2;
933 els_logi->class_3.initiator_ctl = FCOE_B2V_2(src + offset);
934 offset += 2;
935 els_logi->class_3.recipient_ctl = FCOE_B2V_2(src + offset);
936 offset += 2;
937 els_logi->class_3.rcv_size = FCOE_B2V_2(src + offset);
938 offset += 2;
939 els_logi->class_3.conc_sequences = FCOE_B2V_2(src + offset);
940 offset += 2;
941 els_logi->class_3.n_port_e_to_e_credit = FCOE_B2V_2(src +
942 offset);
943 offset += 2;
944 els_logi->class_3.open_seq_per_xchng = FCOE_B2V_2(src + offset);
946 break;
948 case LA_ELS_PRLI:
950 * PRLI service parameter response page
952 * fcp_prli_acc doesn't include ls_code, don't use offsetof
954 offset = 4;
955 prli_acc = (struct fcp_prli_acc *)(void *)(dest + offset);
956 prli_acc->type = FCOE_B2V_1(src + offset);
958 * Type code extension
960 offset += 1;
962 * PRLI response flags
964 offset += 1;
965 prli_acc->orig_process_assoc_valid =
966 (FCOE_B2V_2(src + offset) & BIT_15) ? 1 : 0;
967 prli_acc->resp_process_assoc_valid =
968 (FCOE_B2V_2(src + offset) & BIT_14) ? 1 : 0;
969 prli_acc->image_pair_established =
970 (FCOE_B2V_2(src + offset) & BIT_13) ? 1 : 0;
971 prli_acc->accept_response_code =
972 (FCOE_B2V_2(src + offset) & 0x0F00) >> 8;
974 * process associator
976 offset += 2;
977 prli_acc->orig_process_associator = FCOE_B2V_4(src + offset);
978 offset += 4;
979 prli_acc->resp_process_associator = FCOE_B2V_4(src + offset);
981 * FC-4 type
983 offset += 4;
984 prli_acc->initiator_fn =
985 (FCOE_B2V_4(src + offset) & BIT_5) ? 1 : 0;
986 prli_acc->target_fn =
987 (FCOE_B2V_4(src + offset) & BIT_4) ? 1 : 0;
988 prli_acc->cmd_data_mixed =
989 (FCOE_B2V_4(src + offset) & BIT_3) ? 1 : 0;
990 prli_acc->data_resp_mixed =
991 (FCOE_B2V_4(src + offset) & BIT_2) ? 1 : 0;
992 prli_acc->read_xfer_rdy_disabled =
993 (FCOE_B2V_4(src + offset) & BIT_1) ? 1 : 0;
994 prli_acc->write_xfer_rdy_disabled =
995 (FCOE_B2V_4(src + offset) & BIT_0) ? 1 : 0;
997 break;
999 case LA_ELS_LOGO:
1001 * could only be LS_ACC, no additional information
1003 els_code->ls_code = FCOE_B2V_1(src);
1004 break;
1006 case LA_ELS_SCR:
1008 * LS_ACC/LS_RJT, no additional information
1010 els_code->ls_code = FCOE_B2V_1(src);
1011 break;
1013 case LA_ELS_ADISC:
1014 offset = 5;
1015 els_adisc->hard_addr.hard_addr = FCOE_B2V_3(src + offset);
1016 offset = offsetof(la_els_adisc_t, port_wwn);
1017 bcopy(src + offset, &els_adisc->port_wwn, 8);
1018 offset = offsetof(la_els_adisc_t, node_wwn);
1019 bcopy(src + offset, &els_adisc->node_wwn, 8);
1020 offset += 9;
1021 els_adisc->nport_id.port_id = FCOE_B2V_3(src + offset);
1022 break;
1023 case LA_ELS_RLS:
1024 els_rls = (la_els_rls_acc_t *)(void *)dest;
1025 els_rls->ls_code.ls_code = FCOE_B2V_1(src);
1026 offset = 4;
1027 els_rls->rls_link_params.rls_link_fail =
1028 FCOE_B2V_4(src + offset);
1029 offset = 8;
1030 els_rls->rls_link_params.rls_sync_loss =
1031 FCOE_B2V_4(src + offset);
1032 offset = 12;
1033 els_rls->rls_link_params.rls_sig_loss =
1034 FCOE_B2V_4(src + offset);
1035 offset = 16;
1036 els_rls->rls_link_params.rls_prim_seq_err =
1037 FCOE_B2V_4(src + offset);
1038 offset = 20;
1039 els_rls->rls_link_params.rls_invalid_word =
1040 FCOE_B2V_4(src + offset);
1041 offset = 24;
1042 els_rls->rls_link_params.rls_invalid_crc =
1043 FCOE_B2V_4(src + offset);
1044 break;
1045 case LA_ELS_RNID:
1046 els_rnid = (la_els_rnid_acc_t *)(void *)dest;
1047 els_rnid->ls_code.ls_code = FCOE_B2V_1(src);
1048 offset = 4;
1049 bcopy(src + offset, &els_rnid->hdr.data_format, 1);
1050 offset = 5;
1051 bcopy(src + offset, &els_rnid->hdr.cmn_len, 1);
1052 offset = 7;
1053 bcopy(src + offset, &els_rnid->hdr.specific_len, 1);
1054 offset = 8;
1055 bcopy(src + offset, els_rnid->data, FCIO_RNID_MAX_DATA_LEN);
1056 break;
1057 default:
1058 FCOEI_LOG(__FUNCTION__, "unsupported R_CTL");
1059 break;
1064 * fcoei_fill_fcp_resp
1065 * Fill fpkt FCP response in host format according to frm payload
1067 * Input:
1068 * src - frm payload in link format
1069 * dest - fpkt FCP response in host format
1070 * size - Maximum conversion size
1072 * Returns:
1073 * N/A
1075 * Comments:
1076 * This is called only for SCSI response with non good status
1078 static void
1079 fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size)
1081 fcp_rsp_t *fcp_rsp_iu = (fcp_rsp_t *)(void *)dest;
1082 int offset;
1085 * set fcp_status
1087 offset = offsetof(fcp_rsp_t, fcp_u);
1088 offset += 2;
1089 fcp_rsp_iu->fcp_u.fcp_status.resid_under =
1090 (FCOE_B2V_1(src + offset) & BIT_3) ? 1 : 0;
1091 fcp_rsp_iu->fcp_u.fcp_status.resid_over =
1092 (FCOE_B2V_1(src + offset) & BIT_2) ? 1 : 0;
1093 fcp_rsp_iu->fcp_u.fcp_status.sense_len_set =
1094 (FCOE_B2V_1(src + offset) & BIT_1) ? 1 : 0;
1095 fcp_rsp_iu->fcp_u.fcp_status.rsp_len_set =
1096 (FCOE_B2V_1(src + offset) & BIT_0) ? 1 : 0;
1097 offset += 1;
1098 fcp_rsp_iu->fcp_u.fcp_status.scsi_status = FCOE_B2V_1(src + offset);
1100 * fcp_resid/fcp_sense_len/fcp_response_len
1102 offset = offsetof(fcp_rsp_t, fcp_resid);
1103 fcp_rsp_iu->fcp_resid = FCOE_B2V_4(src + offset);
1104 offset = offsetof(fcp_rsp_t, fcp_sense_len);
1105 fcp_rsp_iu->fcp_sense_len = FCOE_B2V_4(src + offset);
1106 offset = offsetof(fcp_rsp_t, fcp_response_len);
1107 fcp_rsp_iu->fcp_response_len = FCOE_B2V_4(src + offset);
1109 * sense or response
1111 offset += 4;
1112 if (fcp_rsp_iu->fcp_sense_len) {
1113 if ((offset + fcp_rsp_iu->fcp_sense_len) > size) {
1114 FCOEI_LOG(__FUNCTION__, "buffer too small - sens");
1115 return;
1117 bcopy(src + offset, dest + offset, fcp_rsp_iu->fcp_sense_len);
1118 offset += fcp_rsp_iu->fcp_sense_len;
1121 if (fcp_rsp_iu->fcp_response_len) {
1122 if ((offset + fcp_rsp_iu->fcp_response_len) > size) {
1123 FCOEI_LOG(__FUNCTION__, "buffer too small - resp");
1124 return;
1126 bcopy(src + offset, dest + offset,
1127 fcp_rsp_iu->fcp_response_len);
1131 void
1132 fcoei_init_ect_vectors(fcoe_client_t *ect)
1134 ect->ect_rx_frame = fcoei_rx_frame;
1135 ect->ect_port_event = fcoei_port_event;
1136 ect->ect_release_sol_frame = fcoei_release_sol_frame;
1140 * fcoei_process_unsol_frame
1141 * Unsolicited frame is received
1143 * Input:
1144 * frame = unsolicited frame that is received
1146 * Returns:
1147 * N/A
1149 * Comments:
1150 * watchdog will call this to process unsolicited frames that we
1151 * just received fcoei_process_xx is used to handle different
1152 * unsolicited frames
1154 void
1155 fcoei_process_unsol_frame(fcoe_frame_t *frm)
1157 fcoei_exchange_t *xch;
1158 uint16_t sol_oxid;
1160 switch (FRM_R_CTL(frm)) {
1161 case R_CTL_SOLICITED_DATA:
1163 * READ data phase frame
1164 * Find the associated exchange
1166 sol_oxid = FRM_OXID(frm);
1167 if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
1168 FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
1169 PRT_FRM_HDR(__FUNCTION__, frm);
1170 FCOEI_LOG(__FUNCTION__, "associated xch not found: "
1171 "oxid/%x %lu - %lu", sol_oxid,
1172 CURRENT_CLOCK, frm->frm_clock);
1173 break;
1177 * Copy data into fpkt data buffer, and update the counter
1179 bcopy(frm->frm_payload, (uint8_t *)xch->xch_fpkt->pkt_data +
1180 FRM_PARAM(frm), frm->frm_payload_size);
1181 xch->xch_resid -= frm->frm_payload_size;
1182 xch->xch_rxid = FRM_RXID(frm);
1183 break;
1185 case R_CTL_XFER_RDY:
1186 fcoei_process_unsol_xfer_rdy(frm);
1187 break;
1189 case R_CTL_STATUS:
1190 fcoei_process_sol_fcp_resp(frm);
1191 break;
1193 case R_CTL_ELS_REQ:
1194 fcoei_process_unsol_els_req(frm);
1195 break;
1197 case R_CTL_LS_ABTS:
1198 fcoei_process_unsol_abts_req(frm);
1199 break;
1201 case R_CTL_ELS_RSP:
1202 fcoei_process_sol_els_rsp(frm);
1203 break;
1205 case R_CTL_SOLICITED_CONTROL:
1206 fcoei_process_sol_ct_rsp(frm);
1207 break;
1209 case R_CTL_LS_BA_ACC:
1210 fcoei_process_sol_abts_acc(frm);
1211 break;
1213 case R_CTL_LS_BA_RJT:
1214 fcoei_process_sol_abts_rjt(frm);
1215 break;
1217 default:
1219 * Unsupported frame
1221 PRT_FRM_HDR("Unsupported unsol frame: ", frm);
1225 * Release the frame and netb
1227 frm->frm_eport->eport_free_netb(frm->frm_netb);
1228 frm->frm_eport->eport_release_frame(frm);
1232 * fcoei_handle_sol_frame_done
1233 * solicited frame is just sent out
1235 * Input:
1236 * frame = solicited frame that has been sent out
1238 * Returns:
1239 * N/A
1241 * Comments:
1242 * watchdog will call this to handle solicited frames that FCOEI
1243 * has sent out Non-request frame post handling
1245 void
1246 fcoei_handle_sol_frame_done(fcoe_frame_t *frm)
1249 * the corresponding xch could be NULL at this time
1251 fcoei_exchange_t *xch = FRM2IFM(frm)->ifm_xch;
1253 switch (FRM2IFM(frm)->ifm_rctl) {
1254 case R_CTL_ELS_RSP:
1256 * Complete it with frm as NULL
1258 fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
1259 break;
1261 case R_CTL_LS_BA_ACC:
1262 FCOEI_LOG(__FUNCTION__, "BA_ACC out: xch-%p, frm-%p",
1263 xch, frm);
1264 PRT_FRM_HDR("LS_BA_ACC", frm);
1265 break;
1267 case R_CTL_LS_BA_RJT:
1268 FCOEI_LOG(__FUNCTION__, "BA_RJT out: xch-%p, frm-%p",
1269 xch, frm);
1270 PRT_FRM_HDR("LS_BA_RJT", frm);
1271 break;
1273 default:
1275 * Unsupported frame
1277 PRT_FRM_HDR("Unsupported sol frame: ", frm);
1281 * We should release only the frame, and we don't care its netb
1283 FRM2SS(frm)->ss_eport->eport_release_frame(frm);
1287 * fcoei_port_event
1288 * link/port state changed
1290 * Input:
1291 * eport = to indicate which port has changed
1292 * event = what change
1294 * Returns:
1295 * N/A
1297 * Comments:
1298 * refer fctl.h for ss_link_state value
1300 void
1301 fcoei_port_event(fcoe_port_t *eport, uint32_t event)
1303 fcoei_event_t *ae;
1305 if (!(EPORT2SS(eport)->ss_flags & SS_FLAG_LV_BOUND)) {
1306 FCOEI_LOG(__FUNCTION__, "not bound now");
1307 return;
1310 mutex_enter(&EPORT2SS(eport)->ss_watchdog_mutex);
1311 switch (event) {
1312 case FCOE_NOTIFY_EPORT_LINK_DOWN:
1313 EPORT2SS(eport)->ss_link_state = FC_STATE_OFFLINE;
1314 cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link down",
1315 eport->eport_portwwn[0], eport->eport_portwwn[1],
1316 eport->eport_portwwn[2], eport->eport_portwwn[3],
1317 eport->eport_portwwn[4], eport->eport_portwwn[5],
1318 eport->eport_portwwn[6], eport->eport_portwwn[7]);
1319 break;
1321 case FCOE_NOTIFY_EPORT_LINK_UP:
1322 if (eport->eport_mtu >= 2200) {
1323 EPORT2SS(eport)->ss_fcp_data_payload_size =
1324 FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
1325 } else {
1326 FCOEI_LOG(__FUNCTION__, "fcoei: MTU is not big enough. "
1327 "we will use 1K frames in FCP data phase.");
1328 EPORT2SS(eport)->ss_fcp_data_payload_size =
1329 FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
1332 cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link up",
1333 eport->eport_portwwn[0], eport->eport_portwwn[1],
1334 eport->eport_portwwn[2], eport->eport_portwwn[3],
1335 eport->eport_portwwn[4], eport->eport_portwwn[5],
1336 eport->eport_portwwn[6], eport->eport_portwwn[7]);
1337 EPORT2SS(eport)->ss_link_state = FC_STATE_ONLINE;
1338 break;
1340 default:
1341 FCOEI_LOG(__FUNCTION__, "unsupported event");
1342 mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
1344 return;
1347 EPORT2SS(eport)->ss_port_event_counter++;
1348 ae = (fcoei_event_t *)kmem_zalloc(sizeof (fcoei_event_t), KM_SLEEP);
1349 ae->ae_type = AE_EVENT_PORT;
1350 ae->ae_obj = EPORT2SS(eport);
1351 ae->ae_specific = EPORT2SS(eport)->ss_link_state;
1352 list_insert_tail(&EPORT2SS(eport)->ss_event_list, ae);
1353 mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
1357 * fcoei_process_event_port
1358 * link/port state changed
1360 * Input:
1361 * ae = link fcoei_event
1363 * Returns:
1364 * N/A
1366 * Comments:
1367 * asynchronous events from FCOE
1369 void
1370 fcoei_process_event_port(fcoei_event_t *ae)
1372 fcoei_soft_state_t *ss = (fcoei_soft_state_t *)ae->ae_obj;
1374 if (ss->ss_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
1375 ae->ae_specific |= FC_STATE_1GBIT_SPEED;
1376 } else if (ss->ss_eport->eport_link_speed ==
1377 FCOE_PORT_SPEED_10G) {
1378 ae->ae_specific |= FC_STATE_10GBIT_SPEED;
1381 if (ss->ss_flags & SS_FLAG_LV_BOUND) {
1382 ss->ss_bind_info.port_statec_cb(ss->ss_port,
1383 (uint32_t)ae->ae_specific);
1384 } else {
1385 FCOEI_LOG(__FUNCTION__, "ss %p not bound now", ss);
1388 atomic_dec_32(&ss->ss_port_event_counter);
1389 kmem_free(ae, sizeof (fcoei_event_t));