diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 133 |
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, |