mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-19 13:46:25 +00:00
- 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:
@@ -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
|
||||
---------------------------------------------------
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user