- Node name setting added

- qlini_mode "disabled" parameter handling improved

 - Docs updated



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2607 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-11-05 18:56:54 +00:00
parent 0754629ea6
commit 8c33147780
9 changed files with 159 additions and 381 deletions
+6
View File
@@ -6,6 +6,12 @@ Summary of changes between versions 2.0.0 and 2.1.0
control for them. Thanks a lot to Uri Yanai and Dorit
Halsadi!
- Node name setting added
- qlini_mode "disabled" parameter handling improved
- Other minor fixes and cleanups
Summary of changes between versions 1.0.2 and 2.0.0
---------------------------------------------------
+1 -9
View File
@@ -142,15 +142,7 @@ enabled back.
Usage of mode "disabled" is recommended, if you have incorrectly
functioning your target's initiators, which if once seen a port in
initiator mode, later refuse to see it as a target. Although this mode
does make a noticeable difference, it isn't absolutely strong, since the
firmware once initialized requires a HBA to be in either initiator, or
target mode, so until you enable target mode on a port, your initiators
will report this port as working in initiator mode. If you need
absolutely strong assurance that initiator mode never enabled, you can
consider using patch
unsupported-patches/qla_delayed_hw_init_tgt_mode_from_the_beginning.diff.
See description of it inside the patch.
initiator mode, later refuse to see it as a target.
Use mode "enabled" if you need your QLA adapters to work in both
initiator and target modes at the same time.
+104 -27
View File
@@ -133,23 +133,24 @@ static ssize_t q2t_abort_isp_store(struct kobject *kobj,
struct kobj_attribute q2t_abort_isp_attr =
__ATTR(abort_isp, S_IWUSR, NULL, q2t_abort_isp_store);
static const struct attribute *q2t_tgt_attrs[] = {
&q2t_expl_conf_attr.attr,
&q2t_abort_isp_attr.attr,
NULL,
};
static ssize_t q2t_hw_target_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static struct kobj_attribute q2t_hw_target_attr =
__ATTR(hw_target, S_IRUGO, q2t_hw_target_show, NULL);
static ssize_t q2t_vp_node_name_show(struct kobject *kobj,
static ssize_t q2t_node_name_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static struct kobj_attribute q2t_vp_node_name_attr =
__ATTR(node_name, S_IRUGO, q2t_vp_node_name_show, NULL);
__ATTR(node_name, S_IRUGO, q2t_node_name_show, NULL);
static ssize_t q2t_node_name_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buffer, size_t size);
static struct kobj_attribute q2t_hw_node_name_attr =
__ATTR(node_name, S_IRUGO|S_IWUSR, q2t_node_name_show,
q2t_node_name_store);
static ssize_t q2t_vp_parent_host_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
@@ -157,6 +158,12 @@ static ssize_t q2t_vp_parent_host_show(struct kobject *kobj,
static struct kobj_attribute q2t_vp_parent_host_attr =
__ATTR(parent_host, S_IRUGO, q2t_vp_parent_host_show, NULL);
static const struct attribute *q2t_tgt_attrs[] = {
&q2t_expl_conf_attr.attr,
&q2t_abort_isp_attr.attr,
NULL,
};
#endif /* CONFIG_SCST_PROC */
static int q2t_enable_tgt(struct scst_tgt *tgt, bool enable);
@@ -5310,7 +5317,8 @@ static int q2t_add_target(scsi_qla_host_t *ha)
ha->q2t_tgt = tgt;
if (q2t_get_target_name(ha->port_name, &wwn) != 0)
res = q2t_get_target_name(ha->port_name, &wwn);
if (res != 0)
goto out_free;
tgt->scst_tgt = scst_register_target(&tgt2x_template, wwn);
@@ -5368,6 +5376,13 @@ static int q2t_add_target(scsi_qla_host_t *ha)
PRINT_ERROR("qla2x00t(%ld): Unable to create "
"\"hw_target\" file for target %s",
ha->instance, scst_get_tgt_name(tgt->scst_tgt));
rc = sysfs_create_file(scst_sysfs_get_tgt_kobj(tgt->scst_tgt),
&q2t_hw_node_name_attr.attr);
if (rc != 0)
PRINT_ERROR("qla2x00t(%ld): Unable to create "
"\"node_name\" file for HW target %s",
ha->instance, scst_get_tgt_name(tgt->scst_tgt));
} else {
rc = sysfs_create_file(scst_sysfs_get_tgt_kobj(tgt->scst_tgt),
&q2t_vp_node_name_attr.attr);
@@ -5534,7 +5549,7 @@ static int q2t_parse_wwn(const char *ns, u64 *nm)
u8 wwn[8];
/* validate we have enough characters for WWPN */
if (strlen(ns) != 23)
if (strnlen(ns, 23) != 23)
return -EINVAL;
memset(wwn, 0, sizeof(wwn));
@@ -5824,27 +5839,93 @@ static ssize_t q2t_hw_target_show(struct kobject *kobj,
return sprintf(buf, "%d\n", 1);
}
static ssize_t q2t_vp_node_name_show(struct kobject *kobj,
static ssize_t q2t_node_name_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_tgt *scst_tgt;
struct q2t_tgt *tgt;
scsi_qla_host_t *ha;
ssize_t size;
ssize_t res;
char *wwn;
uint8_t *node_name;
scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
ha = tgt->ha;
if (q2t_get_target_name(ha->node_name, &wwn) != 0)
return 0;
if (ha->parent == NULL) {
if (qla_tgt_mode_enabled(ha) || !ha->node_name_set)
node_name = ha->node_name;
else
node_name = ha->tgt_node_name;
} else
node_name = ha->node_name;
size = sprintf(buf, "%s\n%s\n", wwn, SCST_SYSFS_KEY_MARK);
res = q2t_get_target_name(node_name, &wwn);
if (res != 0)
goto out;
res = sprintf(buf, "%s\n", wwn);
if ((ha->parent != NULL) || ha->node_name_set)
res += sprintf(&buf[res], "%s\n", SCST_SYSFS_KEY_MARK);
kfree(wwn);
return size;
out:
return res;
}
static ssize_t q2t_node_name_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buffer, size_t size)
{
struct scst_tgt *scst_tgt;
struct q2t_tgt *tgt;
scsi_qla_host_t *ha;
u64 node_name, old_node_name;
int res;
TRACE_ENTRY();
scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
ha = tgt->ha;
sBUG_ON(ha->parent != NULL);
if (size == 0)
goto out_default;
res = q2t_parse_wwn(buffer, &node_name);
if (res != 0) {
if ((buffer[0] == '\0') || (buffer[0] == '\n'))
goto out_default;
PRINT_ERROR("qla2x00t(%ld): Wrong node name", ha->instance);
goto out;
}
old_node_name = wwn_to_u64(ha->node_name);
if (old_node_name == node_name)
goto out_success;
u64_to_wwn(node_name, ha->tgt_node_name);
ha->node_name_set = 1;
abort:
if (qla_tgt_mode_enabled(ha)) {
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
qla2x00_wait_for_hba_online(ha);
}
out_success:
res = size;
out:
TRACE_EXIT_RES(res);
return res;
out_default:
ha->node_name_set = 0;
goto abort;
}
static ssize_t q2t_vp_parent_host_show(struct kobject *kobj,
@@ -5853,27 +5934,23 @@ static ssize_t q2t_vp_parent_host_show(struct kobject *kobj,
struct scst_tgt *scst_tgt;
struct q2t_tgt *tgt;
scsi_qla_host_t *ha;
ssize_t size;
ssize_t res;
char *wwn;
scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
tgt = (struct q2t_tgt *)scst_tgt_get_tgt_priv(scst_tgt);
ha = to_qla_parent(tgt->ha);
if (!ha) {
PRINT_ERROR("qla2x00t(%ld): No parent for NPIV target %s",
tgt->ha->instance, scst_get_tgt_name(scst_tgt));
return 0;
}
res = q2t_get_target_name(ha->port_name, &wwn);
if (res != 0)
goto out;
if (q2t_get_target_name(ha->port_name, &wwn) != 0)
return 0;
size = sprintf(buf, "%s\n%s\n", wwn, SCST_SYSFS_KEY_MARK);
res = sprintf(buf, "%s\n%s\n", wwn, SCST_SYSFS_KEY_MARK);
kfree(wwn);
return size;
out:
return res;
}
#else /* CONFIG_SCST_PROC */
+2 -2
View File
@@ -44,13 +44,13 @@
* Must be changed on any change in any initiator visible interfaces or
* data in the target add-on
*/
#define QLA2X_TARGET_MAGIC 268
#define QLA2X_TARGET_MAGIC 269
/*
* Must be changed on any change in any target visible interfaces or
* data in the initiator
*/
#define QLA2X_INITIATOR_MAGIC 57221
#define QLA2X_INITIATOR_MAGIC 57222
#define QLA2X_INI_MODE_STR_EXCLUSIVE "exclusive"
#define QLA2X_INI_MODE_STR_DISABLED "disabled"
+3
View File
@@ -2353,6 +2353,7 @@ typedef struct scsi_qla_host {
unsigned int enable_explicit_conf :1;
unsigned int host_shutting_down :1;
unsigned int ini_mode_force_reverse :1;
unsigned int node_name_set :1;
dma_addr_t atio_dma; /* Physical address. */
atio_t *atio_ring; /* Base virtual address */
@@ -2643,6 +2644,8 @@ typedef struct scsi_qla_host {
uint32_t saved_firmware_options_3;
uint8_t saved_firmware_options[2];
uint8_t saved_add_firmware_options[2];
uint8_t tgt_node_name[WWN_SIZE];
#endif /* CONFIG_SCSI_QLA2XXX_TARGET */
struct scsi_qla_host *parent; /* holds pport */
+1 -1
View File
@@ -550,7 +550,7 @@ qla2x00_rff_id(scsi_qla_host_t *ha)
ct_req->req.rff_id.fc4_feature = BIT_0 | BIT_1;
else
ct_req->req.rff_id.fc4_feature = BIT_0;
} else
} else if (qla_ini_mode_enabled(ha))
#endif
ct_req->req.rff_id.fc4_feature = BIT_1;
+34 -18
View File
@@ -129,7 +129,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
/* Enable target response to SCSI bus. */
if (qla_tgt_mode_enabled(ha))
qla2x00_send_enable_lun(ha, true);
else
else if (qla_ini_mode_enabled(ha))
qla2x00_send_enable_lun(ha, false);
}
#endif
@@ -1766,10 +1766,10 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
/* Disable Full Login after LIP */
nv->firmware_options[1] &= ~BIT_5;
/* Enable FC tapes support, just in case, it is ON by default */
/* Enable initial LIP */
nv->firmware_options[1] &= BIT_1;
/* Enable FC tapes support */
nv->add_firmware_options[1] |= BIT_4;
/* Enable Fibre Channel Confirm */
nv->add_firmware_options[1] |= BIT_5;
/* Enable Command Queuing in Target Mode */
nv->add_firmware_options[1] |= BIT_6;
} else {
@@ -1809,10 +1809,12 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
if (IS_QLA23XX(ha)) {
/* Enable full duplex */
nv->firmware_options[0] |= BIT_2;
/* Disable Fast Sataus Posting */
/* Disable Fast Status Posting */
nv->firmware_options[0] &= ~BIT_3;
/* P2P preferred, otherwise loop */
nv->add_firmware_options[1] |= BIT_5 | BIT_4;
/* out-of-order frames rassembly */
nv->special_options[0] |= BIT_6;
@@ -1859,13 +1861,19 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
while (cnt--)
*dptr1++ = *dptr2++;
/* Use alternate WWN? */
if (nv->host_p[1] & BIT_7) {
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
/* Prepare nodename */
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
if (ha->node_name_set) {
memcpy(icb->node_name, ha->tgt_node_name, WWN_SIZE);
icb->firmware_options[1] |= BIT_6;
} else
#endif
if (nv->host_p[1] & BIT_7) {
/* Use alternate WWN? */
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
if ((icb->firmware_options[1] & BIT_6) == 0) {
/*
* Firmware will apply the following mask if the nodename was
@@ -3759,7 +3767,9 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
/* Disable Full Login after LIP */
nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13);
/* Enable FC tapes support, just in case, it is ON by default */
/* Enable initial LIP */
nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_9);
/* Enable FC tapes support */
nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
} else {
if (ha->saved_set) {
@@ -3820,13 +3830,19 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
qla2x00_set_model_info(ha, nv->model_name, sizeof(nv->model_name),
"QLA2462");
/* Use alternate WWN? */
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
/* Prepare nodename */
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
if (ha->node_name_set) {
memcpy(icb->node_name, ha->tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= __constant_cpu_to_le32(BIT_14);
} else
#endif
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
/* Use alternate WWN? */
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
/*
* Firmware will apply the following mask if the nodename was
+8
View File
@@ -1020,6 +1020,13 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
ha->host_no));
if (!qla_tgt_mode_enabled(ha) && !qla_ini_mode_enabled(ha)) {
DEBUG11(printk("qla2x00_init_firmware(%ld): neither initiator, "
"nor target mode enabled, exiting\n", ha->host_no));
rval = QLA_SUCCESS;
goto out;
}
#ifdef QL_DEBUG_LEVEL_5
if (IS_FWI2_CAPABLE(ha)) {
struct init_cb_24xx *icb = (struct init_cb_24xx *)ha->init_cb;
@@ -1071,6 +1078,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
ha->host_no));
}
out:
return rval;
}
@@ -1,324 +0,0 @@
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;