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.
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
34 #include <sys/byteorder.h>
35 #include <sys/atomic.h>
36 #include <sys/scsi/scsi.h>
37 #include <sys/mac_client.h>
38 #include <sys/modhash.h>
41 * leadville header files
43 #include <sys/fibre-channel/fc.h>
44 #include <sys/fibre-channel/impl/fc_fcaif.h>
49 #include <sys/fcoe/fcoe_common.h>
57 * forward declaration of stack functions
59 static uint32_t fcoei_xch_check(
60 mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
);
61 static int fcoei_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
62 static int fcoei_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
63 static int fcoei_open(dev_t
*devp
, int flag
, int otype
, cred_t
*credp
);
64 static int fcoei_close(dev_t dev
, int flag
, int otype
, cred_t
*credp
);
65 static int fcoei_ioctl(
66 dev_t dev
, int cmd
, intptr_t data
, int mode
, cred_t
*credp
, int *rval
);
67 static int fcoei_attach_init(fcoei_soft_state_t
*ss
);
68 static int fcoei_detach_uninit(fcoei_soft_state_t
*ss
);
69 static void fcoei_watchdog(void *arg
);
70 static void fcoei_process_events(fcoei_soft_state_t
*ss
);
71 static void fcoei_trigger_fp_attach(void *arg
);
72 static void fcoei_abts_exchange(fcoei_exchange_t
*xch
);
73 static void fcoei_clear_watchdog_jobs(fcoei_soft_state_t
*ss
);
76 * Driver identificaton stuff
78 static struct cb_ops fcoei_cb_ops
= {
93 D_MP
| D_NEW
| D_HOTPLUG
,
99 static struct dev_ops fcoei_ops
= {
111 ddi_quiesce_not_needed
114 static struct modldrv modldrv
= {
120 static struct modlinkage modlinkage
= {
127 * Driver's global variables
129 void *fcoei_state
= NULL
;
130 int fcoei_use_ext_log
= 0;
133 * Common loadable module entry points _init, _fini, _info
140 ret
= ddi_soft_state_init(&fcoei_state
, sizeof (fcoei_soft_state_t
), 0);
141 if (ret
!= DDI_SUCCESS
) {
142 FCOEI_LOG(__FUNCTION__
, "soft state init failed: %x", ret
);
146 ret
= mod_install(&modlinkage
);
148 ddi_soft_state_fini(&fcoei_state
);
149 FCOEI_LOG(__FUNCTION__
, "fcoei mod_install failed: %x", ret
);
154 * Let FCTL initialize devo_bus_ops
156 fc_fca_init(&fcoei_ops
);
158 FCOEI_LOG(__FUNCTION__
, "fcoei _init succeeded");
167 ret
= mod_remove(&modlinkage
);
169 FCOEI_EXT_LOG(__FUNCTION__
, "fcoei mod_remove failed: %x", ret
);
173 ddi_soft_state_fini(&fcoei_state
);
174 FCOEI_LOG(__FUNCTION__
, "fcoei _fini succeeded");
179 _info(struct modinfo
*modinfop
)
181 return (mod_info(&modlinkage
, modinfop
));
185 * Autoconfiguration entry points: attach, detach, getinfo
189 fcoei_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
194 fcoei_soft_state_t
*ss
;
196 instance
= ddi_get_instance(dip
);
197 FCOEI_LOG(__FUNCTION__
, "instance is %d", instance
);
200 ret
= ddi_soft_state_zalloc(fcoei_state
, instance
);
201 if (ret
!= DDI_SUCCESS
) {
202 FCOEI_LOG(__FUNCTION__
, "ss zalloc failed: %x", ret
);
207 * Get the soft state, and do basic initialization with dip
209 ss
= ddi_get_soft_state(fcoei_state
, instance
);
212 fcoe_ret
= fcoei_attach_init(ss
);
213 if (fcoe_ret
!= FCOE_SUCCESS
) {
214 ddi_soft_state_free(fcoei_state
, instance
);
215 FCOEI_LOG(__FUNCTION__
, "fcoei_attach_init failed: "
217 return (DDI_FAILURE
);
220 ss
->ss_flags
|= SS_FLAG_TRIGGER_FP_ATTACH
;
221 (void) timeout(fcoei_trigger_fp_attach
, ss
, FCOE_SEC2TICK(1));
222 FCOEI_LOG(__FUNCTION__
, "fcoei_attach succeeded: dip-%p, "
224 return (DDI_SUCCESS
);
227 return (DDI_SUCCESS
);
230 FCOEI_LOG(__FUNCTION__
, "unsupported attach cmd-%X", cmd
);
231 return (DDI_FAILURE
);
236 fcoei_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
240 fcoei_soft_state_t
*ss
;
242 instance
= ddi_get_instance(dip
);
243 ss
= ddi_get_soft_state(fcoei_state
, instance
);
245 FCOEI_LOG(__FUNCTION__
, "get ss failed: dip-%p", dip
);
246 return (DDI_FAILURE
);
251 if (ss
->ss_flags
& SS_FLAG_TRIGGER_FP_ATTACH
) {
252 FCOEI_LOG(__FUNCTION__
, "still await fp attach");
253 return (DDI_FAILURE
);
256 if (ss
->ss_flags
& SS_FLAG_LV_BOUND
) {
257 FCOEI_LOG(__FUNCTION__
, "fp is not detached yet");
258 return (DDI_FAILURE
);
261 fcoe_ret
= fcoei_detach_uninit(ss
);
262 if (fcoe_ret
!= FCOE_SUCCESS
) {
263 FCOEI_LOG(__FUNCTION__
, "fcoei_detach_uninit failed:"
264 " dip-%p, fcoe_ret-%d", dip
, fcoe_ret
);
265 return (DDI_FAILURE
);
268 FCOEI_LOG(__FUNCTION__
, "succeeded: dip-%p, cmd-%x", dip
, cmd
);
269 return (DDI_SUCCESS
);
272 return (DDI_SUCCESS
);
275 FCOEI_LOG(__FUNCTION__
, "unspported detach cmd-%X", cmd
);
276 return (DDI_FAILURE
);
281 * Device access entry points: open, close, ioctl
285 fcoei_open(dev_t
*devp
, int flag
, int otype
, cred_t
*credp
)
287 fcoei_soft_state_t
*ss
;
289 if (otype
!= OTYP_CHR
) {
290 FCOEI_LOG(__FUNCTION__
, "flag: %x", flag
);
294 if (drv_priv(credp
)) {
299 * First of all, get related soft state
301 ss
= ddi_get_soft_state(fcoei_state
, (int)getminor(*devp
));
306 mutex_enter(&ss
->ss_ioctl_mutex
);
307 if (ss
->ss_ioctl_flags
& FCOEI_IOCTL_FLAG_OPEN
) {
309 * We don't support concurrent open
311 mutex_exit(&ss
->ss_ioctl_mutex
);
315 ss
->ss_ioctl_flags
|= FCOEI_IOCTL_FLAG_OPEN
;
316 mutex_exit(&ss
->ss_ioctl_mutex
);
322 fcoei_close(dev_t dev
, int flag
, int otype
, cred_t
*credp
)
324 fcoei_soft_state_t
*ss
;
326 if (otype
!= OTYP_CHR
) {
327 FCOEI_LOG(__FUNCTION__
, "flag: %x, %p", flag
, credp
);
332 * First of all, get related soft state
334 ss
= ddi_get_soft_state(fcoei_state
, (int)getminor(dev
));
339 mutex_enter(&ss
->ss_ioctl_mutex
);
340 if (!(ss
->ss_ioctl_flags
& FCOEI_IOCTL_FLAG_OPEN
)) {
342 * If it's not open, we can exit
345 mutex_exit(&ss
->ss_ioctl_mutex
);
349 ss
->ss_ioctl_flags
&= ~FCOEI_IOCTL_FLAG_OPEN
;
350 mutex_exit(&ss
->ss_ioctl_mutex
);
356 fcoei_ioctl(dev_t dev
, int cmd
, intptr_t data
, int mode
,
357 cred_t
*credp
, int *rval
)
359 fcoei_soft_state_t
*ss
;
362 if (drv_priv(credp
) != 0) {
363 FCOEI_LOG(__FUNCTION__
, "data: %p, %x", data
, mode
);
368 * Get related soft state
370 ss
= ddi_get_soft_state(fcoei_state
, (int32_t)getminor(dev
));
381 FCOEI_LOG(__FUNCTION__
, "ioctl-0x%02X", cmd
);
394 * init related stuff of the soft state
397 * ss = the soft state that will be processed
400 * if it succeeded or not
406 fcoei_attach_init(fcoei_soft_state_t
*ss
)
409 fcoe_client_t client_fcoei
;
412 la_els_logi_t
*els
= &ss
->ss_els_logi
;
413 svc_param_t
*class3_param
;
416 * Register fcoei to FCOE as its client
418 client_fcoei
.ect_eport_flags
= EPORT_FLAG_INI_MODE
|
419 EPORT_FLAG_IS_DIRECT_P2P
;
420 client_fcoei
.ect_max_fc_frame_size
= FCOE_MAX_FC_FRAME_SIZE
;
421 client_fcoei
.ect_private_frame_struct_size
= sizeof (fcoei_frame_t
);
422 fcoei_init_ect_vectors(&client_fcoei
);
423 client_fcoei
.ect_client_port_struct
= ss
;
424 client_fcoei
.ect_fcoe_ver
= FCOE_VER_NOW
;
425 FCOEI_LOG(__FUNCTION__
, "version: %x %x", FCOE_VER_NOW
, fcoe_ver_now
);
426 ret
= ddi_prop_get_int(DDI_DEV_T_ANY
, ss
->ss_dip
,
427 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
, "mac_id", -1);
429 FCOEI_LOG(__FUNCTION__
, "get mac_id failed");
430 return (DDI_FAILURE
);
432 client_fcoei
.ect_channelid
= ret
;
436 * It's fcoe's responsiblity to initialize eport's all elements,
437 * so we needn't do eport initialization
439 eport
= fcoe_register_client(&client_fcoei
);
441 goto fail_register_client
;
443 ss
->ss_eport
= eport
;
444 FCOE_SET_DEFAULT_FPORT_ADDR(eport
->eport_efh_dst
);
448 * Now it's time to register fca_tran to FCTL
449 * Remember fc_local_port is transparent to FCA (fcoei)
451 ss
->ss_fca_tran
.fca_version
= FCTL_FCA_MODREV_5
;
452 ss
->ss_fca_tran
.fca_numports
= 1;
453 ss
->ss_fca_tran
.fca_pkt_size
= sizeof (fcoei_exchange_t
);
454 ss
->ss_fca_tran
.fca_cmd_max
= 2048;
457 * scsi_tran_hba_setup could need these stuff
459 ss
->ss_fca_tran
.fca_dma_lim
= NULL
;
460 ss
->ss_fca_tran
.fca_iblock
= NULL
;
461 ss
->ss_fca_tran
.fca_dma_attr
= NULL
;
462 ss
->ss_fca_tran
.fca_acc_attr
= NULL
;
467 fcoei_init_fcatran_vectors(&ss
->ss_fca_tran
);
470 * fc_fca_attach only sets driver's private, it has nothing to with
471 * common port object between fcoei and leadville.
472 * After this attach, fp_attach will be triggered, and it will call
473 * fca_bind_port to let fcoei to know about common port object.
475 if (fc_fca_attach(ss
->ss_dip
, &ss
->ss_fca_tran
) != DDI_SUCCESS
) {
476 goto fail_fca_attach
;
480 * It's time to do ss initialization
482 ret
= ddi_create_minor_node(ss
->ss_dip
, "admin",
483 S_IFCHR
, ddi_get_instance(ss
->ss_dip
), DDI_NT_NEXUS
, 0);
484 if (ret
!= DDI_SUCCESS
) {
485 goto fail_minor_node
;
491 * ss->ss_eport has been initialized
494 ss
->ss_sol_oxid_hash
= mod_hash_create_idhash(
495 "fcoei_sol_oxid_hash", FCOEI_SOL_HASH_SIZE
,
496 mod_hash_null_valdtor
);
497 ss
->ss_unsol_rxid_hash
= mod_hash_create_idhash(
498 "fcoei_unsol_rxid_hash", FCOEI_UNSOL_HASH_SIZE
,
499 mod_hash_null_valdtor
);
500 list_create(&ss
->ss_comp_xch_list
, sizeof (fcoei_exchange_t
),
501 offsetof(fcoei_exchange_t
, xch_comp_node
));
502 ss
->ss_next_sol_oxid
= 0xFFFF;
503 ss
->ss_next_unsol_rxid
= 0xFFFF;
505 mutex_init(&ss
->ss_watchdog_mutex
, 0, MUTEX_DRIVER
, 0);
506 cv_init(&ss
->ss_watchdog_cv
, NULL
, CV_DRIVER
, NULL
);
507 (void) snprintf(taskq_name
, 32, "leadville_fcoei_%d_taskq",
508 ddi_get_instance(ss
->ss_dip
));
510 ss
->ss_taskq
= ddi_taskq_create(ss
->ss_dip
,
511 taskq_name
, 64, TASKQ_DEFAULTPRI
, DDI_SLEEP
);
513 ss
->ss_link_state
= FC_STATE_OFFLINE
;
514 ss
->ss_link_speed
= 0;
515 ss
->ss_port_event_counter
= 0;
517 list_create(&ss
->ss_event_list
, sizeof (fcoei_event_t
),
518 offsetof(fcoei_event_t
, ae_node
));
522 ss
->ss_sol_cnt
= &ss
->ss_sol_cnt1
;
523 ss
->ss_unsol_cnt1
= 0;
524 ss
->ss_unsol_cnt2
= 0;
525 ss
->ss_unsol_cnt
= &ss
->ss_unsol_cnt1
;
526 ss
->ss_ioctl_flags
= 0;
528 mutex_init(&ss
->ss_ioctl_mutex
, 0, MUTEX_DRIVER
, 0);
530 bcopy(eport
->eport_portwwn
, els
->nport_ww_name
.raw_wwn
, 8);
531 bcopy(eport
->eport_nodewwn
, els
->node_ww_name
.raw_wwn
, 8);
532 els
->common_service
.fcph_version
= 0x2008;
533 els
->common_service
.btob_credit
= 3;
534 els
->common_service
.cmn_features
= 0x8800;
535 els
->common_service
.conc_sequences
= 0xff;
536 els
->common_service
.relative_offset
= 3;
537 els
->common_service
.e_d_tov
= 0x07d0;
538 class3_param
= (svc_param_t
*)&els
->class_3
;
539 class3_param
->class_opt
= 0x8800;
540 class3_param
->rcv_size
= els
->common_service
.rx_bufsize
= 2048;
541 class3_param
->conc_sequences
= 0xff;
542 class3_param
->open_seq_per_xchng
= 1;
545 * Fill out RNID Management Information
547 bcopy(ss
->ss_eport
->eport_portwwn
, ss
->ss_rnid
.global_id
, 8);
548 ss
->ss_rnid
.unit_type
= FCOEI_RNID_HBA
;
549 ss
->ss_rnid
.ip_version
= FCOEI_RNID_IPV4
;
554 (void) ddi_taskq_dispatch(ss
->ss_taskq
,
555 fcoei_watchdog
, ss
, DDI_SLEEP
);
556 while (!(ss
->ss_flags
& SS_FLAG_WATCHDOG_RUNNING
)) {
561 * Report the device to the system
563 ddi_report_dev(ss
->ss_dip
);
564 return (DDI_SUCCESS
);
568 FCOEI_LOG(__FUNCTION__
, "fail_minor_node");
569 (void) fc_fca_detach(ss
->ss_dip
);
572 eport
->eport_deregister_client(eport
);
573 FCOEI_LOG(__FUNCTION__
, "fail_fca_attach");
575 fail_register_client
:
576 FCOEI_LOG(__FUNCTION__
, "fail_register_client");
577 return (DDI_FAILURE
);
581 * fcoei_detach_uninit
582 * uninit related stuff of the soft state
585 * ss = the soft state that will be processed
588 * if it succeeded or not
594 fcoei_detach_uninit(fcoei_soft_state_t
*ss
)
597 * Stop watchdog first
599 if (ss
->ss_flags
& SS_FLAG_WATCHDOG_RUNNING
) {
600 ss
->ss_flags
|= SS_FLAG_TERMINATE_WATCHDOG
;
601 cv_broadcast(&ss
->ss_watchdog_cv
);
607 ddi_taskq_wait(ss
->ss_taskq
);
608 ddi_taskq_destroy(ss
->ss_taskq
);
611 * Release all allocated resources
613 mutex_destroy(&ss
->ss_ioctl_mutex
);
614 mutex_destroy(&ss
->ss_watchdog_mutex
);
615 cv_destroy(&ss
->ss_watchdog_cv
);
616 mod_hash_destroy_idhash(ss
->ss_sol_oxid_hash
);
617 mod_hash_destroy_idhash(ss
->ss_unsol_rxid_hash
);
618 list_destroy(&ss
->ss_event_list
);
619 ss
->ss_eport
->eport_deregister_client(ss
->ss_eport
);
620 ddi_remove_minor_node(ss
->ss_dip
, NULL
);
625 ddi_soft_state_free(fcoei_state
, ddi_get_instance(ss
->ss_dip
));
626 return (FCOE_SUCCESS
);
631 * Perform periodic checking and routine tasks
634 * arg = the soft state that will be processed
643 fcoei_watchdog(void *arg
)
645 fcoei_soft_state_t
*ss
;
653 ss
= (fcoei_soft_state_t
*)arg
;
654 FCOEI_LOG(__FUNCTION__
, "ss %p", ss
);
655 FCOEI_LOG(__FUNCTION__
, "sol_hash %p", ss
->ss_sol_oxid_hash
);
656 FCOEI_LOG(__FUNCTION__
, "unsol_hash %p", ss
->ss_unsol_rxid_hash
);
657 ss
->ss_flags
|= SS_FLAG_WATCHDOG_RUNNING
;
658 tmp_delay
= FCOE_SEC2TICK(1) / 2;
659 last_clock
= CURRENT_CLOCK
;
662 * If nobody reqeusts to terminate the watchdog, we will work forever
664 while (!(ss
->ss_flags
& SS_FLAG_TERMINATE_WATCHDOG
)) {
666 * We handle all asynchronous events serially
668 fcoei_process_events(ss
);
671 * To avoid to check timing too freqently, we check
672 * if we need skip timing stuff.
674 start_clock
= CURRENT_CLOCK
;
675 if ((start_clock
- last_clock
) < tmp_delay
) {
678 last_clock
= start_clock
;
682 * It's time to do timeout checking of solicited exchanges
684 if (ss
->ss_sol_cnt
== (&ss
->ss_sol_cnt1
)) {
685 if (ss
->ss_sol_cnt2
== 0) {
686 ss
->ss_sol_cnt
= &ss
->ss_sol_cnt2
;
688 mod_hash_walk(ss
->ss_sol_oxid_hash
,
689 fcoei_xch_check
, ss
);
692 if (ss
->ss_sol_cnt1
== 0) {
693 ss
->ss_sol_cnt
= &ss
->ss_sol_cnt1
;
695 mod_hash_walk(ss
->ss_sol_oxid_hash
,
696 fcoei_xch_check
, ss
);
701 * It's time to do timeout checking of unsolicited exchange
703 if (ss
->ss_unsol_cnt
== (&ss
->ss_unsol_cnt1
)) {
704 if (ss
->ss_unsol_cnt2
== 0) {
705 ss
->ss_unsol_cnt
= &ss
->ss_unsol_cnt2
;
707 mod_hash_walk(ss
->ss_unsol_rxid_hash
,
708 fcoei_xch_check
, ss
);
711 if (ss
->ss_unsol_cnt1
== 0) {
712 ss
->ss_unsol_cnt
= &ss
->ss_unsol_cnt1
;
714 mod_hash_walk(ss
->ss_unsol_rxid_hash
,
715 fcoei_xch_check
, ss
);
720 * Check if there are exchanges which are ready to complete
722 fcoei_handle_comp_xch_list(ss
);
726 * Wait for next cycle
728 mutex_enter(&ss
->ss_watchdog_mutex
);
729 ss
->ss_flags
|= SS_FLAG_WATCHDOG_IDLE
;
730 if (!list_is_empty(&ss
->ss_event_list
)) {
734 (void) cv_timedwait(&ss
->ss_watchdog_cv
,
735 &ss
->ss_watchdog_mutex
, CURRENT_CLOCK
+
738 ss
->ss_flags
&= ~SS_FLAG_WATCHDOG_IDLE
;
739 mutex_exit(&ss
->ss_watchdog_mutex
);
743 * Do clear work before exit
745 fcoei_clear_watchdog_jobs(ss
);
748 * Watchdog has stopped
750 ss
->ss_flags
&= ~SS_FLAG_WATCHDOG_RUNNING
;
754 fcoei_clear_watchdog_jobs(fcoei_soft_state_t
*ss
)
759 mutex_enter(&ss
->ss_watchdog_mutex
);
760 while (!list_is_empty(&ss
->ss_event_list
)) {
761 ae
= (fcoei_event_t
*)list_head(&ss
->ss_event_list
);
762 list_remove(&ss
->ss_event_list
, ae
);
763 switch (ae
->ae_type
) {
764 case AE_EVENT_SOL_FRAME
:
765 frm
= (fcoe_frame_t
*)ae
->ae_obj
;
766 frm
->frm_eport
->eport_release_frame(frm
);
769 case AE_EVENT_UNSOL_FRAME
:
770 frm
= (fcoe_frame_t
*)ae
->ae_obj
;
771 frm
->frm_eport
->eport_free_netb(frm
->frm_netb
);
772 frm
->frm_eport
->eport_release_frame(frm
);
776 atomic_dec_32(&ss
->ss_port_event_counter
);
780 kmem_free(ae
, sizeof (fcoei_event_t
));
783 case AE_EVENT_EXCHANGE
:
791 mod_hash_clear(ss
->ss_unsol_rxid_hash
);
792 mod_hash_clear(ss
->ss_sol_oxid_hash
);
794 while (!list_is_empty(&ss
->ss_comp_xch_list
)) {
795 (void) list_remove_head(&ss
->ss_comp_xch_list
);
797 mutex_exit(&ss
->ss_watchdog_mutex
);
801 * fcoei_process_events
802 * Process the events one by one
805 * ss = the soft state that will be processed
814 fcoei_process_events(fcoei_soft_state_t
*ss
)
816 fcoei_event_t
*ae
= NULL
;
819 * It's the only place to delete node from ss_event_list, so we needn't
820 * hold mutex to check if the list is empty.
822 ASSERT(!MUTEX_HELD(&ss
->ss_watchdog_mutex
));
823 while (list_is_empty(&ss
->ss_event_list
) == B_FALSE
) {
824 mutex_enter(&ss
->ss_watchdog_mutex
);
825 ae
= (fcoei_event_t
*)list_remove_head(&ss
->ss_event_list
);
826 mutex_exit(&ss
->ss_watchdog_mutex
);
828 switch (ae
->ae_type
) {
829 case AE_EVENT_SOL_FRAME
:
830 fcoei_handle_sol_frame_done((fcoe_frame_t
*)ae
->ae_obj
);
833 case AE_EVENT_UNSOL_FRAME
:
834 fcoei_process_unsol_frame((fcoe_frame_t
*)ae
->ae_obj
);
837 case AE_EVENT_EXCHANGE
:
838 fcoei_process_event_exchange(ae
);
842 fcoei_process_event_port(ae
);
846 fcoei_process_event_reset(ae
);
850 FCOEI_LOG(__FUNCTION__
, "unsupported events");
857 * fcoei_handle_tmout_xch_list
858 * Complete every exchange in the timed-out xch list of the soft state
861 * ss = the soft state that need be handled
867 * When mod_hash_walk is in progress, we can't change the hashtable.
868 * This is post-walk handling of exchange timing
871 fcoei_handle_comp_xch_list(fcoei_soft_state_t
*ss
)
873 fcoei_exchange_t
*xch
= NULL
;
875 while ((xch
= list_remove_head(&ss
->ss_comp_xch_list
)) != NULL
) {
876 fcoei_complete_xch(xch
, NULL
, xch
->xch_fpkt
->pkt_state
,
877 xch
->xch_fpkt
->pkt_reason
);
883 * Check if the exchange timed out or link is down
886 * key = rxid of the unsolicited exchange
887 * val = the unsolicited exchange
888 * arg = the soft state
891 * MH_WALK_CONTINUE = continue to walk
894 * We need send ABTS for timed-out for solicited exchange
895 * If it's solicited FLOGI, we need set SS_FLAG_FLOGI_FAILED
896 * If the link is down, we think it has timed out too.
900 fcoei_xch_check(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
902 fcoei_exchange_t
*xch
= (fcoei_exchange_t
*)val
;
904 ASSERT(xch
->xch_ss
== arg
);
905 if ((xch
->xch_end_tick
< CURRENT_CLOCK
) &&
906 (xch
->xch_ss
->ss_link_state
!= FC_STATE_OFFLINE
)) {
907 if (xch
->xch_flags
& XCH_FLAG_IN_SOL_HASH
) {
908 ASSERT(xch
->xch_oxid
== CMHK(key
));
910 * It's solicited exchange
912 fcoei_abts_exchange(xch
);
913 if (LA_ELS_FLOGI
== ((ls_code_t
*)(void *)
914 xch
->xch_fpkt
->pkt_cmd
)->ls_code
) {
916 * It's solicited FLOGI
918 xch
->xch_ss
->ss_flags
|= SS_FLAG_FLOGI_FAILED
;
922 FCOEI_LOG(__FUNCTION__
, "oxid-%x/rxid-%x timed out",
923 xch
->xch_oxid
, xch
->xch_rxid
);
924 xch
->xch_flags
|= XCH_FLAG_TMOUT
;
925 xch
->xch_fpkt
->pkt_state
= FC_PKT_TIMEOUT
;
926 xch
->xch_fpkt
->pkt_reason
= FC_REASON_ABORTED
;
927 list_insert_tail(&xch
->xch_ss
->ss_comp_xch_list
, xch
);
928 } else if (xch
->xch_ss
->ss_link_state
== FC_STATE_OFFLINE
) {
929 FCOEI_LOG(__FUNCTION__
, "oxid-%x/rxid-%x offline complete",
930 xch
->xch_oxid
, xch
->xch_rxid
);
931 xch
->xch_flags
|= XCH_FLAG_TMOUT
;
932 xch
->xch_fpkt
->pkt_state
= FC_PKT_PORT_OFFLINE
;
933 xch
->xch_fpkt
->pkt_reason
= FC_REASON_OFFLINE
;
934 list_insert_tail(&xch
->xch_ss
->ss_comp_xch_list
, xch
);
937 return (MH_WALK_CONTINUE
);
942 * initialize fcoei_frame
945 * frm = the frame that ifm need link to
946 * xch = the exchange that ifm need link to
952 * For solicited frames, it's called after FC frame header initialization
953 * For unsolicited frames, it's called just after the frame enters fcoei
956 fcoei_init_ifm(fcoe_frame_t
*frm
, fcoei_exchange_t
*xch
)
958 FRM2IFM(frm
)->ifm_frm
= frm
;
959 FRM2IFM(frm
)->ifm_xch
= xch
;
960 FRM2IFM(frm
)->ifm_rctl
= FRM_R_CTL(frm
);
964 * fcoei_trigger_fp_attach
965 * Trigger fp_attach for this fcoei port
968 * arg = the soft state that fp will attach
977 fcoei_trigger_fp_attach(void * arg
)
979 fcoei_soft_state_t
*ss
= (fcoei_soft_state_t
*)arg
;
980 dev_info_t
*child
= NULL
;
981 int rval
= NDI_FAILURE
;
983 ndi_devi_alloc_sleep(ss
->ss_dip
, "fp", DEVI_PSEUDO_NODEID
, &child
);
985 FCOEI_LOG(__FUNCTION__
, "can't alloc dev_info");
990 * fp/fctl need this property
992 if (ddi_prop_update_string(DDI_DEV_T_NONE
, child
,
993 "bus-addr", "0,0") != DDI_PROP_SUCCESS
) {
994 FCOEI_LOG(__FUNCTION__
, "update bus-addr failed");
995 (void) ndi_devi_free(child
);
1000 * If it's physical HBA, fp.conf will register the property.
1001 * fcoei is one software HBA, so we need register it manually
1003 if (ddi_prop_update_int(DDI_DEV_T_NONE
, child
,
1004 "port", 0) != DDI_PROP_SUCCESS
) {
1005 FCOEI_LOG(__FUNCTION__
, "update port failed");
1006 (void) ndi_devi_free(child
);
1011 * It will call fp_attach eventually
1013 rval
= ndi_devi_online(child
, NDI_ONLINE_ATTACH
);
1014 ss
->ss_flags
&= ~SS_FLAG_TRIGGER_FP_ATTACH
;
1015 if (rval
!= NDI_SUCCESS
) {
1016 FCOEI_LOG(__FUNCTION__
, "devi_online: %d", rval
);
1018 FCOEI_LOG(__FUNCTION__
, "triggered successfully");
1023 * fcoei_abts_exchange
1024 * Send ABTS to abort solicited exchange
1027 * xch = the exchange that will be aborted
1033 * ABTS frame uses the same oxid as the exchange
1036 fcoei_abts_exchange(fcoei_exchange_t
*xch
)
1038 fc_packet_t
*fpkt
= xch
->xch_fpkt
;
1039 fcoe_frame_t
*frm
= NULL
;
1042 * BLS_ABTS doesn't contain any other payload except FCFH
1044 frm
= xch
->xch_ss
->ss_eport
->eport_alloc_frame(xch
->xch_ss
->ss_eport
,
1047 FCOEI_LOG(__FUNCTION__
, "can't alloc frame: %p", xch
);
1051 FFM_R_CTL(0x81, frm
);
1052 FFM_D_ID(fpkt
->pkt_cmd_fhdr
.d_id
, frm
);
1053 FFM_S_ID(fpkt
->pkt_cmd_fhdr
.s_id
, frm
);
1054 FFM_F_CTL(0x090000, frm
);
1055 FFM_SEQ_ID(0x01, frm
);
1056 FFM_OXID(xch
->xch_oxid
, frm
);
1057 FFM_RXID(xch
->xch_rxid
, frm
);
1058 fcoei_init_ifm(frm
, xch
);
1059 xch
->xch_ss
->ss_eport
->eport_tx_frame(frm
);
1063 * fcoei_complete_xch
1064 * Complete the exchange
1067 * xch = the exchange that will be completed
1068 * frm = newly-allocated frame that has not been submitted
1069 * pkt_state = LV fpkt state
1070 * pkt_reason = LV fpkt reason
1079 fcoei_complete_xch(fcoei_exchange_t
*xch
, fcoe_frame_t
*frm
,
1080 uint8_t pkt_state
, uint8_t pkt_reason
)
1084 if (pkt_state
!= FC_PKT_SUCCESS
) {
1085 FCOEI_LOG(__FUNCTION__
, "FHDR: %x/%x/%x, %x/%x/%x",
1086 xch
->xch_fpkt
->pkt_cmd_fhdr
.r_ctl
,
1087 xch
->xch_fpkt
->pkt_cmd_fhdr
.f_ctl
,
1088 xch
->xch_fpkt
->pkt_cmd_fhdr
.type
,
1089 xch
->xch_fpkt
->pkt_resp_fhdr
.r_ctl
,
1090 xch
->xch_fpkt
->pkt_resp_fhdr
.f_ctl
,
1091 xch
->xch_fpkt
->pkt_resp_fhdr
.type
);
1092 FCOEI_LOG(__FUNCTION__
, "%p/%p/%x/%x",
1093 xch
, frm
, pkt_state
, pkt_reason
);
1098 * It's newly-allocated frame , which we haven't sent out
1100 xch
->xch_ss
->ss_eport
->eport_free_netb(frm
->frm_netb
);
1101 xch
->xch_ss
->ss_eport
->eport_release_frame(frm
);
1102 FCOEI_LOG(__FUNCTION__
, "xch: %p, not submitted", xch
);
1106 * If xch is in hash table, we need remove it
1108 if (xch
->xch_flags
& XCH_FLAG_IN_SOL_HASH
) {
1109 (void) mod_hash_remove(xch
->xch_ss
->ss_sol_oxid_hash
,
1110 FMHK(xch
->xch_oxid
), &val
);
1111 ASSERT((fcoei_exchange_t
*)val
== xch
);
1112 xch
->xch_flags
&= ~XCH_FLAG_IN_SOL_HASH
;
1113 } else if (xch
->xch_flags
& XCH_FLAG_IN_UNSOL_HASH
) {
1114 (void) mod_hash_remove(xch
->xch_ss
->ss_unsol_rxid_hash
,
1115 FMHK(xch
->xch_rxid
), &val
);
1116 ASSERT((fcoei_exchange_t
*)val
== xch
);
1117 xch
->xch_flags
&= ~XCH_FLAG_IN_UNSOL_HASH
;
1119 FCOEI_LOG(__FUNCTION__
, "xch not in any hash: %p", xch
);
1122 xch
->xch_fpkt
->pkt_state
= pkt_state
;
1123 xch
->xch_fpkt
->pkt_reason
= pkt_reason
;
1124 if (xch
->xch_fpkt
->pkt_tran_flags
& FC_TRAN_NO_INTR
) {
1125 FCOEI_LOG(__FUNCTION__
, "polled xch is done: %p", xch
);
1126 sema_v(&xch
->xch_sema
);
1128 xch
->xch_fpkt
->pkt_comp(xch
->xch_fpkt
);