Unsupported (yet) patch making QLA adapters behave in the target mode from the very beginning with description from Bryan Mesich <bryan.mesi

ch@ndsu.edu>.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2360 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-10-06 18:51:51 +00:00
parent 9eac25591f
commit b4dfb7cda6
2 changed files with 328 additions and 0 deletions

View File

@@ -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
---------------------

View File

@@ -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 <andrew.vasquez@qlogic.com> 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 <andrew.vasquez@qlogic.com>
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 <greg@enjellic.com>
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Cc: Stable Tree <stable@kernel.org>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
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;