summaryrefslogtreecommitdiff
path: root/drivers/scsi/qla2xxx/qla_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_attr.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c587
1 files changed, 569 insertions, 18 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 4888b999e82f..b28f159fdaee 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -158,9 +158,17 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return 0;
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
+
if (IS_NOCACHE_VPD_TYPE(ha))
ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
ha->nvram_size);
+ mutex_unlock(&ha->optrom_mutex);
+
return memory_read_from_buffer(buf, count, &off, ha->nvram,
ha->nvram_size);
}
@@ -208,10 +216,17 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
return -EAGAIN;
}
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
+ return -EAGAIN;
+ }
+
/* Write NVRAM. */
ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count);
ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base,
- count);
+ count);
+ mutex_unlock(&ha->optrom_mutex);
ql_dbg(ql_dbg_user, vha, 0x7060,
"Setting ISP_ABORT_NEEDED\n");
@@ -322,6 +337,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
size = ha->optrom_size - start;
mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
switch (val) {
case 0:
if (ha->optrom_state != QLA_SREADING &&
@@ -499,8 +518,14 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
faddr = ha->flt_region_vpd_sec << 2;
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
ha->isp_ops->read_optrom(vha, ha->vpd, faddr,
ha->vpd_size);
+ mutex_unlock(&ha->optrom_mutex);
}
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
}
@@ -518,9 +543,6 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
if (unlikely(pci_channel_offline(ha->pdev)))
return 0;
- if (qla2x00_chip_is_down(vha))
- return 0;
-
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size ||
!ha->isp_ops->write_nvram)
return 0;
@@ -531,16 +553,25 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
return -EAGAIN;
}
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
+ }
+
/* Write NVRAM. */
ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count);
ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count);
/* Update flash version information for 4Gb & above. */
- if (!IS_FWI2_CAPABLE(ha))
+ if (!IS_FWI2_CAPABLE(ha)) {
+ mutex_unlock(&ha->optrom_mutex);
return -EINVAL;
+ }
tmp_data = vmalloc(256);
if (!tmp_data) {
+ mutex_unlock(&ha->optrom_mutex);
ql_log(ql_log_warn, vha, 0x706b,
"Unable to allocate memory for VPD information update.\n");
return -ENOMEM;
@@ -548,6 +579,8 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
ha->isp_ops->get_flash_version(vha, tmp_data);
vfree(tmp_data);
+ mutex_unlock(&ha->optrom_mutex);
+
return count;
}
@@ -573,10 +606,15 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN) || off != 0 || count < SFP_DEV_SIZE)
return 0;
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
return 0;
+ }
rval = qla2x00_read_sfp_dev(vha, buf, count);
+ mutex_unlock(&vha->hw->optrom_mutex);
+
if (rval)
return -EIO;
@@ -785,9 +823,11 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
if (unlikely(pci_channel_offline(ha->pdev)))
return 0;
-
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
return 0;
+ }
if (ha->xgmac_data)
goto do_read;
@@ -795,6 +835,7 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
&ha->xgmac_data_dma, GFP_KERNEL);
if (!ha->xgmac_data) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x7076,
"Unable to allocate memory for XGMAC read-data.\n");
return 0;
@@ -806,6 +847,8 @@ do_read:
rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
XGMAC_DATA_SIZE, &actual_size);
+
+ mutex_unlock(&vha->hw->optrom_mutex);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7077,
"Unable to read XGMAC data (%x).\n", rval);
@@ -842,13 +885,16 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj,
if (ha->dcbx_tlv)
goto do_read;
-
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
return 0;
+ }
ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
&ha->dcbx_tlv_dma, GFP_KERNEL);
if (!ha->dcbx_tlv) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x7078,
"Unable to allocate memory for DCBX TLV read-data.\n");
return -ENOMEM;
@@ -859,6 +905,9 @@ do_read:
rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
DCBX_TLV_DATA_SIZE);
+
+ mutex_unlock(&vha->hw->optrom_mutex);
+
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7079,
"Unable to read DCBX TLV (%x).\n", rval);
@@ -1159,6 +1208,34 @@ qla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr,
}
static ssize_t
+qla_zio_threshold_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ return scnprintf(buf, PAGE_SIZE, "%d exchanges\n",
+ vha->hw->last_zio_threshold);
+}
+
+static ssize_t
+qla_zio_threshold_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (vha->hw->zio_mode != QLA_ZIO_MODE_6)
+ return -EINVAL;
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+ if (val < 0 || val > 256)
+ return -ERANGE;
+
+ atomic_set(&vha->hw->zio_threshold, val);
+ return strlen(buf);
+}
+
+static ssize_t
qla2x00_beacon_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1184,15 +1261,17 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return -EPERM;
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ mutex_lock(&vha->hw->optrom_mutex);
if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x707a,
"Abort ISP active -- ignoring beacon request.\n");
return -EBUSY;
}
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
if (val)
rval = ha->isp_ops->beacon_on(vha);
else
@@ -1201,6 +1280,8 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
if (rval != QLA_SUCCESS)
count = 0;
+ mutex_unlock(&vha->hw->optrom_mutex);
+
return count;
}
@@ -1370,18 +1451,24 @@ qla2x00_thermal_temp_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
uint16_t temp = 0;
+ int rc;
+ mutex_lock(&vha->hw->optrom_mutex);
if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n");
goto done;
}
if (vha->hw->flags.eeh_busy) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x70dd, "PCI EEH busy.\n");
goto done;
}
- if (qla2x00_get_thermal_temp(vha, &temp) == QLA_SUCCESS)
+ rc = qla2x00_get_thermal_temp(vha, &temp);
+ mutex_unlock(&vha->hw->optrom_mutex);
+ if (rc == QLA_SUCCESS)
return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
done:
@@ -1402,13 +1489,24 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
return scnprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
}
- if (qla2x00_chip_is_down(vha))
+ mutex_lock(&vha->hw->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
+ mutex_unlock(&vha->hw->optrom_mutex);
ql_log(ql_log_warn, vha, 0x707c,
"ISP reset active.\n");
- else if (!vha->hw->flags.eeh_busy)
- rval = qla2x00_get_firmware_state(vha, state);
- if (rval != QLA_SUCCESS)
+ goto out;
+ } else if (vha->hw->flags.eeh_busy) {
+ mutex_unlock(&vha->hw->optrom_mutex);
+ goto out;
+ }
+
+ rval = qla2x00_get_firmware_state(vha, state);
+ mutex_unlock(&vha->hw->optrom_mutex);
+out:
+ if (rval != QLA_SUCCESS) {
memset(state, -1, sizeof(state));
+ rval = qla2x00_get_firmware_state(vha, state);
+ }
return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
state[0], state[1], state[2], state[3], state[4], state[5]);
@@ -1534,6 +1632,433 @@ qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr,
ha->max_speed_sup ? "32Gps" : "16Gps");
}
+/* ----- */
+
+static ssize_t
+qlini_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int len = 0;
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "Supported options: enabled | disabled | dual | exclusive\n");
+
+ /* --- */
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Current selection: ");
+
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_EXCLUSIVE);
+ break;
+ case QLA2XXX_INI_MODE_DISABLED:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_DISABLED);
+ break;
+ case QLA2XXX_INI_MODE_ENABLED:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_ENABLED);
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ QLA2XXX_INI_MODE_STR_DUAL);
+ break;
+ }
+ len += scnprintf(buf + len, PAGE_SIZE-len, "\n");
+
+ return len;
+}
+
+static char *mode_to_str[] = {
+ "exclusive",
+ "disabled",
+ "enabled",
+ "dual",
+};
+
+#define NEED_EXCH_OFFLOAD(_exchg) ((_exchg) > FW_DEF_EXCHANGES_CNT)
+static int qla_set_ini_mode(scsi_qla_host_t *vha, int op)
+{
+ int rc = 0;
+ enum {
+ NO_ACTION,
+ MODE_CHANGE_ACCEPT,
+ MODE_CHANGE_NO_ACTION,
+ TARGET_STILL_ACTIVE,
+ };
+ int action = NO_ACTION;
+ int set_mode = 0;
+ u8 eo_toggle = 0; /* exchange offload flipped */
+
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_DISABLED:
+ switch (op) {
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle) {
+ /*
+ * The number of exchange to be offload
+ * was tweaked or offload option was
+ * flipped
+ */
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ break;
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle) {
+ /*
+ * The number of exchange to be offload
+ * was tweaked or offload option was
+ * flipped
+ */
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ } else {
+ action = MODE_CHANGE_ACCEPT;
+ }
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ action = MODE_CHANGE_ACCEPT;
+ /* active_mode is target only, reset it to dual */
+ if (qla_tgt_mode_enabled(vha)) {
+ set_mode = 1;
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (qla_tgt_mode_enabled(vha))
+ action = TARGET_STILL_ACTIVE;
+ else {
+ action = MODE_CHANGE_ACCEPT;
+ set_mode = 1;
+ }
+ break;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ switch (op) {
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle)
+ /*
+ * The number of exchange to be offload
+ * was tweaked or offload option was
+ * flipped
+ */
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = NO_ACTION;
+ } else
+ action = NO_ACTION;
+
+ break;
+
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (qla_tgt_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xexchoffld !=
+ vha->u_ql2xexchoffld) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
+ eo_toggle)
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = MODE_CHANGE_NO_ACTION;
+ } else
+ action = MODE_CHANGE_NO_ACTION;
+ break;
+
+ case QLA2XXX_INI_MODE_DUAL: /* exclusive -> dual */
+ if (qla_tgt_mode_enabled(vha)) {
+ action = MODE_CHANGE_ACCEPT;
+ set_mode = 1;
+ } else
+ action = MODE_CHANGE_ACCEPT;
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (qla_tgt_mode_enabled(vha))
+ action = TARGET_STILL_ACTIVE;
+ else {
+ if (vha->hw->flags.fw_started)
+ action = MODE_CHANGE_NO_ACTION;
+ else
+ action = MODE_CHANGE_ACCEPT;
+ }
+ break;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ switch (op) {
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+ if (((vha->ql2xiniexchg != vha->u_ql2xiniexchg) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg)) ||
+ eo_toggle)
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = NO_ACTION;
+ break;
+ case QLA2XXX_INI_MODE_DUAL:
+ case QLA2XXX_INI_MODE_DISABLED:
+ action = MODE_CHANGE_ACCEPT;
+ break;
+ default:
+ action = MODE_CHANGE_NO_ACTION;
+ break;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_DUAL:
+ switch (op) {
+ case QLA2XXX_INI_MODE_DUAL:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld +
+ vha->u_ql2xiniexchg) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+
+ if ((((vha->ql2xexchoffld +
+ vha->ql2xiniexchg) !=
+ (vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) || eo_toggle)
+ action = MODE_CHANGE_ACCEPT;
+ else
+ action = NO_ACTION;
+ } else {
+ if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld +
+ vha->u_ql2xiniexchg) !=
+ vha->hw->flags.exchoffld_enabled)
+ eo_toggle = 1;
+
+ if ((((vha->ql2xexchoffld + vha->ql2xiniexchg)
+ != (vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) &&
+ NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg +
+ vha->u_ql2xexchoffld)) || eo_toggle)
+ action = MODE_CHANGE_NO_ACTION;
+ else
+ action = NO_ACTION;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_DISABLED:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ /* turning off initiator mode */
+ set_mode = 1;
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_NO_ACTION;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ set_mode = 1;
+ action = MODE_CHANGE_ACCEPT;
+ } else {
+ action = MODE_CHANGE_ACCEPT;
+ }
+ break;
+
+ case QLA2XXX_INI_MODE_ENABLED:
+ if (qla_tgt_mode_enabled(vha) ||
+ qla_dual_mode_enabled(vha)) {
+ action = TARGET_STILL_ACTIVE;
+ } else {
+ action = MODE_CHANGE_ACCEPT;
+ }
+ }
+ break;
+ }
+
+ switch (action) {
+ case MODE_CHANGE_ACCEPT:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Mode change accepted. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n",
+ mode_to_str[vha->qlini_mode], mode_to_str[op],
+ vha->ql2xexchoffld, vha->u_ql2xexchoffld,
+ vha->ql2xiniexchg, vha->u_ql2xiniexchg);
+
+ vha->qlini_mode = op;
+ vha->ql2xexchoffld = vha->u_ql2xexchoffld;
+ vha->ql2xiniexchg = vha->u_ql2xiniexchg;
+ if (set_mode)
+ qlt_set_mode(vha);
+ vha->flags.online = 1;
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ break;
+
+ case MODE_CHANGE_NO_ACTION:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Mode is set. No action taken. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n",
+ mode_to_str[vha->qlini_mode], mode_to_str[op],
+ vha->ql2xexchoffld, vha->u_ql2xexchoffld,
+ vha->ql2xiniexchg, vha->u_ql2xiniexchg);
+ vha->qlini_mode = op;
+ vha->ql2xexchoffld = vha->u_ql2xexchoffld;
+ vha->ql2xiniexchg = vha->u_ql2xiniexchg;
+ break;
+
+ case TARGET_STILL_ACTIVE:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Target Mode is active. Unable to change Mode.\n");
+ break;
+
+ case NO_ACTION:
+ default:
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Mode unchange. No action taken. %d|%d pct %d|%d.\n",
+ vha->qlini_mode, op,
+ vha->ql2xexchoffld, vha->u_ql2xexchoffld);
+ break;
+ }
+
+ return rc;
+}
+
+static ssize_t
+qlini_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int ini;
+
+ if (!buf)
+ return -EINVAL;
+
+ if (strncasecmp(QLA2XXX_INI_MODE_STR_EXCLUSIVE, buf,
+ strlen(QLA2XXX_INI_MODE_STR_EXCLUSIVE)) == 0)
+ ini = QLA2XXX_INI_MODE_EXCLUSIVE;
+ else if (strncasecmp(QLA2XXX_INI_MODE_STR_DISABLED, buf,
+ strlen(QLA2XXX_INI_MODE_STR_DISABLED)) == 0)
+ ini = QLA2XXX_INI_MODE_DISABLED;
+ else if (strncasecmp(QLA2XXX_INI_MODE_STR_ENABLED, buf,
+ strlen(QLA2XXX_INI_MODE_STR_ENABLED)) == 0)
+ ini = QLA2XXX_INI_MODE_ENABLED;
+ else if (strncasecmp(QLA2XXX_INI_MODE_STR_DUAL, buf,
+ strlen(QLA2XXX_INI_MODE_STR_DUAL)) == 0)
+ ini = QLA2XXX_INI_MODE_DUAL;
+ else
+ return -EINVAL;
+
+ qla_set_ini_mode(vha, ini);
+ return strlen(buf);
+}
+
+static ssize_t
+ql2xexchoffld_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int len = 0;
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "target exchange: new %d : current: %d\n\n",
+ vha->u_ql2xexchoffld, vha->ql2xexchoffld);
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n",
+ vha->host_no);
+
+ return len;
+}
+
+static ssize_t
+ql2xexchoffld_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ if (val > FW_MAX_EXCHANGES_CNT)
+ val = FW_MAX_EXCHANGES_CNT;
+ else if (val < 0)
+ val = 0;
+
+ vha->u_ql2xexchoffld = val;
+ return strlen(buf);
+}
+
+static ssize_t
+ql2xiniexchg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int len = 0;
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "target exchange: new %d : current: %d\n\n",
+ vha->u_ql2xiniexchg, vha->ql2xiniexchg);
+
+ len += scnprintf(buf + len, PAGE_SIZE-len,
+ "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n",
+ vha->host_no);
+
+ return len;
+}
+
+static ssize_t
+ql2xiniexchg_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int val = 0;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ if (val > FW_MAX_EXCHANGES_CNT)
+ val = FW_MAX_EXCHANGES_CNT;
+ else if (val < 0)
+ val = 0;
+
+ vha->u_ql2xiniexchg = val;
+ return strlen(buf);
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -1581,6 +2106,13 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL);
static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL);
static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL);
+static DEVICE_ATTR(zio_threshold, 0644,
+ qla_zio_threshold_show,
+ qla_zio_threshold_store);
+static DEVICE_ATTR_RW(qlini_mode);
+static DEVICE_ATTR_RW(ql2xexchoffld);
+static DEVICE_ATTR_RW(ql2xiniexchg);
+
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -1617,9 +2149,28 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_pep_version,
&dev_attr_min_link_speed,
&dev_attr_max_speed_sup,
+ &dev_attr_zio_threshold,
+ NULL, /* reserve for qlini_mode */
+ NULL, /* reserve for ql2xiniexchg */
+ NULL, /* reserve for ql2xexchoffld */
NULL,
};
+void qla_insert_tgt_attrs(void)
+{
+ struct device_attribute **attr;
+
+ /* advance to empty slot */
+ for (attr = &qla2x00_host_attrs[0]; *attr; ++attr)
+ continue;
+
+ *attr = &dev_attr_qlini_mode;
+ attr++;
+ *attr = &dev_attr_ql2xiniexchg;
+ attr++;
+ *attr = &dev_attr_ql2xexchoffld;
+}
+
/* Host attributes. */
static void