diff --git a/qla2x00t/qla2x00-target/README b/qla2x00t/qla2x00-target/README index 22cdaebe7..5da8229fd 100644 --- a/qla2x00t/qla2x00-target/README +++ b/qla2x00t/qla2x00-target/README @@ -137,6 +137,10 @@ of the initiator mode from enabled to disabled and vice versa. You can always see which modes are currently active in active_mode sysfs attribute. +Also if the "disabled" mode isn't sufficiently strong for you, you can +consider using patch unsupported-patches/qla_delayed_hw_init_tgt_mode_from_the_beginning.diff. +See description of it inside it. + Explicit conformation --------------------- diff --git a/qla2x00t/unsupported-patches/qla_delayed_hw_init_tgt_mode_from_the_beginning.diff b/qla2x00t/unsupported-patches/qla_delayed_hw_init_tgt_mode_from_the_beginning.diff new file mode 100644 index 000000000..41af251b2 --- /dev/null +++ b/qla2x00t/unsupported-patches/qla_delayed_hw_init_tgt_mode_from_the_beginning.diff @@ -0,0 +1,324 @@ +The below patch fixes a problem that RHEL 5 initiators encounter when +the target is running SCST + qla2x00tgt. The qla2xxx driver that is +shipped with Red Hat supplied kernels for RHEL 5 does not handle +fc_remote_port role changes. Specifically, a role change of: + +FCP Target -> unknown -> FCP Initiator -> FCP Target + +results in the fc_remote_port failing to transition to FCP Target. +The above role change is usually triggered by a reboot of the FC +target. After the target comes up after its reboot, the initiator(s) +will be unable to re-attach their storage without a reboot of their +own (or possibly an unload/reload of the qla2xxx driver). + +The problem lies in the initiator briefly seeing the target as a FCP +Initiator, an artifact from the qla2xxx and qla2x00tgt modules loading on +the target. This patch fixes the problem by delaying firmware loading +until the qla2x00tgt module is loaded. When the qla2x00tgt is loaded, +it is forced into target mode (i.e. target_mode_enabled = 1). This +requires that SCST have its configuration loaded _before_ qla2x00tgt +is loaded. Otherwise the initiators will log into the target without +security groups in place, etc... The qla2xxx driver needs to be loaded +with the parameter "qlini_mode=disabled" to postpone the firmware load +until qla2x00tgt is loaded. See below for loading example: + + 1. modprobe scst + 2. modprobe scst_vdisk + 3. modprobe qla2xxx qlini_mode=disabled + (NOTE: You should see that firmware initialization + was posponed by looking at the output of dmesg.) + 4. Load SCST configuration (scstadmin or other utility) + 5. modprobe qla2x00tgt + +Also required is that SCST and qla2x00tgt be compiled with PROCFS +support enabled (see below why). Starting at version 2.0.0, SCST +defaults to SYSFS, so make sure "make enable_procfs" is run before +building. + +With the patch applied, the resulting role change will be the +following during a target reboot: + +FCP Target -> unknown -> FCP Target + +The isp_mod target driver does not have this problem since the card +stays uninitialized until target mode in enabled. It is, however, still +possible to have problems during role transitioning with both isp_mod +and qla2x00tgt modules. This occurs if the Qlogic HBA is configured to +load BIOS during boot. This is typically used for SAN booting and +probably should be disabled on the target to keep things simple. + +Andrew Vasquez fixed this issue for the +main line kernels and was added in 2.6.27. RHEL 5 initiators running +kernels >= 2.6.27 do not need this patch applied. + +commit 6390d1f33faecf48e31f27dd7dbe928540f8acfc +Author: Andrew Vasquez +Date: Wed Aug 13 21:36:56 2008 -0700 + + [SCSI] qla2xxx: Correct synchronization of software/firmware fcport states. + + Greg Wettstein (greg@enjellic.com) noted: + http://article.gmane.org/gmane.linux.scsi/43409 + + on a reboot of a previously recognized SCST target, the initiator + driver would be unable to re-recognize the device as a target. + It turns out that prior to the SCST software reloading and + returning it's "target-capable" abilities in the PRLI payload, + the HBA would be re-initialized as an initiator-only type port. + Since initiators typically classify themselves as an FCP-2 + capable device, both software and firmware do not perform an + explicit logout during port-loss. Unfortunately, as can be seen + by the failure case, when the port (now target-capable) returns, + firmware performs an ADISC without a follow-on PRLI, leaving + stale 'initiator-only' data in the firmware's port database. + + Correct the discrepancy by performing the explicit logout during + the transport's request to terminate-rport-io, thus synchronizing + port states and ensuring a follow-on PRLI is performed. + + Reported-by: Greg Wettstein + Signed-off-by: Andrew Vasquez + Cc: Stable Tree + Signed-off-by: James Bottomley + + +This patch wasn't applied to the qla2x00t, because it can work only with +the obsolete procfs-based interface, where LUNs initialization for the +QLA targets happens before the corresponding SCST targets created. With +the sysfs-based interface it isn't possible, because in it all LUNs are +bound to target. It's so, at least, until SCST has persistent LUN +groups, so each target immediately after it's created would have all its +LUNs configured from the corresponding persistent group. + +-- + +Index: qla_init.c +=================================================================== +--- qla_init.c (revision 2148) ++++ qla_init.c (working copy) +@@ -4202,6 +4202,10 @@ int qla2xxx_tgt_register_driver(struct q + + memcpy(&qla_target, tgt_data, sizeof(qla_target)); + ++ res = qla2xxx_check_init_hardware(); ++ if (res != 0) ++ goto out; ++ + res = QLA2X_INITIATOR_MAGIC; + + out: +Index: qla_gbl.h +=================================================================== +--- qla_gbl.h (revision 2148) ++++ qla_gbl.h (working copy) +@@ -82,6 +82,8 @@ extern int qla2x00_post_hwe_work(struct + + extern void qla2x00_abort_fcport_cmds(fc_port_t *); + ++extern int qla2xxx_check_init_hardware(void); ++ + /* + * Global Functions in qla_mid.c source file. + */ +Index: qla2x_tgt.h +=================================================================== +--- qla2x_tgt.h (revision 2148) ++++ qla2x_tgt.h (working copy) +@@ -34,6 +34,8 @@ extern request_t *qla2x00_req_pkt(scsi_q + + extern struct qla_tgt_data qla_target; + ++extern bool ql2x_hardware_initialized; ++ + void qla_set_tgt_mode(scsi_qla_host_t *ha); + void qla_clear_tgt_mode(scsi_qla_host_t *ha); + +Index: qla_os.c +=================================================================== +--- qla_os.c (revision 2148) ++++ qla_os.c (working copy) +@@ -50,6 +50,9 @@ MODULE_PARM_DESC(qlini_mode, + static int ql2x_ini_mode = QLA2X_INI_MODE_EXCLUSIVE; + #endif + ++bool ql2x_hardware_initialized; ++EXPORT_SYMBOL(ql2x_hardware_initialized); ++ + /* + * SRB allocation cache + */ +@@ -3124,7 +3127,7 @@ void qla_clear_tgt_mode(scsi_qla_host_t + { + switch (ql2x_ini_mode) { + case QLA2X_INI_MODE_DISABLED: +- ha->host->active_mode = MODE_UNKNOWN; ++ ha->host->active_mode = MODE_TARGET; + break; + case QLA2X_INI_MODE_EXCLUSIVE: + ha->host->active_mode = MODE_INITIATOR; +@@ -3157,6 +3160,22 @@ static bool __init qla2x00_parse_ini_mod + + return true; + } ++ ++int qla2xxx_check_init_hardware(void) ++{ ++ int res = 0; ++ ++ if (!ql2x_hardware_initialized) { ++ res = pci_register_driver(&qla2xxx_pci_driver); ++ if (res != 0) ++ goto out; ++ ql2x_hardware_initialized = true; ++ } ++ ++out: ++ return res; ++} ++ + #else + static inline bool qla2x00_parse_ini_mode(void) + { +@@ -3193,7 +3212,8 @@ qla2x00_module_init(void) + + if (!qla2x00_parse_ini_mode()) { + printk("Wrong qlini_mode value %s\n", qlini_mode); +- return -EINVAL; ++ ret = -EINVAL; ++ goto out; + } + + /* Allocate cache for SRBs. */ +@@ -3202,7 +3222,8 @@ qla2x00_module_init(void) + if (srb_cachep == NULL) { + printk(KERN_ERR + "qla2xxx: Unable to allocate SRB cache...Failing load!\n"); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto out; + } + + /* Derive version string. */ +@@ -3213,26 +3234,46 @@ qla2x00_module_init(void) + qla2xxx_transport_template = + fc_attach_transport(&qla2xxx_transport_functions); + if (!qla2xxx_transport_template) { +- kmem_cache_destroy(srb_cachep); +- return -ENODEV; ++ ret = -ENODEV; ++ goto out_cache_destroy; + } + qla2xxx_transport_vport_template = + fc_attach_transport(&qla2xxx_transport_vport_functions); + if (!qla2xxx_transport_vport_template) { +- kmem_cache_destroy(srb_cachep); +- fc_release_transport(qla2xxx_transport_template); +- return -ENODEV; ++ ret = -ENODEV; ++ goto out_fc_release_transport_template; + } + + printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n", + qla2x00_version_str); +- ret = pci_register_driver(&qla2xxx_pci_driver); +- if (ret) { +- kmem_cache_destroy(srb_cachep); +- fc_release_transport(qla2xxx_transport_template); +- fc_release_transport(qla2xxx_transport_vport_template); ++ ++#ifdef CONFIG_SCSI_QLA2XXX_TARGET ++ if (ql2x_ini_mode == QLA2X_INI_MODE_DISABLED) { ++ printk(KERN_INFO "qlini_mode disabled (%d), delaying hardware " ++ "initialization until target mode add-on load\n", ++ QLA2X_INI_MODE_DISABLED); ++ goto out; + } ++#endif ++ ++ ret = pci_register_driver(&qla2xxx_pci_driver); ++ if (ret) ++ goto out_fc_release_vport_template; ++ ++ ql2x_hardware_initialized = true; ++ ++out: + return ret; ++ ++out_fc_release_vport_template: ++ fc_release_transport(qla2xxx_transport_vport_template); ++ ++out_fc_release_transport_template: ++ fc_release_transport(qla2xxx_transport_template); ++ ++out_cache_destroy: ++ kmem_cache_destroy(srb_cachep); ++ goto out; + } + + /** +@@ -3241,8 +3282,10 @@ qla2x00_module_init(void) + static void __exit + qla2x00_module_exit(void) + { +- pci_unregister_driver(&qla2xxx_pci_driver); +- qla2x00_release_firmware(); ++ if (ql2x_hardware_initialized) { ++ pci_unregister_driver(&qla2xxx_pci_driver); ++ qla2x00_release_firmware(); ++ } + kmem_cache_destroy(srb_cachep); + fc_release_transport(qla2xxx_transport_template); + fc_release_transport(qla2xxx_transport_vport_template); +Index: qla2x00-target/qla2x00t.c +=================================================================== +--- qla2x00-target/qla2x00t.c (revision 2148) ++++ qla2x00-target/qla2x00t.c (working copy) +@@ -314,7 +314,8 @@ static int q2t_target_detect(struct scst + goto out; + } + +- qla2xxx_add_targets(); ++ if (ql2x_hardware_initialized) ++ qla2xxx_add_targets(); + + res = 0; + +@@ -5000,9 +5001,12 @@ static int q2t_add_target(scsi_qla_host_ + + TRACE_ENTRY(); + +- TRACE_DBG("Registering target for host %ld(%p)", ha->host_no, ha); ++ if ((ha->q2t_tgt != NULL) || (ha->tgt != NULL)) { ++ res = 0; ++ goto out; ++ } + +- sBUG_ON((ha->q2t_tgt != NULL) || (ha->tgt != NULL)); ++ TRACE_DBG("Registering target for host %ld(%p)", ha->host_no, ha); + + tgt = kzalloc(sizeof(*tgt), GFP_KERNEL); + if (tgt == NULL) { +@@ -5029,7 +5033,8 @@ static int q2t_add_target(scsi_qla_host_ + + ha->q2t_tgt = tgt; + +- if (q2t_get_target_name(ha, &wwn) != 0) ++ res = q2t_get_target_name(ha, &wwn); ++ if (res != 0) + goto out_free; + + tgt->scst_tgt = scst_register_target(&tgt2x_template, wwn); +@@ -5084,6 +5089,13 @@ static int q2t_add_target(scsi_qla_host_ + scst_tgt_set_sg_tablesize(tgt->scst_tgt, sg_tablesize); + scst_tgt_set_tgt_priv(tgt->scst_tgt, tgt); + ++ if (qla_tgt_mode_enabled(ha)) { ++ ha->tgt = ha->q2t_tgt; ++ ha->tgt->tgt_stop = 0; ++ } ++ ++ res = 0; ++ + out: + TRACE_EXIT_RES(res); + return res;