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]
23 * The following notice accompanied the original version of this file:
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
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
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.
69 #include <sys/sunddi.h>
70 #include <sys/modctl.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>
93 #include <sys/fcoe/fcoe_common.h>
96 * Driver's own header files
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
,
118 * Unsolicited frame is received
121 * frame = unsolicited frame that is received
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
);
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
158 * frame = solicited frame that has been sent out
164 * After FCOE sends solicited frames out, it will call this to notify
165 * FCOEI of the completion.
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
:
178 case R_CTL_UNSOL_CONTROL
:
180 FRM2SS(frm
)->ss_eport
->eport_release_frame(frm
);
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
);
199 * fcoei_process_unsol_xfer_rdy
200 * XFER_RDY is received
203 * frm = XFER_RDY frame
212 fcoei_process_unsol_xfer_rdy(fcoe_frame_t
*frm
)
215 fcoei_exchange_t
*xch
;
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) {
231 * rcv_buf_size is the total size of data that should be transferred
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
);
254 FCOEI_LOG(__FUNCTION__
, "can't alloc frame");
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
);
278 xch
->xch_ss
->ss_eport
->eport_tx_frame(nfrm
);
281 * Update offset and left_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
);
294 fcoei_init_ifm(nfrm
, xch
);
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
;
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
);
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
341 * frm = ELS request frame
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.
352 fcoei_process_unsol_els_req(fcoe_frame_t
*frm
)
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
;
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
,
393 switch (frm
->frm_payload
[0]) {
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);
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
);
413 bcopy(frm
->frm_payload
, ub
->ub_buffer
, frm
->frm_payload_size
);
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
428 * key = oxid of the exchange
430 * arg = the soft state
433 * MH_WALK_TERMINATE = found it, terminate the walk
434 * MH_WALK_CONTINUE = not found, continue the walk
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
) {
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
460 * frm = ABTS request frame
466 * The remote side wants to abort one unsolicited exchange.
469 fcoei_process_unsol_abts_req(fcoe_frame_t
*frm
)
471 fcoei_exchange_t
*xch
= NULL
;
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
);
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
;
498 nfrm
= FRM2SS(frm
)->ss_eport
->eport_alloc_frame(
499 FRM2SS(frm
)->ss_eport
,
500 payload_size
+ FCFH_SIZE
, NULL
);
502 FCOEI_LOG(__FUNCTION__
, "can't alloc frame");
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
);
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
522 nfrm
= FRM2SS(frm
)->ss_eport
->eport_alloc_frame(
523 FRM2SS(frm
)->ss_eport
, payload_size
+ FCFH_SIZE
, NULL
);
525 FCOEI_LOG(__FUNCTION__
, "can't alloc frame");
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
555 * frm = FCP response frame
564 fcoei_process_sol_fcp_resp(fcoe_frame_t
*frm
)
567 uint32_t actual_size
;
568 fcoei_exchange_t
*xch
= NULL
;
569 fc_packet_t
*fpkt
= NULL
;
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
);
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
);
646 xch
->xch_fpkt
->pkt_comp(xch
->xch_fpkt
);
651 * fcoei_process_sol_els_rsp
652 * ELS response is received
655 * frm = ELS response frame
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
;
672 * Look for the related exchange
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
);
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
==
711 fcoei_complete_xch(xch
, NULL
, FC_PKT_FABRIC_RJT
,
712 FC_REASON_INVALID_PARAM
);
714 fcoei_complete_xch(xch
, NULL
, FC_PKT_SUCCESS
, 0);
719 * fcoei_process_sol_ct_rsp
720 * CT response is received
723 * frm = CT response frame
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
;
740 * Look for the related exchange
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
);
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
783 * frm = ABTS accept frame
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.
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
807 * frm = ABTS reject frame
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.
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
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
838 * fpkt->pkt_resp must be mapped to one data structure, and it's
839 * different from the content in the raw frame
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
;
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
);
860 switch (((ls_code_t
*)(void *)xch
->xch_fpkt
->pkt_cmd
)->ls_code
) {
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);
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
);
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
+
901 els_logi
->common_service
.btob_credit
= FCOE_B2V_2(src
+
904 els_logi
->common_service
.cmn_features
= FCOE_B2V_2(src
+
907 els_logi
->common_service
.rx_bufsize
= FCOE_B2V_2(src
+
910 els_logi
->common_service
.conc_sequences
= FCOE_B2V_2(src
+
913 els_logi
->common_service
.relative_offset
= FCOE_B2V_2(src
+
916 els_logi
->common_service
.e_d_tov
= FCOE_B2V_4(src
+
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);
930 offset
= offsetof(la_els_logi_t
, class_3
);
931 els_logi
->class_3
.class_opt
= FCOE_B2V_2(src
+ offset
);
933 els_logi
->class_3
.initiator_ctl
= FCOE_B2V_2(src
+ offset
);
935 els_logi
->class_3
.recipient_ctl
= FCOE_B2V_2(src
+ offset
);
937 els_logi
->class_3
.rcv_size
= FCOE_B2V_2(src
+ offset
);
939 els_logi
->class_3
.conc_sequences
= FCOE_B2V_2(src
+ offset
);
941 els_logi
->class_3
.n_port_e_to_e_credit
= FCOE_B2V_2(src
+
944 els_logi
->class_3
.open_seq_per_xchng
= FCOE_B2V_2(src
+ offset
);
950 * PRLI service parameter response page
952 * fcp_prli_acc doesn't include ls_code, don't use offsetof
955 prli_acc
= (struct fcp_prli_acc
*)(void *)(dest
+ offset
);
956 prli_acc
->type
= FCOE_B2V_1(src
+ offset
);
958 * Type code extension
962 * PRLI response flags
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;
977 prli_acc
->orig_process_associator
= FCOE_B2V_4(src
+ offset
);
979 prli_acc
->resp_process_associator
= FCOE_B2V_4(src
+ offset
);
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;
1001 * could only be LS_ACC, no additional information
1003 els_code
->ls_code
= FCOE_B2V_1(src
);
1008 * LS_ACC/LS_RJT, no additional information
1010 els_code
->ls_code
= FCOE_B2V_1(src
);
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);
1021 els_adisc
->nport_id
.port_id
= FCOE_B2V_3(src
+ offset
);
1024 els_rls
= (la_els_rls_acc_t
*)(void *)dest
;
1025 els_rls
->ls_code
.ls_code
= FCOE_B2V_1(src
);
1027 els_rls
->rls_link_params
.rls_link_fail
=
1028 FCOE_B2V_4(src
+ offset
);
1030 els_rls
->rls_link_params
.rls_sync_loss
=
1031 FCOE_B2V_4(src
+ offset
);
1033 els_rls
->rls_link_params
.rls_sig_loss
=
1034 FCOE_B2V_4(src
+ offset
);
1036 els_rls
->rls_link_params
.rls_prim_seq_err
=
1037 FCOE_B2V_4(src
+ offset
);
1039 els_rls
->rls_link_params
.rls_invalid_word
=
1040 FCOE_B2V_4(src
+ offset
);
1042 els_rls
->rls_link_params
.rls_invalid_crc
=
1043 FCOE_B2V_4(src
+ offset
);
1046 els_rnid
= (la_els_rnid_acc_t
*)(void *)dest
;
1047 els_rnid
->ls_code
.ls_code
= FCOE_B2V_1(src
);
1049 bcopy(src
+ offset
, &els_rnid
->hdr
.data_format
, 1);
1051 bcopy(src
+ offset
, &els_rnid
->hdr
.cmn_len
, 1);
1053 bcopy(src
+ offset
, &els_rnid
->hdr
.specific_len
, 1);
1055 bcopy(src
+ offset
, els_rnid
->data
, FCIO_RNID_MAX_DATA_LEN
);
1058 FCOEI_LOG(__FUNCTION__
, "unsupported R_CTL");
1064 * fcoei_fill_fcp_resp
1065 * Fill fpkt FCP response in host format according to frm payload
1068 * src - frm payload in link format
1069 * dest - fpkt FCP response in host format
1070 * size - Maximum conversion size
1076 * This is called only for SCSI response with non good status
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
;
1087 offset
= offsetof(fcp_rsp_t
, fcp_u
);
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;
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
);
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");
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");
1126 bcopy(src
+ offset
, dest
+ offset
,
1127 fcp_rsp_iu
->fcp_response_len
);
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
1144 * frame = unsolicited frame that is received
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
1155 fcoei_process_unsol_frame(fcoe_frame_t
*frm
)
1157 fcoei_exchange_t
*xch
;
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
);
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
);
1185 case R_CTL_XFER_RDY
:
1186 fcoei_process_unsol_xfer_rdy(frm
);
1190 fcoei_process_sol_fcp_resp(frm
);
1194 fcoei_process_unsol_els_req(frm
);
1198 fcoei_process_unsol_abts_req(frm
);
1202 fcoei_process_sol_els_rsp(frm
);
1205 case R_CTL_SOLICITED_CONTROL
:
1206 fcoei_process_sol_ct_rsp(frm
);
1209 case R_CTL_LS_BA_ACC
:
1210 fcoei_process_sol_abts_acc(frm
);
1213 case R_CTL_LS_BA_RJT
:
1214 fcoei_process_sol_abts_rjt(frm
);
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
1236 * frame = solicited frame that has been sent out
1242 * watchdog will call this to handle solicited frames that FCOEI
1243 * has sent out Non-request frame post handling
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
) {
1256 * Complete it with frm as NULL
1258 fcoei_complete_xch(xch
, NULL
, FC_PKT_SUCCESS
, 0);
1261 case R_CTL_LS_BA_ACC
:
1262 FCOEI_LOG(__FUNCTION__
, "BA_ACC out: xch-%p, frm-%p",
1264 PRT_FRM_HDR("LS_BA_ACC", frm
);
1267 case R_CTL_LS_BA_RJT
:
1268 FCOEI_LOG(__FUNCTION__
, "BA_RJT out: xch-%p, frm-%p",
1270 PRT_FRM_HDR("LS_BA_RJT", frm
);
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
);
1288 * link/port state changed
1291 * eport = to indicate which port has changed
1292 * event = what change
1298 * refer fctl.h for ss_link_state value
1301 fcoei_port_event(fcoe_port_t
*eport
, uint32_t event
)
1305 if (!(EPORT2SS(eport
)->ss_flags
& SS_FLAG_LV_BOUND
)) {
1306 FCOEI_LOG(__FUNCTION__
, "not bound now");
1310 mutex_enter(&EPORT2SS(eport
)->ss_watchdog_mutex
);
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]);
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
;
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
;
1341 FCOEI_LOG(__FUNCTION__
, "unsupported event");
1342 mutex_exit(&EPORT2SS(eport
)->ss_watchdog_mutex
);
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
1361 * ae = link fcoei_event
1367 * asynchronous events from FCOE
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
);
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
));