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 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This file defines interfaces between fcoe and fct driver.
31 * Driver kernel header files
37 #include <sys/sunddi.h>
38 #include <sys/modctl.h>
41 #include <sys/byteorder.h>
42 #include <sys/atomic.h>
43 #include <sys/modhash.h>
44 #include <sys/scsi/scsi.h>
45 #include <sys/ethernet.h>
48 * COMSTAR header files
50 #include <sys/stmf_defines.h>
51 #include <sys/fct_defines.h>
53 #include <sys/portif.h>
59 #include <sys/fcoe/fcoe_common.h>
62 * Driver's own header files
66 #include "fcoet_eth.h"
69 * function forward declaration
71 static fct_status_t
fcoet_fill_plogi_req(fct_local_port_t
*port
,
72 fct_remote_port_t
*rp
, fct_cmd_t
*login
);
73 static fct_status_t
fcoet_fill_plogi_resp(fct_local_port_t
*port
,
74 fct_remote_port_t
*rp
, fct_cmd_t
*login
);
75 static fct_status_t
fcoet_send_sol_els(fct_cmd_t
*cmd
);
76 static fct_status_t
fcoet_send_sol_ct(fct_cmd_t
*cmd
);
77 static fct_status_t
fcoet_send_good_status(fct_cmd_t
*cmd
);
78 static fct_status_t
fcoet_send_els_response(fct_cmd_t
*cmd
);
79 static fct_status_t
fcoet_send_abts_response(fct_cmd_t
*cmd
, uint32_t flags
);
80 static fct_status_t
fcoet_logo_fabric(fcoet_soft_state_t
*ss
);
83 * Return the lower link information
86 fcoet_get_link_info(fct_local_port_t
*port
, fct_link_info_t
*li
)
88 bcopy(&PORT2SS(port
)->ss_link_info
, li
, sizeof (fct_link_info_t
));
93 * FCT will call this, when it wants to send PLOGI or has received PLOGI.
96 fcoet_register_remote_port(fct_local_port_t
*port
, fct_remote_port_t
*rp
,
121 * For not well-known address, we let FCT to select one.
123 handle
= FCT_HANDLE_NONE
;
127 rp
->rp_handle
= handle
;
128 if (login
->cmd_type
== FCT_CMD_SOL_ELS
) {
129 ret
= fcoet_fill_plogi_req(port
, rp
, login
);
131 ret
= fcoet_fill_plogi_resp(port
, rp
, login
);
138 * FCT will call this to say "FCoET can release resources with this RP now."
142 fcoet_deregister_remote_port(fct_local_port_t
*port
, fct_remote_port_t
*rp
)
144 fcoet_soft_state_t
*this_ss
= PORT2SS(port
);
146 this_ss
->ss_rport_dereg_state
= 0;
147 this_ss
->ss_rportid_in_dereg
= 0;
148 return (FCT_SUCCESS
);
152 fcoet_send_cmd(fct_cmd_t
*cmd
)
154 if (cmd
->cmd_type
== FCT_CMD_SOL_ELS
) {
155 return (fcoet_send_sol_els(cmd
));
156 } else if (cmd
->cmd_type
== FCT_CMD_SOL_CT
) {
157 return (fcoet_send_sol_ct(cmd
));
160 return (FCT_FAILURE
);
164 * SCSI response phase
168 fcoet_send_cmd_response(fct_cmd_t
*cmd
, uint32_t ioflags
)
170 char info
[FCT_INFO_LEN
];
172 if (cmd
->cmd_type
== FCT_CMD_FCP_XCHG
) {
173 if (ioflags
& FCT_IOF_FORCE_FCA_DONE
) {
174 goto send_cmd_rsp_error
;
176 return (fcoet_send_status(cmd
));
180 if (cmd
->cmd_type
== FCT_CMD_RCVD_ELS
) {
181 if (ioflags
& FCT_IOF_FORCE_FCA_DONE
) {
182 goto send_cmd_rsp_error
;
184 return (fcoet_send_els_response(cmd
));
188 if (ioflags
& FCT_IOF_FORCE_FCA_DONE
) {
192 if (cmd
->cmd_type
== FCT_CMD_RCVD_ABTS
) {
193 return (fcoet_send_abts_response(cmd
, 0));
196 return (FCT_FAILURE
);
200 (void) snprintf(info
, sizeof (info
), "fcoet_send_cmd_response: can not "
201 "handle FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd
,
203 (void) fct_port_shutdown(CMD2SS(cmd
)->ss_port
,
204 STMF_RFLAG_FATAL_ERROR
| STMF_RFLAG_RESET
, info
);
205 return (FCT_FAILURE
);
209 * It's for read/write (xfer_rdy)
213 fcoet_xfer_scsi_data(fct_cmd_t
*cmd
, stmf_data_buf_t
*dbuf
, uint32_t ioflags
)
221 fcoet_exchange_t
*xch
= CMD2XCH(cmd
);
223 ASSERT(!xch
->xch_dbufs
[dbuf
->db_relative_offset
/FCOET_MAX_DBUF_LEN
]);
224 xch
->xch_dbufs
[dbuf
->db_relative_offset
/FCOET_MAX_DBUF_LEN
] = dbuf
;
226 left_size
= (int)dbuf
->db_data_size
;
227 if (dbuf
->db_relative_offset
== 0)
228 xch
->xch_left_data_size
=
229 XCH2TASK(xch
)->task_expected_xfer_length
;
231 if (dbuf
->db_flags
& DB_DIRECTION_FROM_RPORT
) {
233 * If it's write type command, we need send xfer_rdy now
234 * We may need to consider bidirectional command later
236 dbuf
->db_sglist_length
= 0;
237 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(
238 CMD2SS(cmd
)->ss_eport
, sizeof (fcoe_fcp_xfer_rdy_t
) +
242 return (FCT_FAILURE
);
244 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
245 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
248 FFM_R_CTL(0x05, frm
);
249 FRM2TFM(frm
)->tfm_rctl
= 0x05;
251 FFM_F_CTL(0x890000, frm
);
252 FFM_OXID(cmd
->cmd_oxid
, frm
);
253 FFM_RXID(cmd
->cmd_rxid
, frm
);
254 FFM_S_ID(cmd
->cmd_lportid
, frm
);
255 FFM_D_ID(cmd
->cmd_rportid
, frm
);
256 FCOE_V2B_4(dbuf
->db_relative_offset
, frm
->frm_payload
);
257 FCOE_V2B_4(dbuf
->db_data_size
, frm
->frm_payload
+ 4);
258 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
260 return (FCT_SUCCESS
);
264 * It's time to transfer READ data to remote side
266 frm_num
= (dbuf
->db_data_size
+ CMD2SS(cmd
)->ss_fcp_data_payload_size
-
267 1) / CMD2SS(cmd
)->ss_fcp_data_payload_size
;
268 offset
= dbuf
->db_relative_offset
;
269 for (idx
= 0; idx
< frm_num
; idx
++) {
270 if (idx
== (frm_num
-1)) {
271 data_size
= P2ROUNDUP(left_size
, 4);
273 data_size
= CMD2SS(cmd
)->ss_fcp_data_payload_size
;
276 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(
277 CMD2SS(cmd
)->ss_eport
, data_size
+ FCFH_SIZE
,
278 FCOET_GET_NETB(dbuf
, idx
));
281 return (FCT_FAILURE
);
283 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
285 * lock the xchg to avoid being released (by abort)
286 * after sent out and before release
288 FCOET_BUSY_XCHG(CMD2XCH(cmd
));
291 FFM_R_CTL(0x01, frm
);
292 FRM2TFM(frm
)->tfm_rctl
= 0x01;
293 FRM2TFM(frm
)->tfm_buf_idx
=
294 dbuf
->db_relative_offset
/FCOET_MAX_DBUF_LEN
;
296 if (idx
!= frm_num
- 1) {
297 FFM_F_CTL(0x800008, frm
);
299 FFM_F_CTL(0x880008 | (data_size
- left_size
), frm
);
302 FFM_OXID(cmd
->cmd_oxid
, frm
);
303 FFM_RXID(cmd
->cmd_rxid
, frm
);
304 FFM_S_ID(cmd
->cmd_lportid
, frm
);
305 FFM_D_ID(cmd
->cmd_rportid
, frm
);
306 FFM_SEQ_CNT(xch
->xch_sequence_no
, frm
);
307 atomic_inc_8(&xch
->xch_sequence_no
);
308 FFM_PARAM(offset
, frm
);
310 left_size
-= data_size
;
313 * Disassociate netbs which will be freed by NIC driver
315 FCOET_SET_NETB(dbuf
, idx
, NULL
);
317 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
320 return (FCT_SUCCESS
);
324 fcoet_abort_cmd(struct fct_local_port
*port
, fct_cmd_t
*cmd
, uint32_t flags
)
326 fcoet_soft_state_t
*this_ss
= PORT2SS(port
);
327 fct_status_t fct_ret
= FCT_SUCCESS
;
329 FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p",
330 cmd
, cmd
->cmd_fca_private
, cmd
->cmd_specific
);
331 switch (cmd
->cmd_type
) {
332 case FCT_CMD_RCVD_ABTS
:
334 * Sometimes unsolicited ABTS request will be received twice
335 * and the first ABTS is not done yet, so the second ABTS
336 * will be passed down here, in this case we will do
337 * nothing and abts response is not needed to be sent
338 * fct_ret = fcoet_send_abts_response(cmd, 1);
341 case FCT_CMD_FCP_XCHG
:
342 case FCT_CMD_RCVD_ELS
:
343 if (CMD2XCH(cmd
)->xch_flags
& XCH_FLAG_FCT_CALLED_ABORT
) {
347 CMD2XCH(cmd
)->xch_flags
|= XCH_FLAG_FCT_CALLED_ABORT
;
348 (void) fcoet_clear_unsol_exchange(CMD2XCH(cmd
));
349 if (!(flags
& FCT_IOF_FORCE_FCA_DONE
)) {
350 mutex_enter(&this_ss
->ss_watch_mutex
);
351 CMD2XCH(cmd
)->xch_start_time
= ddi_get_lbolt();
352 list_insert_tail(&this_ss
->ss_abort_xchg_list
,
354 cv_signal(&this_ss
->ss_watch_cv
);
355 mutex_exit(&this_ss
->ss_watch_mutex
);
359 case FCT_CMD_SOL_ELS
:
361 if (CMD2XCH(cmd
)->xch_flags
& XCH_FLAG_FCT_CALLED_ABORT
) {
365 CMD2XCH(cmd
)->xch_flags
|= XCH_FLAG_FCT_CALLED_ABORT
;
366 fcoet_clear_sol_exchange(CMD2XCH(cmd
));
368 if (!(flags
& FCT_IOF_FORCE_FCA_DONE
)) {
369 mutex_enter(&this_ss
->ss_watch_mutex
);
370 CMD2XCH(cmd
)->xch_start_time
= ddi_get_lbolt();
371 cv_signal(&this_ss
->ss_watch_cv
);
372 list_insert_tail(&this_ss
->ss_abort_xchg_list
,
374 mutex_exit(&this_ss
->ss_watch_mutex
);
384 if ((flags
& FCT_IOF_FORCE_FCA_DONE
) &&
385 (cmd
->cmd_type
!= FCT_CMD_FCP_XCHG
)) {
394 fcoet_do_flogi(fct_local_port_t
*port
, fct_flogi_xchg_t
*fx
)
396 cmn_err(CE_WARN
, "FLOGI requested (not supported)");
397 return (FCT_FAILURE
);
401 fcoet_send_sol_flogi(fcoet_soft_state_t
*ss
)
403 fcoet_exchange_t
*xch
;
409 * FCT will initialize fct_cmd_t
410 * Initialize fcoet_exchange
412 cmd
= (fct_cmd_t
*)fct_alloc(FCT_STRUCT_CMD_SOL_ELS
,
413 sizeof (fcoet_exchange_t
), 0);
417 xch
->xch_oxid
= atomic_add_16_nv(&ss
->ss_next_sol_oxid
, 1);
418 if (xch
->xch_oxid
== 0xFFFF) {
420 atomic_add_16_nv(&ss
->ss_next_sol_oxid
, 1);
422 xch
->xch_rxid
= 0xFFFF;
426 xch
->xch_current_seq
= NULL
;
427 xch
->xch_start_time
= ddi_get_lbolt();
430 * Keep it to compare with response
432 ss
->ss_sol_flogi
= xch
;
433 els
->els_resp_alloc_size
= 116;
434 els
->els_resp_size
= 116;
435 els
->els_resp_payload
= (uint8_t *)
436 kmem_zalloc(els
->els_resp_size
, KM_SLEEP
);
437 (void) mod_hash_insert(xch
->xch_ss
->ss_sol_oxid_hash
,
438 (mod_hash_key_t
)(uintptr_t)xch
->xch_oxid
, (mod_hash_val_t
)xch
);
439 xch
->xch_flags
|= XCH_FLAG_IN_HASH_TABLE
;
440 atomic_or_32(&ss
->ss_flags
, SS_FLAG_DELAY_PLOGI
);
443 * FCoE will initialize fcoe_frame_t
445 frm
= ss
->ss_eport
->eport_alloc_frame(ss
->ss_eport
,
446 FLOGI_REQ_PAYLOAD_SIZE
+ FCFH_SIZE
, NULL
);
451 fcoet_init_tfm(frm
, xch
);
452 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
455 FFM_R_CTL(0x22, frm
);
456 FRM2TFM(frm
)->tfm_rctl
= 0x22;
458 FFM_F_CTL(0x290000, frm
);
459 FFM_OXID(xch
->xch_oxid
, frm
);
460 FFM_RXID(xch
->xch_rxid
, frm
);
461 FFM_D_ID(0xfffffe, frm
);
462 frm
->frm_payload
[0] = ELS_OP_FLOGI
;
463 /* Common Service Parameters */
464 frm
->frm_payload
[4] = 0x20;
465 frm
->frm_payload
[5] = 0x08;
466 frm
->frm_payload
[6] = 0x0;
467 frm
->frm_payload
[7] = 0x03;
469 frm
->frm_payload
[8] = 0x88;
470 frm
->frm_payload
[9] = 0x00;
471 frm
->frm_payload
[10] = 0x08;
472 frm
->frm_payload
[11] = 0x0;
473 frm
->frm_payload
[12] = 0x0;
474 frm
->frm_payload
[13] = 0xff;
475 frm
->frm_payload
[14] = 0x0;
476 frm
->frm_payload
[15] = 0x03;
477 frm
->frm_payload
[16] = 0x0;
478 frm
->frm_payload
[17] = 0x0;
479 frm
->frm_payload
[18] = 0x07;
480 frm
->frm_payload
[19] = 0xd0;
482 frm
->frm_payload
[20] = 0x0;
483 bcopy(ss
->ss_eport
->eport_portwwn
, frm
->frm_payload
+20, 8);
484 bcopy(ss
->ss_eport
->eport_nodewwn
, frm
->frm_payload
+28, 8);
485 /* Class 3 Service Parameters */
486 frm
->frm_payload
[68] = 0x88;
487 frm
->frm_payload
[74] = 0x08;
488 frm
->frm_payload
[77] = 0xff;
490 ss
->ss_eport
->eport_tx_frame(frm
);
491 xch
->xch_flags
|= XCH_FLAG_NONFCP_REQ_SENT
;
495 * This is for solicited FLOGI only
498 fcoet_send_sol_abts(fcoet_exchange_t
*xch
)
501 fcoet_soft_state_t
*ss
= xch
->xch_ss
;
504 * FCoE will initialize fcoe_frame_t
505 * ABTS has no payload
507 frm
= ss
->ss_eport
->eport_alloc_frame(ss
->ss_eport
,
513 fcoet_init_tfm(frm
, xch
);
514 frm
->frm_payload
= NULL
;
517 FFM_R_CTL(0x81, frm
);
518 FRM2TFM(frm
)->tfm_rctl
= 0x81;
519 FFM_F_CTL(0x090000, frm
);
520 FFM_OXID(xch
->xch_oxid
, frm
);
521 FFM_RXID(xch
->xch_rxid
, frm
);
522 FFM_D_ID(0xfffffe, frm
);
523 FFM_SEQ_CNT(xch
->xch_sequence_no
, frm
);
524 xch
->xch_start_time
= ddi_get_lbolt();
526 ss
->ss_eport
->eport_tx_frame(frm
);
530 fcoet_ctl(struct fct_local_port
*port
, int cmd
, void *arg
)
532 stmf_change_status_t st
;
533 stmf_state_change_info_t
*ssci
= (stmf_state_change_info_t
*)arg
;
534 fcoet_soft_state_t
*this_ss
= PORT2SS(port
);
536 st
.st_completion_status
= FCT_SUCCESS
;
537 st
.st_additional_info
= NULL
;
540 case FCT_CMD_PORT_ONLINE
:
541 if (this_ss
->ss_state
== FCT_STATE_ONLINE
)
542 st
.st_completion_status
= STMF_ALREADY
;
543 else if (this_ss
->ss_state
!= FCT_STATE_OFFLINE
)
544 st
.st_completion_status
= FCT_FAILURE
;
545 if (st
.st_completion_status
== FCT_SUCCESS
) {
546 this_ss
->ss_state
= FCT_STATE_ONLINING
;
547 this_ss
->ss_state_not_acked
= 1;
548 st
.st_completion_status
= fcoet_enable_port(this_ss
);
549 if (st
.st_completion_status
!= STMF_SUCCESS
) {
550 this_ss
->ss_state
= FCT_STATE_OFFLINE
;
551 this_ss
->ss_state_not_acked
= 0;
553 this_ss
->ss_state
= FCT_STATE_ONLINE
;
556 fct_ctl(port
->port_lport
, FCT_CMD_PORT_ONLINE_COMPLETE
, &st
);
557 this_ss
->ss_change_state_flags
= 0;
560 case FCT_CMD_PORT_OFFLINE
:
561 if (this_ss
->ss_state
== FCT_STATE_OFFLINE
) {
562 st
.st_completion_status
= STMF_ALREADY
;
563 } else if (this_ss
->ss_state
!= FCT_STATE_ONLINE
) {
564 st
.st_completion_status
= FCT_FAILURE
;
566 if (st
.st_completion_status
== FCT_SUCCESS
) {
567 this_ss
->ss_state
= FCT_STATE_OFFLINING
;
568 this_ss
->ss_state_not_acked
= 1;
569 this_ss
->ss_change_state_flags
= ssci
->st_rflags
;
570 st
.st_completion_status
= fcoet_disable_port(this_ss
);
571 if (st
.st_completion_status
!= STMF_SUCCESS
) {
572 this_ss
->ss_state
= FCT_STATE_ONLINE
;
573 this_ss
->ss_state_not_acked
= 0;
575 this_ss
->ss_state
= FCT_STATE_OFFLINE
;
579 * Notify the watchdog to do clear work
581 mutex_enter(&this_ss
->ss_watch_mutex
);
582 cv_signal(&this_ss
->ss_watch_cv
);
583 mutex_exit(&this_ss
->ss_watch_mutex
);
584 fct_ctl(port
->port_lport
, FCT_CMD_PORT_OFFLINE_COMPLETE
, &st
);
587 case FCT_ACK_PORT_ONLINE_COMPLETE
:
588 this_ss
->ss_state_not_acked
= 0;
591 case FCT_ACK_PORT_OFFLINE_COMPLETE
:
592 this_ss
->ss_state_not_acked
= 0;
593 if (this_ss
->ss_change_state_flags
& STMF_RFLAG_RESET
) {
594 if (fct_port_initialize(port
,
595 this_ss
->ss_change_state_flags
,
596 "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
597 "with RLFLAG_RESET") != FCT_SUCCESS
) {
598 cmn_err(CE_WARN
, "fcoet_ctl: "
599 "fct_port_initialize %s failed",
601 FCOET_LOG("fcoet_ctl: fct_port_initialize "
602 "%s failed", this_ss
->ss_alias
);
607 FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd
);
613 * Filling the hba attributes
617 fcoet_populate_hba_fru_details(struct fct_local_port
*port
,
618 struct fct_port_attrs
*port_attrs
)
620 (void) snprintf(port_attrs
->manufacturer
, FCHBA_MANUFACTURER_LEN
,
621 "Sun Microsystems, Inc.");
622 (void) snprintf(port_attrs
->driver_name
, FCHBA_DRIVER_NAME_LEN
,
624 (void) snprintf(port_attrs
->driver_version
, FCHBA_DRIVER_VERSION_LEN
,
625 "%s", FCOET_VERSION
);
626 (void) strcpy(port_attrs
->serial_number
, "N/A");
627 (void) strcpy(port_attrs
->hardware_version
, "N/A");
628 (void) strcpy(port_attrs
->model
, "FCoE Virtual FC HBA");
629 (void) strcpy(port_attrs
->model_description
, "N/A");
630 (void) strcpy(port_attrs
->firmware_version
, "N/A");
631 (void) strcpy(port_attrs
->option_rom_version
, "N/A");
633 port_attrs
->vendor_specific_id
= 0xFC0E;
634 port_attrs
->max_frame_size
= 2136;
635 port_attrs
->supported_cos
= 0x10000000;
636 /* Specified a fix speed here, need to change it in the future */
637 port_attrs
->supported_speed
= PORT_SPEED_1G
| PORT_SPEED_10G
;
642 fcoet_send_sol_els(fct_cmd_t
*cmd
)
645 fcoet_exchange_t
*xch
= NULL
;
649 xch
->xch_ss
= CMD2SS(cmd
);
651 xch
->xch_current_seq
= NULL
;
652 xch
->xch_left_data_size
= 0;
653 xch
->xch_sequence_no
= 0;
654 xch
->xch_start_time
= ddi_get_lbolt();
655 xch
->xch_rxid
= 0xFFFF;
656 xch
->xch_oxid
= atomic_add_16_nv(&xch
->xch_ss
->ss_next_sol_oxid
, 1);
657 if (xch
->xch_oxid
== 0xFFFF) {
659 atomic_add_16_nv(&xch
->xch_ss
->ss_next_sol_oxid
, 1);
662 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(CMD2SS(cmd
)->ss_eport
,
663 CMD2ELS(cmd
)->els_req_size
+ FCFH_SIZE
, NULL
);
666 return (FCT_FAILURE
);
668 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
669 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
672 (void) mod_hash_insert(FRM2SS(frm
)->ss_sol_oxid_hash
,
673 (mod_hash_key_t
)(uintptr_t)xch
->xch_oxid
, (mod_hash_val_t
)xch
);
674 xch
->xch_flags
|= XCH_FLAG_IN_HASH_TABLE
;
675 bcopy(CMD2ELS(cmd
)->els_req_payload
, frm
->frm_payload
,
676 frm
->frm_payload_size
);
677 FFM_R_CTL(0x22, frm
);
678 FRM2TFM(frm
)->tfm_rctl
= 0x22;
680 FFM_F_CTL(0x290000, frm
);
681 FFM_OXID(xch
->xch_oxid
, frm
);
682 FFM_RXID(xch
->xch_rxid
, frm
);
683 FFM_S_ID(cmd
->cmd_lportid
, frm
);
684 FFM_D_ID(cmd
->cmd_rportid
, frm
);
685 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
687 return (FCT_SUCCESS
);
691 fcoet_send_sol_ct(fct_cmd_t
*cmd
)
694 fcoet_exchange_t
*xch
;
698 xch
->xch_ss
= CMD2SS(cmd
);
700 xch
->xch_current_seq
= NULL
;
701 xch
->xch_left_data_size
= 0;
702 xch
->xch_sequence_no
= 0;
703 xch
->xch_start_time
= ddi_get_lbolt();
704 xch
->xch_rxid
= 0xFFFF;
705 xch
->xch_oxid
= atomic_add_16_nv(&xch
->xch_ss
->ss_next_sol_oxid
, 1);
706 if (xch
->xch_oxid
== 0xFFFF) {
708 atomic_add_16_nv(&xch
->xch_ss
->ss_next_sol_oxid
, 1);
711 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(CMD2SS(cmd
)->ss_eport
,
712 CMD2ELS(cmd
)->els_req_size
+ FCFH_SIZE
, NULL
);
715 return (FCT_FAILURE
);
717 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
718 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
721 (void) mod_hash_insert(FRM2SS(frm
)->ss_sol_oxid_hash
,
722 (mod_hash_key_t
)(uintptr_t)xch
->xch_oxid
, (mod_hash_val_t
)xch
);
723 xch
->xch_flags
|= XCH_FLAG_IN_HASH_TABLE
;
724 bcopy(CMD2ELS(cmd
)->els_req_payload
, frm
->frm_payload
,
725 frm
->frm_payload_size
);
727 FRM2TFM(frm
)->tfm_rctl
= 0x2;
729 FFM_F_CTL(0x290000, frm
);
730 FFM_OXID(xch
->xch_oxid
, frm
);
731 FFM_RXID(xch
->xch_rxid
, frm
);
732 FFM_S_ID(cmd
->cmd_lportid
, frm
);
733 FFM_D_ID(cmd
->cmd_rportid
, frm
);
734 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
736 return (FCT_SUCCESS
);
740 fcoet_send_status(fct_cmd_t
*cmd
)
743 scsi_task_t
*task
= CMD2TASK(cmd
);
748 * Fast channel for good status phase
750 if (task
->task_scsi_status
== STATUS_GOOD
&& !task
->task_resid
) {
751 return (fcoet_send_good_status(cmd
));
754 raw_frame_size
= FCFH_SIZE
+ sizeof (fcoe_fcp_rsp_t
);
755 if (task
->task_scsi_status
== STATUS_CHECK
) {
756 raw_frame_size
+= task
->task_sense_length
;
758 raw_frame_size
= P2ROUNDUP(raw_frame_size
, 4);
760 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(CMD2SS(cmd
)->ss_eport
,
761 raw_frame_size
, NULL
);
764 return (FCT_FAILURE
);
766 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
767 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
769 * lock the xchg to avoid being released (by abort)
770 * after sent out and before release
772 FCOET_BUSY_XCHG(CMD2XCH(cmd
));
776 * If there's sense data, copy it first
778 if ((task
->task_scsi_status
== STATUS_CHECK
) &&
779 task
->task_sense_length
) {
780 bcopy(task
->task_sense_data
, frm
->frm_payload
+
781 sizeof (fcoe_fcp_rsp_t
), task
->task_sense_length
);
787 ffr
= (fcoe_fcp_rsp_t
*)frm
->frm_payload
;
788 FCOE_V2B_4(0, ffr
->ffr_retry_delay_timer
);
789 FCOE_V2B_1(0, ffr
->ffr_flags
);
790 if (task
->task_scsi_status
== STATUS_CHECK
|| task
->task_resid
) {
791 if (task
->task_scsi_status
== STATUS_CHECK
) {
792 ffr
->ffr_flags
[0] |= BIT_1
;
794 if (task
->task_status_ctrl
== TASK_SCTRL_OVER
) {
795 ffr
->ffr_flags
[0] |= BIT_2
;
796 } else if (task
->task_status_ctrl
== TASK_SCTRL_UNDER
) {
797 ffr
->ffr_flags
[0] |= BIT_3
;
800 FCOE_V2B_1(task
->task_scsi_status
, ffr
->ffr_scsi_status
);
801 FCOE_V2B_4(task
->task_resid
, ffr
->ffr_resid
);
802 FCOE_V2B_4(task
->task_sense_length
, ffr
->ffr_sns_len
);
803 FCOE_V2B_4(0, ffr
->ffr_rsp_len
);
806 * Fill fc frame header
808 FFM_R_CTL(0x07, frm
);
809 FRM2TFM(frm
)->tfm_rctl
= 0x07;
811 FFM_F_CTL(0x990000, frm
);
812 FFM_OXID(cmd
->cmd_oxid
, frm
);
813 FFM_RXID(cmd
->cmd_rxid
, frm
);
814 FFM_S_ID(cmd
->cmd_lportid
, frm
);
815 FFM_D_ID(cmd
->cmd_rportid
, frm
);
816 FFM_SEQ_ID(0x01, frm
);
817 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
819 return (FCT_SUCCESS
);
823 fcoet_send_els_response(fct_cmd_t
*cmd
)
827 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(CMD2SS(cmd
)->ss_eport
,
828 CMD2ELS(cmd
)->els_resp_size
+ FCFH_SIZE
, NULL
);
831 return (FCT_FAILURE
);
833 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
834 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
836 * lock the xchg to avoid being released (by abort)
837 * after sent out and before release
839 FCOET_BUSY_XCHG(CMD2XCH(cmd
));
842 bcopy(CMD2ELS(cmd
)->els_resp_payload
, frm
->frm_payload
,
843 frm
->frm_payload_size
);
844 FFM_R_CTL(0x23, frm
);
845 FRM2TFM(frm
)->tfm_rctl
= 0x23;
847 FFM_F_CTL(0x980000, frm
);
848 FFM_OXID(cmd
->cmd_oxid
, frm
);
849 FFM_RXID(cmd
->cmd_rxid
, frm
);
850 FFM_S_ID(cmd
->cmd_lportid
, frm
);
851 FFM_D_ID(cmd
->cmd_rportid
, frm
);
852 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
854 return (FCT_SUCCESS
);
859 fcoet_send_abts_response(fct_cmd_t
*cmd
, uint32_t flags
)
862 fct_rcvd_abts_t
*abts
= (fct_rcvd_abts_t
*)cmd
->cmd_specific
;
865 * The relevant fcoet_exchange has been released
867 cmd
->cmd_fca_private
= NULL
;
868 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(CMD2SS(cmd
)->ss_eport
,
869 12 + FCFH_SIZE
, NULL
);
872 return (FCT_FAILURE
);
874 fcoet_init_tfm(frm
, NULL
);
877 bcopy(abts
->abts_resp_payload
, frm
->frm_payload
,
878 frm
->frm_payload_size
);
879 FFM_R_CTL(abts
->abts_resp_rctl
, frm
);
880 FRM2TFM(frm
)->tfm_rctl
= abts
->abts_resp_rctl
;
882 FFM_F_CTL(0x980000, frm
);
883 FFM_OXID(cmd
->cmd_oxid
, frm
);
884 FFM_RXID(cmd
->cmd_rxid
, frm
);
885 FFM_S_ID(cmd
->cmd_lportid
, frm
);
886 FFM_D_ID(cmd
->cmd_rportid
, frm
);
887 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
889 return (FCT_SUCCESS
);
893 * enable/disable port is simple compared to physical FC HBAs
896 fcoet_enable_port(fcoet_soft_state_t
*ss
)
898 FCOET_EXT_LOG(ss
->ss_alias
, "port is being enabled-%p", ss
);
899 /* Call fcoe function to online the port */
900 if (ss
->ss_eport
->eport_ctl(ss
->ss_eport
, FCOE_CMD_PORT_ONLINE
, 0) ==
902 return (FCT_FAILURE
);
905 if ((ss
->ss_flags
& SS_FLAG_PORT_DISABLED
) == SS_FLAG_PORT_DISABLED
) {
906 atomic_and_32(&ss
->ss_flags
, ~SS_FLAG_PORT_DISABLED
);
909 return (FCT_SUCCESS
);
913 fcoet_disable_port(fcoet_soft_state_t
*ss
)
917 FCOET_EXT_LOG(ss
->ss_alias
, "port is being disabled-%p", ss
);
918 /* Call fcoe function to offline the port */
919 status
= fcoet_logo_fabric(ss
);
920 ss
->ss_eport
->eport_ctl(ss
->ss_eport
, FCOE_CMD_PORT_OFFLINE
, 0);
921 atomic_or_32(&ss
->ss_flags
, SS_FLAG_PORT_DISABLED
);
926 fcoet_logo_fabric(fcoet_soft_state_t
*ss
)
929 uint32_t req_payload_size
= 16;
930 uint16_t xch_oxid
, xch_rxid
= 0xFFFF;
932 frm
= ss
->ss_eport
->eport_alloc_frame(ss
->ss_eport
,
933 req_payload_size
+ FCFH_SIZE
, NULL
);
936 return (FCT_FAILURE
);
938 fcoet_init_tfm(frm
, NULL
);
939 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
941 xch_oxid
= atomic_inc_16_nv(&ss
->ss_next_sol_oxid
);
942 if (xch_oxid
== 0xFFFF) {
943 xch_oxid
= atomic_inc_16_nv(&ss
->ss_next_sol_oxid
);
945 FFM_R_CTL(0x22, frm
);
946 FRM2TFM(frm
)->tfm_rctl
= 0x22;
948 FFM_F_CTL(0x290000, frm
);
949 FFM_OXID(xch_oxid
, frm
);
950 FFM_RXID(xch_rxid
, frm
);
951 FFM_S_ID(ss
->ss_link_info
.portid
, frm
);
952 FFM_D_ID(0xfffffe, frm
);
954 FCOE_V2B_1(0x5, frm
->frm_payload
);
955 FCOE_V2B_3(ss
->ss_link_info
.portid
, frm
->frm_payload
+ 5);
956 bcopy(ss
->ss_eport
->eport_portwwn
, frm
->frm_payload
+ 8, 8);
957 ss
->ss_eport
->eport_tx_frame(frm
);
959 return (FCT_SUCCESS
);
964 * Called by: fcoet_register_remote_port
968 fcoet_fill_plogi_req(fct_local_port_t
*port
, fct_remote_port_t
*rp
,
973 p
= ((fct_els_t
*)login
->cmd_specific
)->els_req_payload
;
980 p
[13] = 0xff; p
[15] = 0x1f;
981 p
[18] = 7; p
[19] = 0xd0;
983 bcopy(port
->port_pwwn
, p
+ 20, 8);
984 bcopy(port
->port_nwwn
, p
+ 28, 8);
991 return (FCT_SUCCESS
);
995 * Called by: fcoet_register_remote_port
999 fcoet_fill_plogi_resp(fct_local_port_t
*port
, fct_remote_port_t
*rp
,
1006 p
= ((fct_els_t
*)login
->cmd_specific
)->els_req_payload
;
1014 bcopy(port
->port_pwwn
, p
+ 20, 8);
1015 bcopy(port
->port_nwwn
, p
+ 28, 8);
1018 return (FCT_SUCCESS
);
1022 fcoet_send_good_status(fct_cmd_t
*cmd
)
1027 raw_frame_size
= FCFH_SIZE
+ sizeof (fcoe_fcp_rsp_t
);
1028 frm
= CMD2SS(cmd
)->ss_eport
->eport_alloc_frame(CMD2SS(cmd
)->ss_eport
,
1029 raw_frame_size
, NULL
);
1032 return (FCT_FAILURE
);
1034 fcoet_init_tfm(frm
, CMD2XCH(cmd
));
1035 bzero(frm
->frm_payload
, frm
->frm_payload_size
);
1037 * lock the xchg to avoid being released (by abort)
1038 * after sent out and before release
1040 FCOET_BUSY_XCHG(CMD2XCH(cmd
));
1044 * Fill fc frame header
1046 FFM_R_CTL(0x07, frm
);
1047 FRM2TFM(frm
)->tfm_rctl
= 0x07;
1048 FFM_TYPE(0x08, frm
);
1049 FFM_F_CTL(0x990000, frm
);
1050 FFM_OXID(cmd
->cmd_oxid
, frm
);
1051 FFM_RXID(cmd
->cmd_rxid
, frm
);
1052 FFM_S_ID(cmd
->cmd_lportid
, frm
);
1053 FFM_D_ID(cmd
->cmd_rportid
, frm
);
1054 FFM_SEQ_ID(0x01, frm
);
1056 CMD2SS(cmd
)->ss_eport
->eport_tx_frame(frm
);
1058 return (FCT_SUCCESS
);