summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_os.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c133
1 files changed, 87 insertions, 46 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index be9698d920c2..db3dbd999cb6 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -105,7 +105,7 @@ MODULE_PARM_DESC(ql2xshiftctondsd,
"based on total number of SG elements.");
int ql2xfdmienable=1;
-module_param(ql2xfdmienable, int, S_IRUGO);
+module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registrations. "
"0 - no FDMI. Default is 1 - perform FDMI.");
@@ -238,7 +238,9 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
static int qla2x00_change_queue_depth(struct scsi_device *, int, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
+static void qla2x00_clear_drv_active(struct qla_hw_data *);
static void qla2x00_free_device(scsi_qla_host_t *);
+static void qla83xx_disable_laser(scsi_qla_host_t *vha);
struct scsi_host_template qla2xxx_driver_template = {
.module = THIS_MODULE,
@@ -547,14 +549,13 @@ qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str)
}
static char *
-qla2x00_fw_version_str(struct scsi_qla_host *vha, char *str)
+qla2x00_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size)
{
char un_str[10];
struct qla_hw_data *ha = vha->hw;
- sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
- ha->fw_minor_version,
- ha->fw_subminor_version);
+ snprintf(str, size, "%d.%02d.%02d ", ha->fw_major_version,
+ ha->fw_minor_version, ha->fw_subminor_version);
if (ha->fw_attributes & BIT_9) {
strcat(str, "FLX");
@@ -586,11 +587,11 @@ qla2x00_fw_version_str(struct scsi_qla_host *vha, char *str)
}
static char *
-qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str)
+qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size)
{
struct qla_hw_data *ha = vha->hw;
- sprintf(str, "%d.%02d.%02d (%x)", ha->fw_major_version,
+ snprintf(str, size, "%d.%02d.%02d (%x)", ha->fw_major_version,
ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes);
return str;
}
@@ -730,6 +731,15 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
goto qc24_target_busy;
}
+ /*
+ * Return target busy if we've received a non-zero retry_delay_timer
+ * in a FCP_RSP.
+ */
+ if (time_after(jiffies, fcport->retry_delay_timestamp))
+ fcport->retry_delay_timestamp = 0;
+ else
+ goto qc24_target_busy;
+
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
if (!sp)
goto qc24_host_busy;
@@ -860,8 +870,10 @@ qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- while ((!(vha->flags.online) || ha->dpc_active ||
- ha->flags.mbox_busy))
+ while (((qla2x00_reset_active(vha)) || ha->dpc_active ||
+ ha->flags.mbox_busy) ||
+ test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
+ test_bit(FX00_TARGET_SCAN, &vha->dpc_flags))
msleep(1000);
}
@@ -1351,6 +1363,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
struct qla_hw_data *ha = vha->hw;
struct req_que *req;
+ qlt_host_reset_handler(ha);
+
spin_lock_irqsave(&ha->hardware_lock, flags);
for (que = 0; que < ha->max_req_queues; que++) {
req = ha->req_q_map[que];
@@ -2384,6 +2398,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
"Memory allocated for ha=%p.\n", ha);
ha->pdev = pdev;
ha->tgt.enable_class_2 = ql2xenableclass2;
+ INIT_LIST_HEAD(&ha->tgt.q_full_list);
+ spin_lock_init(&ha->tgt.q_full_lock);
/* Clear our data area */
ha->bars = bars;
@@ -2527,7 +2543,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->portnum = PCI_FUNC(ha->pdev->devfn);
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
- req_length = REQUEST_ENTRY_CNT_24XX;
+ req_length = REQUEST_ENTRY_CNT_83XX;
rsp_length = RESPONSE_ENTRY_CNT_2300;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
@@ -2631,6 +2647,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
pci_set_drvdata(pdev, base_vha);
+ set_bit(PFLG_DRIVER_PROBING, &base_vha->pci_flags);
host = base_vha->host;
base_vha->req = req;
@@ -2923,10 +2940,11 @@ skip_dpc:
pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info),
pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-',
base_vha->host_no,
- ha->isp_ops->fw_version_str(base_vha, fw_str));
+ ha->isp_ops->fw_version_str(base_vha, fw_str, sizeof(fw_str)));
qlt_add_target(ha, base_vha);
+ clear_bit(PFLG_DRIVER_PROBING, &base_vha->pci_flags);
return 0;
probe_init_failed:
@@ -2954,16 +2972,8 @@ probe_failed:
scsi_host_put(base_vha->host);
probe_hw_failed:
- if (IS_QLA82XX(ha)) {
- qla82xx_idc_lock(ha);
- qla82xx_clear_drv_active(ha);
- qla82xx_idc_unlock(ha);
- }
- if (IS_QLA8044(ha)) {
- qla8044_idc_lock(ha);
- qla8044_clear_drv_active(ha);
- qla8044_idc_unlock(ha);
- }
+ qla2x00_clear_drv_active(ha);
+
iospace_config_failed:
if (IS_P3P_TYPE(ha)) {
if (!ha->nx_pcibase)
@@ -3026,6 +3036,9 @@ qla2x00_shutdown(struct pci_dev *pdev)
qla2x00_free_irqs(vha);
qla2x00_free_fw_dump(ha);
+
+ pci_disable_pcie_error_reporting(pdev);
+ pci_disable_device(pdev);
}
/* Deletes all the virtual ports for a given ha */
@@ -3119,10 +3132,8 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha)
}
static void
-qla2x00_clear_drv_active(scsi_qla_host_t *vha)
+qla2x00_clear_drv_active(struct qla_hw_data *ha)
{
- struct qla_hw_data *ha = vha->hw;
-
if (IS_QLA8044(ha)) {
qla8044_idc_lock(ha);
qla8044_clear_drv_active(ha);
@@ -3140,15 +3151,25 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_qla_host_t *base_vha;
struct qla_hw_data *ha;
+ base_vha = pci_get_drvdata(pdev);
+ ha = base_vha->hw;
+
+ /* Indicate device removal to prevent future board_disable and wait
+ * until any pending board_disable has completed. */
+ set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags);
+ cancel_work_sync(&ha->board_disable);
+
/*
- * If the PCI device is disabled that means that probe failed and any
- * resources should be have cleaned up on probe exit.
+ * If the PCI device is disabled then there was a PCI-disconnect and
+ * qla2x00_disable_board_on_pci_error has taken care of most of the
+ * resources.
*/
- if (!atomic_read(&pdev->enable_cnt))
+ if (!atomic_read(&pdev->enable_cnt)) {
+ scsi_host_put(base_vha->host);
+ kfree(ha);
+ pci_set_drvdata(pdev, NULL);
return;
-
- base_vha = pci_get_drvdata(pdev);
- ha = base_vha->hw;
+ }
qla2x00_wait_for_hba_ready(base_vha);
@@ -3173,6 +3194,10 @@ qla2x00_remove_one(struct pci_dev *pdev)
qla84xx_put_chip(base_vha);
+ /* Laser should be disabled only for ISP2031 */
+ if (IS_QLA2031(ha))
+ qla83xx_disable_laser(base_vha);
+
/* Disable timer */
if (base_vha->timer_active)
qla2x00_stop_timer(base_vha);
@@ -3191,9 +3216,9 @@ qla2x00_remove_one(struct pci_dev *pdev)
qla2x00_free_device(base_vha);
- scsi_host_put(base_vha->host);
+ qla2x00_clear_drv_active(ha);
- qla2x00_clear_drv_active(base_vha);
+ scsi_host_put(base_vha->host);
qla2x00_unmap_iobases(ha);
@@ -4808,18 +4833,15 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
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);
+ /*
+ * Let qla2x00_remove_one cleanup qla_hw_data on device removal.
+ */
}
/**************************************************************************
@@ -4853,7 +4875,6 @@ qla2x00_do_dpc(void *data)
"DPC handler sleeping.\n");
schedule();
- __set_current_state(TASK_RUNNING);
if (!base_vha->flags.init_done || ha->flags.mbox_busy)
goto end_loop;
@@ -5192,13 +5213,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
*/
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);
+ qla2x00_check_reg16_for_disconnect(vha, w);
}
/* Make sure qla82xx_watchdog is run only for physical port */
@@ -5706,6 +5721,32 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
ha->flags.eeh_busy = 0;
}
+static void
+qla83xx_disable_laser(scsi_qla_host_t *vha)
+{
+ uint32_t reg, data, fn;
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_24xx __iomem *isp_reg = &ha->iobase->isp24;
+
+ /* pci func #/port # */
+ ql_dbg(ql_dbg_init, vha, 0x004b,
+ "Disabling Laser for hba: %p\n", vha);
+
+ fn = (RD_REG_DWORD(&isp_reg->ctrl_status) &
+ (BIT_15|BIT_14|BIT_13|BIT_12));
+
+ fn = (fn >> 12);
+
+ if (fn & 1)
+ reg = PORT_1_2031;
+ else
+ reg = PORT_0_2031;
+
+ data = LASER_OFF_2031;
+
+ qla83xx_wr_reg(vha, reg, data);
+}
+
static const struct pci_error_handlers qla2xxx_err_handler = {
.error_detected = qla2xxx_pci_error_detected,
.mmio_enabled = qla2xxx_pci_mmio_enabled,