summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 02:32:26 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 02:32:26 +0100
commit194e57fd1835564735fd0ba5e3870230861cacd2 (patch)
tree9f2fd1463109ec6b151088417e0c1e14204d0924 /drivers/scsi/qla2xxx
parentMerge tag 'pci-v3.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/gi... (diff)
parentMerge branch 'misc' into for-linus (diff)
downloadlinux-194e57fd1835564735fd0ba5e3870230861cacd2.tar.xz
linux-194e57fd1835564735fd0ba5e3870230861cacd2.zip
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "This patch set is a lot of driver updates for qla4xxx, bfa, hpsa, qla2xxx. It also removes the aic7xxx_old driver (which has been deprecated for nearly a decade) and adds support for deadlines in error handling" * tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (75 commits) [SCSI] hpsa: allow SCSI mid layer to handle unit attention [SCSI] hpsa: do not require board "not ready" status after hard reset [SCSI] hpsa: enable unit attention reporting [SCSI] hpsa: rename scsi prefetch field [SCSI] hpsa: use workqueue instead of kernel thread for lockup detection [SCSI] ipr: increase dump size in ipr driver [SCSI] mac_scsi: Fix crash on out of memory [SCSI] st: fix enlarge_buffer [SCSI] qla1280: Annotate timer on stack so object debug does not complain [SCSI] qla4xxx: Update driver version to 5.04.00-k3 [SCSI] qla4xxx: Recreate chap data list during get chap operation [SCSI] qla4xxx: Add support for ISCSI_PARAM_LOCAL_IPADDR sysfs attr [SCSI] libiscsi: Add local_ipaddr parameter in iscsi_conn struct [SCSI] scsi_transport_iscsi: Export ISCSI_PARAM_LOCAL_IPADDR attr for iscsi_connection [SCSI] qla4xxx: Add host statistics support [SCSI] scsi_transport_iscsi: Add host statistics support [SCSI] qla4xxx: Added support for Diagnostics MBOX command [SCSI] bfa: Driver version upgrade to 3.2.23.0 [SCSI] bfa: change FC_ELS_TOV to 20sec [SCSI] bfa: Observed auto D-port mode instead of manual ...
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c116
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c44
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h13
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h22
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h15
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h19
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c82
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c73
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c39
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h12
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c22
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c33
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c368
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
16 files changed, 540 insertions, 329 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 5f174b83f56f..570c7fcc0c4d 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -862,7 +862,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
}
void
-qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)
+qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon)
{
struct Scsi_Host *host = vha->host;
struct sysfs_entry *iter;
@@ -880,7 +880,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)
iter->attr);
}
- if (ha->beacon_blink_led == 1)
+ if (stop_beacon && ha->beacon_blink_led == 1)
ha->isp_ops->beacon_off(vha);
}
@@ -890,7 +890,7 @@ static ssize_t
qla2x00_drvr_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
}
static ssize_t
@@ -901,7 +901,7 @@ qla2x00_fw_version_show(struct device *dev,
struct qla_hw_data *ha = vha->hw;
char fw_str[128];
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
ha->isp_ops->fw_version_str(vha, fw_str));
}
@@ -914,15 +914,15 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
uint32_t sn;
if (IS_QLAFX00(vha->hw)) {
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
vha->hw->mr.serial_num);
} else if (IS_FWI2_CAPABLE(ha)) {
- qla2xxx_get_vpd_field(vha, "SN", buf, PAGE_SIZE);
- return snprintf(buf, PAGE_SIZE, "%s\n", buf);
+ qla2xxx_get_vpd_field(vha, "SN", buf, PAGE_SIZE - 1);
+ return strlen(strcat(buf, "\n"));
}
sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
- return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
+ return scnprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
sn % 100000);
}
@@ -931,7 +931,7 @@ qla2x00_isp_name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
- return snprintf(buf, PAGE_SIZE, "ISP%04X\n", vha->hw->pdev->device);
+ return scnprintf(buf, PAGE_SIZE, "ISP%04X\n", vha->hw->pdev->device);
}
static ssize_t
@@ -942,10 +942,10 @@ qla2x00_isp_id_show(struct device *dev, struct device_attribute *attr,
struct qla_hw_data *ha = vha->hw;
if (IS_QLAFX00(vha->hw))
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
vha->hw->mr.hw_version);
- return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
+ return scnprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
ha->product_id[0], ha->product_id[1], ha->product_id[2],
ha->product_id[3]);
}
@@ -956,11 +956,7 @@ qla2x00_model_name_show(struct device *dev, struct device_attribute *attr,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
- if (IS_QLAFX00(vha->hw))
- return snprintf(buf, PAGE_SIZE, "%s\n",
- vha->hw->mr.product_name);
-
- return snprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_number);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_number);
}
static ssize_t
@@ -968,7 +964,7 @@ qla2x00_model_desc_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
vha->hw->model_desc ? vha->hw->model_desc : "");
}
@@ -979,7 +975,7 @@ qla2x00_pci_info_show(struct device *dev, struct device_attribute *attr,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
char pci_info[30];
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
vha->hw->isp_ops->pci_info_str(vha, pci_info));
}
@@ -994,29 +990,29 @@ qla2x00_link_state_show(struct device *dev, struct device_attribute *attr,
if (atomic_read(&vha->loop_state) == LOOP_DOWN ||
atomic_read(&vha->loop_state) == LOOP_DEAD ||
vha->device_flags & DFLG_NO_CABLE)
- len = snprintf(buf, PAGE_SIZE, "Link Down\n");
+ len = scnprintf(buf, PAGE_SIZE, "Link Down\n");
else if (atomic_read(&vha->loop_state) != LOOP_READY ||
qla2x00_reset_active(vha))
- len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n");
+ len = scnprintf(buf, PAGE_SIZE, "Unknown Link State\n");
else {
- len = snprintf(buf, PAGE_SIZE, "Link Up - ");
+ len = scnprintf(buf, PAGE_SIZE, "Link Up - ");
switch (ha->current_topology) {
case ISP_CFG_NL:
- len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Loop\n");
break;
case ISP_CFG_FL:
- len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
break;
case ISP_CFG_N:
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"N_Port to N_Port\n");
break;
case ISP_CFG_F:
- len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
break;
default:
- len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Loop\n");
break;
}
}
@@ -1032,10 +1028,10 @@ qla2x00_zio_show(struct device *dev, struct device_attribute *attr,
switch (vha->hw->zio_mode) {
case QLA_ZIO_MODE_6:
- len += snprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
break;
case QLA_ZIO_DISABLED:
- len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
break;
}
return len;
@@ -1075,7 +1071,7 @@ qla2x00_zio_timer_show(struct device *dev, struct device_attribute *attr,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
- return snprintf(buf, PAGE_SIZE, "%d us\n", vha->hw->zio_timer * 100);
+ return scnprintf(buf, PAGE_SIZE, "%d us\n", vha->hw->zio_timer * 100);
}
static ssize_t
@@ -1105,9 +1101,9 @@ qla2x00_beacon_show(struct device *dev, struct device_attribute *attr,
int len = 0;
if (vha->hw->beacon_blink_led)
- len += snprintf(buf + len, PAGE_SIZE-len, "Enabled\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Enabled\n");
else
- len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
return len;
}
@@ -1149,7 +1145,7 @@ qla2x00_optrom_bios_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
ha->bios_revision[0]);
}
@@ -1159,7 +1155,7 @@ qla2x00_optrom_efi_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
ha->efi_revision[0]);
}
@@ -1169,7 +1165,7 @@ qla2x00_optrom_fcode_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
ha->fcode_revision[0]);
}
@@ -1179,7 +1175,7 @@ qla2x00_optrom_fw_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
ha->fw_revision[3]);
}
@@ -1192,9 +1188,9 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
ha->gold_fw_version[0], ha->gold_fw_version[1],
ha->gold_fw_version[2], ha->gold_fw_version[3]);
}
@@ -1204,7 +1200,7 @@ qla2x00_total_isp_aborts_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
vha->qla_stats.total_isp_aborts);
}
@@ -1218,16 +1214,16 @@ qla24xx_84xx_fw_version_show(struct device *dev,
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA84XX(ha))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
if (ha->cs84xx->op_fw_version == 0)
rval = qla84xx_verify_chip(vha, status);
if ((rval == QLA_SUCCESS) && (status[0] == 0))
- return snprintf(buf, PAGE_SIZE, "%u\n",
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
(uint32_t)ha->cs84xx->op_fw_version);
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
}
static ssize_t
@@ -1238,9 +1234,9 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
ha->mpi_version[0], ha->mpi_version[1], ha->mpi_version[2],
ha->mpi_capabilities);
}
@@ -1253,9 +1249,9 @@ qla2x00_phy_version_show(struct device *dev, struct device_attribute *attr,
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
ha->phy_version[0], ha->phy_version[1], ha->phy_version[2]);
}
@@ -1266,7 +1262,7 @@ qla2x00_flash_block_size_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
}
static ssize_t
@@ -1276,9 +1272,9 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
if (!IS_CNA_CAPABLE(vha->hw))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
}
static ssize_t
@@ -1288,9 +1284,9 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
if (!IS_CNA_CAPABLE(vha->hw))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%pMR\n", vha->fcoe_vn_port_mac);
+ return scnprintf(buf, PAGE_SIZE, "%pMR\n", vha->fcoe_vn_port_mac);
}
static ssize_t
@@ -1299,7 +1295,7 @@ qla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
- return snprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap);
}
static ssize_t
@@ -1320,10 +1316,10 @@ qla2x00_thermal_temp_show(struct device *dev,
}
if (qla2x00_get_thermal_temp(vha, &temp) == QLA_SUCCESS)
- return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
done:
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
}
static ssize_t
@@ -1337,7 +1333,7 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
if (IS_QLAFX00(vha->hw)) {
pstate = qlafx00_fw_state_show(dev, attr, buf);
- return snprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
}
if (qla2x00_reset_active(vha))
@@ -1348,7 +1344,7 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
if (rval != QLA_SUCCESS)
memset(state, -1, sizeof(state));
- return snprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0],
+ return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0],
state[1], state[2], state[3], state[4]);
}
@@ -1359,9 +1355,9 @@ qla2x00_diag_requests_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
if (!IS_BIDI_CAPABLE(vha->hw))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%llu\n", vha->bidi_stats.io_count);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", vha->bidi_stats.io_count);
}
static ssize_t
@@ -1371,9 +1367,9 @@ qla2x00_diag_megabytes_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
if (!IS_BIDI_CAPABLE(vha->hw))
- return snprintf(buf, PAGE_SIZE, "\n");
+ return scnprintf(buf, PAGE_SIZE, "\n");
- return snprintf(buf, PAGE_SIZE, "%llu\n",
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
vha->bidi_stats.transfer_bytes >> 20);
}
@@ -1392,7 +1388,7 @@ qla2x00_fw_dump_size_show(struct device *dev, struct device_attribute *attr,
else
size = ha->fw_dump_len;
- return snprintf(buf, PAGE_SIZE, "%d\n", size);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", size);
}
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index aa57bf0af574..f15d03e6b7ee 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2022,6 +2022,46 @@ done:
}
static int
+qla26xx_serdes_op(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ int rval = 0;
+ struct qla_serdes_reg sr;
+
+ memset(&sr, 0, sizeof(sr));
+
+ sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, &sr, sizeof(sr));
+
+ switch (sr.cmd) {
+ case INT_SC_SERDES_WRITE_REG:
+ rval = qla2x00_write_serdes_word(vha, sr.addr, sr.val);
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ break;
+ case INT_SC_SERDES_READ_REG:
+ rval = qla2x00_read_serdes_word(vha, sr.addr, &sr.val);
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &sr, sizeof(sr));
+ bsg_job->reply->reply_payload_rcv_len = sizeof(sr);
+ break;
+ default:
+ ql_log(ql_log_warn, vha, 0x708c,
+ "Unknown serdes cmd %x.\n", sr.cmd);
+ rval = -EDOM;
+ break;
+ }
+
+ bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+ rval ? EXT_STATUS_MAILBOX : 0;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job->reply->result = DID_OK << 16;
+ bsg_job->job_done(bsg_job);
+ return 0;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -2069,6 +2109,10 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_FX00_MGMT_CMD:
return qlafx00_mgmt_cmd(bsg_job);
+
+ case QL_VND_SERDES_OP:
+ return qla26xx_serdes_op(bsg_job);
+
default:
return -ENOSYS;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index 04f770332c2b..e5c2126221e9 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -23,6 +23,7 @@
#define QL_VND_WRITE_I2C 0x10
#define QL_VND_READ_I2C 0x11
#define QL_VND_FX00_MGMT_CMD 0x12
+#define QL_VND_SERDES_OP 0x13
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
@@ -212,4 +213,16 @@ struct qla_i2c_access {
uint8_t buffer[0x40];
} __packed;
+/* 26xx serdes register interface */
+
+/* serdes reg commands */
+#define INT_SC_SERDES_READ_REG 1
+#define INT_SC_SERDES_WRITE_REG 2
+
+struct qla_serdes_reg {
+ uint16_t cmd;
+ uint16_t addr;
+ uint16_t val;
+} __packed;
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index ee5c1833eb73..f6103f553bb1 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,8 +11,9 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x0159 | 0x4b,0xba,0xfa |
- * | Mailbox commands | 0x1181 | 0x111a-0x111b |
+ * | Module Init and Probe | 0x015b | 0x4b,0xba,0xfa |
+ * | | | 0x0x015a |
+ * | Mailbox commands | 0x1187 | 0x111a-0x111b |
* | | | 0x1155-0x1158 |
* | | | 0x1018-0x1019 |
* | | | 0x1115-0x1116 |
@@ -26,7 +27,7 @@
* | | | 0x302d,0x3033 |
* | | | 0x3036,0x3038 |
* | | | 0x303a |
- * | DPC Thread | 0x4022 | 0x4002,0x4013 |
+ * | DPC Thread | 0x4023 | 0x4002,0x4013 |
* | Async Events | 0x5087 | 0x502b-0x502f |
* | | | 0x5047,0x5052 |
* | | | 0x5084,0x5075 |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 93db74ef3461..41d6491d7bd9 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -862,7 +862,6 @@ struct mbx_cmd_32 {
*/
#define MBC_LOAD_RAM 1 /* Load RAM. */
#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */
-#define MBC_WRITE_RAM_WORD 4 /* Write RAM word. */
#define MBC_READ_RAM_WORD 5 /* Read RAM word. */
#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */
#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */
@@ -937,6 +936,8 @@ struct mbx_cmd_32 {
/*
* ISP24xx mailbox commands
*/
+#define MBC_WRITE_SERDES 0x3 /* Write serdes word. */
+#define MBC_READ_SERDES 0x4 /* Read serdes word. */
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
@@ -2734,7 +2735,6 @@ struct req_que {
srb_t **outstanding_cmds;
uint32_t current_outstanding_cmd;
uint16_t num_outstanding_cmds;
-#define MAX_Q_DEPTH 32
int max_q_depth;
dma_addr_t dma_fx00;
@@ -3302,12 +3302,7 @@ struct qla_hw_data {
struct work_struct nic_core_reset;
struct work_struct idc_state_handler;
struct work_struct nic_core_unrecoverable;
-
-#define HOST_QUEUE_RAMPDOWN_INTERVAL (60 * HZ)
-#define HOST_QUEUE_RAMPUP_INTERVAL (30 * HZ)
- unsigned long host_last_rampdown_time;
- unsigned long host_last_rampup_time;
- int cfg_lun_q_depth;
+ struct work_struct board_disable;
struct mr_data_fx00 mr;
@@ -3372,12 +3367,11 @@ typedef struct scsi_qla_host {
#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */
#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */
#define SCR_PENDING 21 /* SCR in target mode */
-#define HOST_RAMP_DOWN_QUEUE_DEPTH 22
-#define HOST_RAMP_UP_QUEUE_DEPTH 23
-#define PORT_UPDATE_NEEDED 24
-#define FX00_RESET_RECOVERY 25
-#define FX00_TARGET_SCAN 26
-#define FX00_CRITEMP_RECOVERY 27
+#define PORT_UPDATE_NEEDED 22
+#define FX00_RESET_RECOVERY 23
+#define FX00_TARGET_SCAN 24
+#define FX00_CRITEMP_RECOVERY 25
+#define FX00_HOST_INFO_RESEND 26
uint32_t device_flags;
#define SWITCH_FOUND BIT_0
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 4446bf5fe292..1f426628a0a5 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -98,7 +98,6 @@ extern int qlport_down_retry;
extern int ql2xplogiabsentdevice;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
-extern int ql2xmaxqdepth;
extern int ql2xallocfwdump;
extern int ql2xextended_error_logging;
extern int ql2xiidmaenable;
@@ -160,6 +159,9 @@ extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
+extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
+extern void qla2x00_disable_board_on_pci_error(struct work_struct *);
+
/*
* Global Functions in qla_mid.c source file.
*/
@@ -339,6 +341,11 @@ extern int
qla2x00_system_error(scsi_qla_host_t *);
extern int
+qla2x00_write_serdes_word(scsi_qla_host_t *, uint16_t, uint16_t);
+extern int
+qla2x00_read_serdes_word(scsi_qla_host_t *, uint16_t, uint16_t *);
+
+extern int
qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
extern int
@@ -455,6 +462,7 @@ extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t);
+bool qla2x00_check_reg_for_disconnect(scsi_qla_host_t *, uint32_t);
extern int qla2x00_beacon_on(struct scsi_qla_host *);
extern int qla2x00_beacon_off(struct scsi_qla_host *);
@@ -541,10 +549,9 @@ struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
extern struct fc_function_template qla2xxx_transport_vport_functions;
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
-extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
+extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *, bool);
extern void qla2x00_init_host_attr(scsi_qla_host_t *);
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
-extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
extern int qla2x00_echo_test(scsi_qla_host_t *,
struct msg_echo_lb *, uint16_t *);
@@ -725,7 +732,7 @@ extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha);
extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha);
extern int qla8044_device_state_handler(struct scsi_qla_host *vha);
extern void qla8044_clear_qsnt_ready(struct scsi_qla_host *vha);
-extern void qla8044_clear_drv_active(struct scsi_qla_host *vha);
+extern void qla8044_clear_drv_active(struct qla_hw_data *);
void qla8044_get_minidump(struct scsi_qla_host *vha);
int qla8044_collect_md_data(struct scsi_qla_host *vha);
extern int qla8044_md_get_template(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 03f715e7591e..e7e5f4facf7f 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1694,6 +1694,8 @@ enable_82xx_npiv:
if (!fw_major_version && ql2xallocfwdump
&& !(IS_P3P_TYPE(ha)))
qla2x00_alloc_fw_dump(vha);
+ } else {
+ goto failed;
}
} else {
ql_log(ql_log_fatal, vha, 0x00cd,
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 957088b04611..ce8b5fb0f347 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -261,25 +261,6 @@ qla2x00_gid_list_size(struct qla_hw_data *ha)
}
static inline void
-qla2x00_do_host_ramp_up(scsi_qla_host_t *vha)
-{
- if (vha->hw->cfg_lun_q_depth >= ql2xmaxqdepth)
- return;
-
- /* Wait at least HOST_QUEUE_RAMPDOWN_INTERVAL before ramping up */
- if (time_before(jiffies, (vha->hw->host_last_rampdown_time +
- HOST_QUEUE_RAMPDOWN_INTERVAL)))
- return;
-
- /* Wait at least HOST_QUEUE_RAMPUP_INTERVAL between each ramp up */
- if (time_before(jiffies, (vha->hw->host_last_rampup_time +
- HOST_QUEUE_RAMPUP_INTERVAL)))
- return;
-
- set_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags);
-}
-
-static inline void
qla2x00_handle_mbx_completion(struct qla_hw_data *ha, int status)
{
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ff9c86b1a0d8..9bc86b9e86b1 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -56,6 +56,16 @@ qla2100_intr_handler(int irq, void *dev_id)
vha = pci_get_drvdata(ha->pdev);
for (iter = 50; iter--; ) {
hccr = RD_REG_WORD(&reg->hccr);
+ /* Check for PCI disconnection */
+ if (hccr == 0xffff) {
+ /*
+ * Schedule this on the default system workqueue so that
+ * all the adapter workqueues and the DPC thread can be
+ * shutdown cleanly.
+ */
+ schedule_work(&ha->board_disable);
+ break;
+ }
if (hccr & HCCR_RISC_PAUSE) {
if (pci_channel_offline(ha->pdev))
break;
@@ -110,6 +120,22 @@ qla2100_intr_handler(int irq, void *dev_id)
return (IRQ_HANDLED);
}
+bool
+qla2x00_check_reg_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
+{
+ /* Check for PCI disconnection */
+ if (reg == 0xffffffff) {
+ /*
+ * Schedule this on the default system workqueue so that all the
+ * adapter workqueues and the DPC thread can be shutdown
+ * cleanly.
+ */
+ schedule_work(&vha->hw->board_disable);
+ return true;
+ } else
+ return false;
+}
+
/**
* qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
@@ -148,11 +174,14 @@ qla2300_intr_handler(int irq, void *dev_id)
vha = pci_get_drvdata(ha->pdev);
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+ if (qla2x00_check_reg_for_disconnect(vha, stat))
+ break;
if (stat & HSR_RISC_PAUSED) {
if (unlikely(pci_channel_offline(ha->pdev)))
break;
hccr = RD_REG_WORD(&reg->hccr);
+
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
ql_log(ql_log_warn, vha, 0x5026,
"Parity error -- HCCR=%x, Dumping "
@@ -269,11 +298,18 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
{ "Complete", "Request Notification", "Time Extension" };
int rval;
struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
+ struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82;
uint16_t __iomem *wptr;
uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
/* Seed data -- mailbox1 -> mailbox7. */
- wptr = (uint16_t __iomem *)&reg24->mailbox1;
+ if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
+ wptr = (uint16_t __iomem *)&reg24->mailbox1;
+ else if (IS_QLA8044(vha->hw))
+ wptr = (uint16_t __iomem *)&reg82->mailbox_out[1];
+ else
+ return;
+
for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
mb[cnt] = RD_REG_WORD(wptr);
@@ -287,7 +323,7 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
case MBA_IDC_COMPLETE:
if (mb[1] >> 15) {
vha->hw->flags.idc_compl_status = 1;
- if (vha->hw->notify_dcbx_comp)
+ if (vha->hw->notify_dcbx_comp && !vha->vp_idx)
complete(&vha->hw->dcbx_comp);
}
break;
@@ -758,7 +794,7 @@ skip_rio:
ql_dbg(ql_dbg_async, vha, 0x500d,
"DCBX Completed -- %04x %04x %04x.\n",
mb[1], mb[2], mb[3]);
- if (ha->notify_dcbx_comp)
+ if (ha->notify_dcbx_comp && !vha->vp_idx)
complete(&ha->dcbx_comp);
} else
@@ -1032,7 +1068,7 @@ skip_rio:
}
}
case MBA_IDC_COMPLETE:
- if (ha->notify_lb_portup_comp)
+ if (ha->notify_lb_portup_comp && !vha->vp_idx)
complete(&ha->lb_portup_comp);
/* Fallthru */
case MBA_IDC_TIME_EXT:
@@ -1991,7 +2027,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
/* Fast path completion. */
if (comp_status == CS_COMPLETE && scsi_status == 0) {
- qla2x00_do_host_ramp_up(vha);
qla2x00_process_completed_request(vha, req, handle);
return;
@@ -2250,9 +2285,6 @@ out:
cp->cmnd, scsi_bufflen(cp), rsp_info_len,
resid_len, fw_resid_len);
- if (!res)
- qla2x00_do_host_ramp_up(vha);
-
if (rsp->status_srb == NULL)
sp->done(ha, sp, res);
}
@@ -2575,6 +2607,8 @@ qla24xx_intr_handler(int irq, void *dev_id)
vha = pci_get_drvdata(ha->pdev);
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->host_status);
+ if (qla2x00_check_reg_for_disconnect(vha, stat))
+ break;
if (stat & HSRX_RISC_PAUSED) {
if (unlikely(pci_channel_offline(ha->pdev)))
break;
@@ -2644,6 +2678,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
struct device_reg_24xx __iomem *reg;
struct scsi_qla_host *vha;
unsigned long flags;
+ uint32_t stat = 0;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2657,11 +2692,19 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
+ /*
+ * Use host_status register to check to PCI disconnection before we
+ * we process the response queue.
+ */
+ stat = RD_REG_DWORD(&reg->host_status);
+ if (qla2x00_check_reg_for_disconnect(vha, stat))
+ goto out;
qla24xx_process_response_queue(vha, rsp);
if (!ha->flags.disable_msix_handshake) {
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD_RELAXED(&reg->hccr);
}
+out:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return IRQ_HANDLED;
@@ -2671,9 +2714,11 @@ static irqreturn_t
qla25xx_msix_rsp_q(int irq, void *dev_id)
{
struct qla_hw_data *ha;
+ scsi_qla_host_t *vha;
struct rsp_que *rsp;
struct device_reg_24xx __iomem *reg;
unsigned long flags;
+ uint32_t hccr = 0;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2682,17 +2727,21 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
return IRQ_NONE;
}
ha = rsp->hw;
+ vha = pci_get_drvdata(ha->pdev);
/* Clear the interrupt, if enabled, for this response queue */
if (!ha->flags.disable_msix_handshake) {
reg = &ha->iobase->isp24;
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD_RELAXED(&reg->hccr);
+ hccr = RD_REG_DWORD_RELAXED(&reg->hccr);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+ if (qla2x00_check_reg_for_disconnect(vha, hccr))
+ goto out;
queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
+out:
return IRQ_HANDLED;
}
@@ -2723,6 +2772,8 @@ qla24xx_msix_default(int irq, void *dev_id)
vha = pci_get_drvdata(ha->pdev);
do {
stat = RD_REG_DWORD(&reg->host_status);
+ if (qla2x00_check_reg_for_disconnect(vha, stat))
+ break;
if (stat & HSRX_RISC_PAUSED) {
if (unlikely(pci_channel_offline(ha->pdev)))
break;
@@ -2937,7 +2988,7 @@ msix_out:
int
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
{
- int ret;
+ int ret = QLA_FUNCTION_FAILED;
device_reg_t __iomem *reg = ha->iobase;
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
@@ -2971,10 +3022,12 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
ha->chip_revision, ha->fw_attributes);
goto clear_risc_ints;
}
- ql_log(ql_log_info, vha, 0x0037,
- "MSI-X Falling back-to MSI mode -%d.\n", ret);
+
skip_msix:
+ ql_log(ql_log_info, vha, 0x0037,
+ "Falling back-to MSI mode -%d.\n", ret);
+
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
!IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha))
goto skip_msi;
@@ -2986,14 +3039,13 @@ skip_msix:
ha->flags.msi_enabled = 1;
} else
ql_log(ql_log_warn, vha, 0x0039,
- "MSI-X; Falling back-to INTa mode -- %d.\n", ret);
+ "Falling back-to INTa mode -- %d.\n", ret);
+skip_msi:
/* Skip INTx on ISP82xx. */
if (!ha->flags.msi_enabled && IS_QLA82XX(ha))
return QLA_FUNCTION_FAILED;
-skip_msi:
-
ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
ha->flags.msi_enabled ? 0 : IRQF_SHARED,
QLA2XXX_DRIVER_NAME, rsp);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index a9aae500e791..b94511ae0051 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -468,7 +468,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
- if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) {
+ if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) {
struct nvram_81xx *nv = ha->nvram;
mcp->mb[4] = (nv->enhanced_features &
EXTENDED_BB_CREDITS);
@@ -1214,7 +1214,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- if ((IS_QLA81XX(ha) || IS_QLA83XX(ha)) && ha->ex_init_cb->ex_version) {
+ if (ha->ex_init_cb && ha->ex_init_cb->ex_version) {
mcp->mb[1] = BIT_0;
mcp->mb[10] = MSW(ha->ex_init_cb_dma);
mcp->mb[11] = LSW(ha->ex_init_cb_dma);
@@ -2800,6 +2800,75 @@ qla2x00_system_error(scsi_qla_host_t *vha)
return rval;
}
+int
+qla2x00_write_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t data)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA2031(vha->hw))
+ return QLA_FUNCTION_FAILED;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1182,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_WRITE_SERDES;
+ mcp->mb[1] = addr;
+ mcp->mb[2] = data & 0xff;
+ mcp->mb[3] = 0;
+ mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1183,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1184,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+int
+qla2x00_read_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t *data)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA2031(vha->hw))
+ return QLA_FUNCTION_FAILED;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1185,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_READ_SERDES;
+ mcp->mb[1] = addr;
+ mcp->mb[3] = 0;
+ mcp->out_mb = MBX_3|MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ *data = mcp->mb[1] & 0xff;
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1186,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1187,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
/**
* qla2x00_set_serdes_params() -
* @ha: HA context
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index 30d20e74e48a..ba6f8b139c98 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -1610,6 +1610,22 @@ qlafx00_timer_routine(scsi_qla_host_t *vha)
ha->mr.fw_critemp_timer_tick--;
}
}
+ if (ha->mr.host_info_resend) {
+ /*
+ * Incomplete host info might be sent to firmware
+ * durinng system boot - info should be resend
+ */
+ if (ha->mr.hinfo_resend_timer_tick == 0) {
+ ha->mr.host_info_resend = false;
+ set_bit(FX00_HOST_INFO_RESEND, &vha->dpc_flags);
+ ha->mr.hinfo_resend_timer_tick =
+ QLAFX00_HINFO_RESEND_INTERVAL;
+ qla2xxx_wake_dpc(vha);
+ } else {
+ ha->mr.hinfo_resend_timer_tick--;
+ }
+ }
+
}
/*
@@ -1867,6 +1883,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
goto done_free_sp;
}
break;
+ case FXDISC_ABORT_IOCTL:
default:
break;
}
@@ -1888,6 +1905,8 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
p_sysid->sysname, SYSNAME_LENGTH);
strncpy(phost_info->nodename,
p_sysid->nodename, NODENAME_LENGTH);
+ if (!strcmp(phost_info->nodename, "(none)"))
+ ha->mr.host_info_resend = true;
strncpy(phost_info->release,
p_sysid->release, RELEASE_LENGTH);
strncpy(phost_info->version,
@@ -1948,8 +1967,8 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
if (fx_type == FXDISC_GET_CONFIG_INFO) {
struct config_info_data *pinfo =
(struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
- memcpy(&vha->hw->mr.product_name, pinfo->product_name,
- sizeof(vha->hw->mr.product_name));
+ strcpy(vha->hw->model_number, pinfo->model_num);
+ strcpy(vha->hw->model_desc, pinfo->model_description);
memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
sizeof(vha->hw->mr.symbolic_name));
memcpy(&vha->hw->mr.serial_num, pinfo->serial_num,
@@ -1993,7 +2012,11 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146,
(uint8_t *)pinfo, 16);
memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
- }
+ } else if (fx_type == FXDISC_ABORT_IOCTL)
+ fdisc->u.fxiocb.result =
+ (fdisc->u.fxiocb.result == cpu_to_le32(0x68)) ?
+ cpu_to_le32(QLA_SUCCESS) : cpu_to_le32(QLA_FUNCTION_FAILED);
+
rval = le32_to_cpu(fdisc->u.fxiocb.result);
done_unmap_dma:
@@ -2092,6 +2115,10 @@ qlafx00_abort_command(srb_t *sp)
/* Command not found. */
return QLA_FUNCTION_FAILED;
}
+ if (sp->type == SRB_FXIOCB_DCMD)
+ return qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
+ FXDISC_ABORT_IOCTL);
+
return qlafx00_async_abt_cmd(sp);
}
@@ -2419,7 +2446,6 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
/* Fast path completion. */
if (comp_status == CS_COMPLETE && scsi_status == 0) {
- qla2x00_do_host_ramp_up(vha);
qla2x00_process_completed_request(vha, req, handle);
return;
}
@@ -2630,9 +2656,6 @@ check_scsi_status:
rsp_info_len, resid_len, fw_resid_len, sense_len,
par_sense_len, rsp_info_len);
- if (!res)
- qla2x00_do_host_ramp_up(vha);
-
if (rsp->status_srb == NULL)
sp->done(ha, sp, res);
}
@@ -3021,6 +3044,8 @@ qlafx00_intr_handler(int irq, void *dev_id)
vha = pci_get_drvdata(ha->pdev);
for (iter = 50; iter--; clr_intr = 0) {
stat = QLAFX00_RD_INTR_REG(ha);
+ if (qla2x00_check_reg_for_disconnect(vha, stat))
+ break;
if ((stat & QLAFX00_HST_INT_STS_BITS) == 0)
break;
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index 79a93c52baec..6cd7072cc0ff 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -304,7 +304,9 @@ struct register_host_info {
#define QLAFX00_TGT_NODE_LIST_SIZE (sizeof(uint32_t) * 32)
struct config_info_data {
- uint8_t product_name[256];
+ uint8_t model_num[16];
+ uint8_t model_description[80];
+ uint8_t reserved0[160];
uint8_t symbolic_name[64];
uint8_t serial_num[32];
uint8_t hw_version[16];
@@ -343,6 +345,7 @@ struct config_info_data {
#define FXDISC_GET_TGT_NODE_INFO 0x80
#define FXDISC_GET_TGT_NODE_LIST 0x81
#define FXDISC_REG_HOST_INFO 0x99
+#define FXDISC_ABORT_IOCTL 0xff
#define QLAFX00_HBA_ICNTRL_REG 0x20B08
#define QLAFX00_ICR_ENB_MASK 0x80000000
@@ -490,7 +493,6 @@ struct qla_mt_iocb_rsp_fx00 {
#define FX00_DEF_RATOV 10
struct mr_data_fx00 {
- uint8_t product_name[256];
uint8_t symbolic_name[64];
uint8_t serial_num[32];
uint8_t hw_version[16];
@@ -511,6 +513,8 @@ struct mr_data_fx00 {
uint32_t old_aenmbx0_state;
uint32_t critical_temperature;
bool extended_io_enabled;
+ bool host_info_resend;
+ uint8_t hinfo_resend_timer_tick;
};
#define QLAFX00_EXTENDED_IO_EN_MASK 0x20
@@ -537,7 +541,11 @@ struct mr_data_fx00 {
#define QLAFX00_RESET_INTERVAL 120 /* number of seconds */
#define QLAFX00_MAX_RESET_INTERVAL 600 /* number of seconds */
#define QLAFX00_CRITEMP_INTERVAL 60 /* number of seconds */
+#define QLAFX00_HINFO_RESEND_INTERVAL 60 /* number of seconds */
#define QLAFX00_CRITEMP_THRSHLD 80 /* Celsius degrees */
+/* Max conncurrent IOs that can be queued */
+#define QLAFX00_MAX_CANQUEUE 1024
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 11ce53dcbe7e..1e6ba4a369e2 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2096,6 +2096,7 @@ qla82xx_msix_default(int irq, void *dev_id)
int status = 0;
unsigned long flags;
uint32_t stat = 0;
+ uint32_t host_int = 0;
uint16_t mb[4];
rsp = (struct rsp_que *) dev_id;
@@ -2111,7 +2112,10 @@ qla82xx_msix_default(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
do {
- if (RD_REG_DWORD(&reg->host_int)) {
+ host_int = RD_REG_DWORD(&reg->host_int);
+ if (qla2x00_check_reg_for_disconnect(vha, host_int))
+ break;
+ if (host_int) {
stat = RD_REG_DWORD(&reg->host_status);
switch (stat & 0xff) {
@@ -2156,6 +2160,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
struct rsp_que *rsp;
struct device_reg_82xx __iomem *reg;
unsigned long flags;
+ uint32_t host_int = 0;
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2168,8 +2173,12 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
reg = &ha->iobase->isp82;
spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
+ host_int = RD_REG_DWORD(&reg->host_int);
+ if (qla2x00_check_reg_for_disconnect(vha, host_int))
+ goto out;
qla24xx_process_response_queue(vha, rsp);
WRT_REG_DWORD(&reg->host_int, 0);
+out:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return IRQ_HANDLED;
}
@@ -2183,6 +2192,7 @@ qla82xx_poll(int irq, void *dev_id)
struct device_reg_82xx __iomem *reg;
int status = 0;
uint32_t stat;
+ uint32_t host_int = 0;
uint16_t mb[4];
unsigned long flags;
@@ -2198,7 +2208,10 @@ qla82xx_poll(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags);
vha = pci_get_drvdata(ha->pdev);
- if (RD_REG_DWORD(&reg->host_int)) {
+ host_int = RD_REG_DWORD(&reg->host_int);
+ if (qla2x00_check_reg_for_disconnect(vha, host_int))
+ goto out;
+ if (host_int) {
stat = RD_REG_DWORD(&reg->host_status);
switch (stat & 0xff) {
case 0x1:
@@ -2224,8 +2237,9 @@ qla82xx_poll(int irq, void *dev_id)
stat * 0xff);
break;
}
+ WRT_REG_DWORD(&reg->host_int, 0);
}
- WRT_REG_DWORD(&reg->host_int, 0);
+out:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
@@ -3003,7 +3017,7 @@ qla8xxx_dev_failed_handler(scsi_qla_host_t *vha)
qla82xx_clear_drv_active(ha);
qla82xx_idc_unlock(ha);
} else if (IS_QLA8044(ha)) {
- qla8044_clear_drv_active(vha);
+ qla8044_clear_drv_active(ha);
qla8044_idc_unlock(ha);
}
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index 8164cc9e7286..b45f4d78ee36 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -1257,10 +1257,10 @@ exit_start_fw:
}
void
-qla8044_clear_drv_active(struct scsi_qla_host *vha)
+qla8044_clear_drv_active(struct qla_hw_data *ha)
{
uint32_t drv_active;
- struct qla_hw_data *ha = vha->hw;
+ struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
drv_active &= ~(1 << (ha->portnum));
@@ -1324,7 +1324,7 @@ qla8044_device_bootstrap(struct scsi_qla_host *vha)
if (rval != QLA_SUCCESS) {
ql_log(ql_log_info, vha, 0xb0b3,
"%s: HW State: FAILED\n", __func__);
- qla8044_clear_drv_active(vha);
+ qla8044_clear_drv_active(ha);
qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
QLA8XXX_DEV_FAILED);
return rval;
@@ -1555,6 +1555,15 @@ qla8044_need_reset_handler(struct scsi_qla_host *vha)
qla8044_idc_lock(ha);
}
+ drv_state = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_STATE_INDEX);
+ drv_active = qla8044_rd_direct(vha,
+ QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+ ql_log(ql_log_info, vha, 0xb0c5,
+ "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
+ __func__, vha->host_no, drv_state, drv_active);
+
if (!ha->flags.nic_core_reset_owner) {
ql_dbg(ql_dbg_p3p, vha, 0xb0c3,
"%s(%ld): reset acknowledged\n",
@@ -1580,23 +1589,15 @@ qla8044_need_reset_handler(struct scsi_qla_host *vha)
dev_state = qla8044_rd_direct(vha,
QLA8044_CRB_DEV_STATE_INDEX);
- } while (dev_state == QLA8XXX_DEV_NEED_RESET);
+ } while (((drv_state & drv_active) != drv_active) &&
+ (dev_state == QLA8XXX_DEV_NEED_RESET));
} else {
qla8044_set_rst_ready(vha);
/* wait for 10 seconds for reset ack from all functions */
reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
- drv_state = qla8044_rd_direct(vha,
- QLA8044_CRB_DRV_STATE_INDEX);
- drv_active = qla8044_rd_direct(vha,
- QLA8044_CRB_DRV_ACTIVE_INDEX);
-
- ql_log(ql_log_info, vha, 0xb0c5,
- "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
- __func__, vha->host_no, drv_state, drv_active);
-
- while (drv_state != drv_active) {
+ while ((drv_state & drv_active) != drv_active) {
if (time_after_eq(jiffies, reset_timeout)) {
ql_log(ql_log_info, vha, 0xb0c6,
"%s: RESET TIMEOUT!"
@@ -1736,7 +1737,7 @@ qla8044_update_idc_reg(struct scsi_qla_host *vha)
rval = qla8044_set_idc_ver(vha);
if (rval == QLA_FUNCTION_FAILED)
- qla8044_clear_drv_active(vha);
+ qla8044_clear_drv_active(ha);
qla8044_idc_unlock(ha);
exit_update_idc_reg:
@@ -1859,7 +1860,7 @@ qla8044_device_state_handler(struct scsi_qla_host *vha)
goto exit;
case QLA8XXX_DEV_COLD:
rval = qla8044_device_bootstrap(vha);
- goto exit;
+ break;
case QLA8XXX_DEV_INITIALIZING:
qla8044_idc_unlock(ha);
msleep(1000);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 52be35e0300c..89a53002b585 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -110,7 +110,8 @@ MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registrations. "
"0 - no FDMI. Default is 1 - perform FDMI.");
-int ql2xmaxqdepth = MAX_Q_DEPTH;
+#define MAX_Q_DEPTH 32
+static int ql2xmaxqdepth = MAX_Q_DEPTH;
module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to set for each LUN. "
@@ -728,10 +729,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
}
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
- if (!sp) {
- set_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags);
+ if (!sp)
goto qc24_host_busy;
- }
sp->u.scmd.cmd = cmd;
sp->type = SRB_SCSI_CMD;
@@ -744,7 +743,6 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3013,
"Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
- set_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags);
goto qc24_host_busy_free_sp;
}
@@ -1474,81 +1472,6 @@ qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
return tag_type;
}
-static void
-qla2x00_host_ramp_down_queuedepth(scsi_qla_host_t *vha)
-{
- scsi_qla_host_t *vp;
- struct Scsi_Host *shost;
- struct scsi_device *sdev;
- struct qla_hw_data *ha = vha->hw;
- unsigned long flags;
-
- ha->host_last_rampdown_time = jiffies;
-
- if (ha->cfg_lun_q_depth <= vha->host->cmd_per_lun)
- return;
-
- if ((ha->cfg_lun_q_depth / 2) < vha->host->cmd_per_lun)
- ha->cfg_lun_q_depth = vha->host->cmd_per_lun;
- else
- ha->cfg_lun_q_depth = ha->cfg_lun_q_depth / 2;
-
- /*
- * Geometrically ramp down the queue depth for all devices on this
- * adapter
- */
- spin_lock_irqsave(&ha->vport_slock, flags);
- list_for_each_entry(vp, &ha->vp_list, list) {
- shost = vp->host;
- shost_for_each_device(sdev, shost) {
- if (sdev->queue_depth > shost->cmd_per_lun) {
- if (sdev->queue_depth < ha->cfg_lun_q_depth)
- continue;
- ql_dbg(ql_dbg_io, vp, 0x3031,
- "%ld:%d:%d: Ramping down queue depth to %d",
- vp->host_no, sdev->id, sdev->lun,
- ha->cfg_lun_q_depth);
- qla2x00_change_queue_depth(sdev,
- ha->cfg_lun_q_depth, SCSI_QDEPTH_DEFAULT);
- }
- }
- }
- spin_unlock_irqrestore(&ha->vport_slock, flags);
-
- return;
-}
-
-static void
-qla2x00_host_ramp_up_queuedepth(scsi_qla_host_t *vha)
-{
- scsi_qla_host_t *vp;
- struct Scsi_Host *shost;
- struct scsi_device *sdev;
- struct qla_hw_data *ha = vha->hw;
- unsigned long flags;
-
- ha->host_last_rampup_time = jiffies;
- ha->cfg_lun_q_depth++;
-
- /*
- * Linearly ramp up the queue depth for all devices on this
- * adapter
- */
- spin_lock_irqsave(&ha->vport_slock, flags);
- list_for_each_entry(vp, &ha->vp_list, list) {
- shost = vp->host;
- shost_for_each_device(sdev, shost) {
- if (sdev->queue_depth > ha->cfg_lun_q_depth)
- continue;
- qla2x00_change_queue_depth(sdev, ha->cfg_lun_q_depth,
- SCSI_QDEPTH_RAMP_UP);
- }
- }
- spin_unlock_irqrestore(&ha->vport_slock, flags);
-
- return;
-}
-
/**
* qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
* @ha: HA context
@@ -2424,7 +2347,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->init_cb_size = sizeof(init_cb_t);
ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
- ha->cfg_lun_q_depth = ql2xmaxqdepth;
/* Assign ISP specific operations. */
if (IS_QLA2100(ha)) {
@@ -2573,6 +2495,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
ha->mr.fw_critemp_timer_tick = QLAFX00_CRITEMP_INTERVAL;
ha->mr.fw_hbt_en = 1;
+ ha->mr.host_info_resend = false;
+ ha->mr.hinfo_resend_timer_tick = QLAFX00_HINFO_RESEND_INTERVAL;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -2638,7 +2562,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host = base_vha->host;
base_vha->req = req;
if (IS_QLAFX00(ha))
- host->can_queue = 1024;
+ host->can_queue = QLAFX00_MAX_CANQUEUE;
else
host->can_queue = req->length + 128;
if (IS_QLA2XXX_MIDTYPE(ha))
@@ -2816,6 +2740,8 @@ que_init:
*/
qla2xxx_wake_dpc(base_vha);
+ INIT_WORK(&ha->board_disable, qla2x00_disable_board_on_pci_error);
+
if (IS_QLA8031(ha) || IS_MCTP_CAPABLE(ha)) {
sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no);
ha->dpc_lp_wq = create_singlethread_workqueue(wq_name);
@@ -2955,7 +2881,7 @@ probe_hw_failed:
}
if (IS_QLA8044(ha)) {
qla8044_idc_lock(ha);
- qla8044_clear_drv_active(base_vha);
+ qla8044_clear_drv_active(ha);
qla8044_idc_unlock(ha);
}
iospace_config_failed:
@@ -2980,22 +2906,6 @@ probe_out:
}
static void
-qla2x00_stop_dpc_thread(scsi_qla_host_t *vha)
-{
- struct qla_hw_data *ha = vha->hw;
- struct task_struct *t = ha->dpc_thread;
-
- if (ha->dpc_thread == NULL)
- return;
- /*
- * qla2xxx_wake_dpc checks for ->dpc_thread
- * so we need to zero it out.
- */
- ha->dpc_thread = NULL;
- kthread_stop(t);
-}
-
-static void
qla2x00_shutdown(struct pci_dev *pdev)
{
scsi_qla_host_t *vha;
@@ -3038,29 +2948,14 @@ qla2x00_shutdown(struct pci_dev *pdev)
qla2x00_free_fw_dump(ha);
}
+/* Deletes all the virtual ports for a given ha */
static void
-qla2x00_remove_one(struct pci_dev *pdev)
+qla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha)
{
- scsi_qla_host_t *base_vha, *vha;
- struct qla_hw_data *ha;
+ struct Scsi_Host *scsi_host;
+ scsi_qla_host_t *vha;
unsigned long flags;
- /*
- * If the PCI device is disabled that means that probe failed and any
- * resources should be have cleaned up on probe exit.
- */
- if (!atomic_read(&pdev->enable_cnt))
- return;
-
- base_vha = pci_get_drvdata(pdev);
- ha = base_vha->hw;
-
- ha->flags.host_shutting_down = 1;
-
- set_bit(UNLOADING, &base_vha->dpc_flags);
- if (IS_QLAFX00(ha))
- qlafx00_driver_shutdown(base_vha, 20);
-
mutex_lock(&ha->vport_lock);
while (ha->cur_vport_count) {
spin_lock_irqsave(&ha->vport_slock, flags);
@@ -3068,7 +2963,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
BUG_ON(base_vha->list.next == &ha->vp_list);
/* This assumes first entry in ha->vp_list is always base vha */
vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list);
- scsi_host_get(vha->host);
+ scsi_host = scsi_host_get(vha->host);
spin_unlock_irqrestore(&ha->vport_slock, flags);
mutex_unlock(&ha->vport_lock);
@@ -3079,27 +2974,12 @@ qla2x00_remove_one(struct pci_dev *pdev)
mutex_lock(&ha->vport_lock);
}
mutex_unlock(&ha->vport_lock);
+}
- if (IS_QLA8031(ha)) {
- ql_dbg(ql_dbg_p3p, base_vha, 0xb07e,
- "Clearing fcoe driver presence.\n");
- if (qla83xx_clear_drv_presence(base_vha) != QLA_SUCCESS)
- ql_dbg(ql_dbg_p3p, base_vha, 0xb079,
- "Error while clearing DRV-Presence.\n");
- }
-
- qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
-
- qla2x00_dfs_remove(base_vha);
-
- qla84xx_put_chip(base_vha);
-
- /* Disable timer */
- if (base_vha->timer_active)
- qla2x00_stop_timer(base_vha);
-
- base_vha->flags.online = 0;
-
+/* Stops all deferred work threads */
+static void
+qla2x00_destroy_deferred_work(struct qla_hw_data *ha)
+{
/* Flush the work queue and remove it */
if (ha->wq) {
flush_workqueue(ha->wq);
@@ -3133,27 +3013,12 @@ qla2x00_remove_one(struct pci_dev *pdev)
ha->dpc_thread = NULL;
kthread_stop(t);
}
- qlt_remove_target(ha, base_vha);
-
- qla2x00_free_sysfs_attr(base_vha);
-
- fc_remove_host(base_vha->host);
-
- scsi_remove_host(base_vha->host);
-
- qla2x00_free_device(base_vha);
-
- scsi_host_put(base_vha->host);
+}
- if (IS_QLA8044(ha)) {
- qla8044_idc_lock(ha);
- qla8044_clear_drv_active(base_vha);
- qla8044_idc_unlock(ha);
- }
+static void
+qla2x00_unmap_iobases(struct qla_hw_data *ha)
+{
if (IS_QLA82XX(ha)) {
- qla82xx_idc_lock(ha);
- qla82xx_clear_drv_active(ha);
- qla82xx_idc_unlock(ha);
iounmap((device_reg_t __iomem *)ha->nx_pcibase);
if (!ql2xdbwr)
@@ -3171,6 +3036,84 @@ qla2x00_remove_one(struct pci_dev *pdev)
if (IS_QLA83XX(ha) && ha->msixbase)
iounmap(ha->msixbase);
}
+}
+
+static void
+qla2x00_clear_drv_active(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (IS_QLA8044(ha)) {
+ qla8044_idc_lock(ha);
+ qla8044_clear_drv_active(ha);
+ qla8044_idc_unlock(ha);
+ } else if (IS_QLA82XX(ha)) {
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_drv_active(ha);
+ qla82xx_idc_unlock(ha);
+ }
+}
+
+static void
+qla2x00_remove_one(struct pci_dev *pdev)
+{
+ scsi_qla_host_t *base_vha;
+ struct qla_hw_data *ha;
+
+ /*
+ * If the PCI device is disabled that means that probe failed and any
+ * resources should be have cleaned up on probe exit.
+ */
+ if (!atomic_read(&pdev->enable_cnt))
+ return;
+
+ base_vha = pci_get_drvdata(pdev);
+ ha = base_vha->hw;
+
+ set_bit(UNLOADING, &base_vha->dpc_flags);
+
+ if (IS_QLAFX00(ha))
+ qlafx00_driver_shutdown(base_vha, 20);
+
+ qla2x00_delete_all_vps(ha, base_vha);
+
+ if (IS_QLA8031(ha)) {
+ ql_dbg(ql_dbg_p3p, base_vha, 0xb07e,
+ "Clearing fcoe driver presence.\n");
+ if (qla83xx_clear_drv_presence(base_vha) != QLA_SUCCESS)
+ ql_dbg(ql_dbg_p3p, base_vha, 0xb079,
+ "Error while clearing DRV-Presence.\n");
+ }
+
+ qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
+
+ qla2x00_dfs_remove(base_vha);
+
+ qla84xx_put_chip(base_vha);
+
+ /* Disable timer */
+ if (base_vha->timer_active)
+ qla2x00_stop_timer(base_vha);
+
+ base_vha->flags.online = 0;
+
+ qla2x00_destroy_deferred_work(ha);
+
+ qlt_remove_target(ha, base_vha);
+
+ qla2x00_free_sysfs_attr(base_vha, true);
+
+ fc_remove_host(base_vha->host);
+
+ scsi_remove_host(base_vha->host);
+
+ qla2x00_free_device(base_vha);
+
+ scsi_host_put(base_vha->host);
+
+ qla2x00_clear_drv_active(base_vha);
+
+ qla2x00_unmap_iobases(ha);
pci_release_selected_regions(ha->pdev, ha->bars);
kfree(ha);
@@ -3192,9 +3135,8 @@ qla2x00_free_device(scsi_qla_host_t *vha)
if (vha->timer_active)
qla2x00_stop_timer(vha);
- qla2x00_stop_dpc_thread(vha);
-
qla25xx_delete_queues(vha);
+
if (ha->flags.fce_enabled)
qla2x00_disable_fce_trace(vha, NULL, NULL);
@@ -4731,6 +4673,66 @@ exit:
return rval;
}
+void
+qla2x00_disable_board_on_pci_error(struct work_struct *work)
+{
+ struct qla_hw_data *ha = container_of(work, struct qla_hw_data,
+ board_disable);
+ struct pci_dev *pdev = ha->pdev;
+ scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+
+ ql_log(ql_log_warn, base_vha, 0x015b,
+ "Disabling adapter.\n");
+
+ set_bit(UNLOADING, &base_vha->dpc_flags);
+
+ qla2x00_delete_all_vps(ha, base_vha);
+
+ qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
+
+ qla2x00_dfs_remove(base_vha);
+
+ qla84xx_put_chip(base_vha);
+
+ if (base_vha->timer_active)
+ qla2x00_stop_timer(base_vha);
+
+ base_vha->flags.online = 0;
+
+ qla2x00_destroy_deferred_work(ha);
+
+ /*
+ * Do not try to stop beacon blink as it will issue a mailbox
+ * command.
+ */
+ qla2x00_free_sysfs_attr(base_vha, false);
+
+ fc_remove_host(base_vha->host);
+
+ scsi_remove_host(base_vha->host);
+
+ base_vha->flags.init_done = 0;
+ qla25xx_delete_queues(base_vha);
+ qla2x00_free_irqs(base_vha);
+ qla2x00_free_fcports(base_vha);
+ qla2x00_mem_free(ha);
+ qla82xx_md_free(base_vha);
+ qla2x00_free_queues(ha);
+
+ scsi_host_put(base_vha->host);
+
+ qla2x00_unmap_iobases(ha);
+
+ pci_release_selected_regions(ha->pdev, ha->bars);
+ kfree(ha);
+ ha = NULL;
+
+ pci_disable_pcie_error_reporting(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+}
+
/**************************************************************************
* qla2x00_do_dpc
* This kernel thread is a task that is schedule by the interrupt handler
@@ -4863,6 +4865,14 @@ qla2x00_do_dpc(void *data)
ql_dbg(ql_dbg_dpc, base_vha, 0x401f,
"ISPFx00 Target Scan End\n");
}
+ if (test_and_clear_bit(FX00_HOST_INFO_RESEND,
+ &base_vha->dpc_flags)) {
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4023,
+ "ISPFx00 Host Info resend scheduled\n");
+ qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport,
+ FXDISC_REG_HOST_INFO);
+ }
}
if (test_and_clear_bit(ISP_ABORT_NEEDED,
@@ -4990,17 +5000,6 @@ loop_resync_check:
qla2xxx_flash_npiv_conf(base_vha);
}
- if (test_and_clear_bit(HOST_RAMP_DOWN_QUEUE_DEPTH,
- &base_vha->dpc_flags)) {
- /* Prevents simultaneous ramp up and down */
- clear_bit(HOST_RAMP_UP_QUEUE_DEPTH,
- &base_vha->dpc_flags);
- qla2x00_host_ramp_down_queuedepth(base_vha);
- }
-
- if (test_and_clear_bit(HOST_RAMP_UP_QUEUE_DEPTH,
- &base_vha->dpc_flags))
- qla2x00_host_ramp_up_queuedepth(base_vha);
intr_on_check:
if (!ha->interrupts_on)
ha->isp_ops->enable_intrs(ha);
@@ -5095,9 +5094,20 @@ qla2x00_timer(scsi_qla_host_t *vha)
return;
}
- /* Hardware read to raise pending EEH errors during mailbox waits. */
- if (!pci_channel_offline(ha->pdev))
+ /*
+ * Hardware read to raise pending EEH errors during mailbox waits. If
+ * the read returns -1 then disable the board.
+ */
+ if (!pci_channel_offline(ha->pdev)) {
pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
+ if (w == 0xffff)
+ /*
+ * Schedule this on the default system workqueue so that
+ * all the adapter workqueues and the DPC thread can be
+ * shutdown cleanly.
+ */
+ schedule_work(&ha->board_disable);
+ }
/* Make sure qla82xx_watchdog is run only for physical port */
if (!vha->vp_idx && IS_P3P_TYPE(ha)) {
@@ -5182,7 +5192,6 @@ qla2x00_timer(scsi_qla_host_t *vha)
"Loop down - seconds remaining %d.\n",
atomic_read(&vha->loop_down_timer));
}
-
/* Check if beacon LED needs to be blinked for physical host only */
if (!vha->vp_idx && (ha->beacon_blink_led == 1)) {
/* There is no beacon_blink function for ISP82xx */
@@ -5206,9 +5215,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) ||
test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||
- test_bit(RELOGIN_NEEDED, &vha->dpc_flags) ||
- test_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags) ||
- test_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags))) {
+ test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) {
ql_dbg(ql_dbg_timer, vha, 0x600b,
"isp_abort_needed=%d loop_resync_needed=%d "
"fcport_update_needed=%d start_dpc=%d "
@@ -5221,15 +5228,12 @@ qla2x00_timer(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_timer, vha, 0x600c,
"beacon_blink_needed=%d isp_unrecoverable=%d "
"fcoe_ctx_reset_needed=%d vp_dpc_needed=%d "
- "relogin_needed=%d, host_ramp_down_needed=%d "
- "host_ramp_up_needed=%d.\n",
+ "relogin_needed=%d.\n",
test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags),
test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags),
test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags),
test_bit(VP_DPC_NEEDED, &vha->dpc_flags),
- test_bit(RELOGIN_NEEDED, &vha->dpc_flags),
- test_bit(HOST_RAMP_UP_QUEUE_DEPTH, &vha->dpc_flags),
- test_bit(HOST_RAMP_DOWN_QUEUE_DEPTH, &vha->dpc_flags));
+ test_bit(RELOGIN_NEEDED, &vha->dpc_flags));
qla2xxx_wake_dpc(vha);
}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index a808e293dae0..31d19535b015 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.06.00.08-k"
+#define QLA2XXX_VERSION "8.06.00.12-k"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 6