diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 258 |
1 files changed, 100 insertions, 158 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3ddfa889e949..efe29924e058 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -104,9 +104,7 @@ static int qla2xxx_slave_alloc(struct scsi_device *); static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time); static void qla2xxx_scan_start(struct Scsi_Host *); static void qla2xxx_slave_destroy(struct scsi_device *); -static int qla2x00_queuecommand(struct scsi_cmnd *cmd, - void (*fn)(struct scsi_cmnd *)); -static int qla24xx_queuecommand(struct scsi_cmnd *cmd, +static int qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)); static int qla2xxx_eh_abort(struct scsi_cmnd *); static int qla2xxx_eh_device_reset(struct scsi_cmnd *); @@ -117,42 +115,10 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *); static int qla2x00_change_queue_depth(struct scsi_device *, int); static int qla2x00_change_queue_type(struct scsi_device *, int); -static struct scsi_host_template qla2x00_driver_template = { +struct scsi_host_template qla2xxx_driver_template = { .module = THIS_MODULE, .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla2x00_queuecommand, - - .eh_abort_handler = qla2xxx_eh_abort, - .eh_device_reset_handler = qla2xxx_eh_device_reset, - .eh_target_reset_handler = qla2xxx_eh_target_reset, - .eh_bus_reset_handler = qla2xxx_eh_bus_reset, - .eh_host_reset_handler = qla2xxx_eh_host_reset, - - .slave_configure = qla2xxx_slave_configure, - - .slave_alloc = qla2xxx_slave_alloc, - .slave_destroy = qla2xxx_slave_destroy, - .scan_finished = qla2xxx_scan_finished, - .scan_start = qla2xxx_scan_start, - .change_queue_depth = qla2x00_change_queue_depth, - .change_queue_type = qla2x00_change_queue_type, - .this_id = -1, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, - - /* - * The RISC allows for each command to transfer (2^32-1) bytes of data, - * which equates to 0x800000 sectors. - */ - .max_sectors = 0xFFFF, - .shost_attrs = qla2x00_host_attrs, -}; - -struct scsi_host_template qla24xx_driver_template = { - .module = THIS_MODULE, - .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla24xx_queuecommand, + .queuecommand = qla2xxx_queuecommand, .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, @@ -430,73 +396,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, } static int -qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); - struct qla_hw_data *ha = vha->hw; - srb_t *sp; - int rval; - - if (unlikely(pci_channel_offline(ha->pdev))) { - cmd->result = DID_REQUEUE << 16; - goto qc_fail_command; - } - - rval = fc_remote_port_chkready(rport); - if (rval) { - cmd->result = rval; - goto qc_fail_command; - } - - /* Close window on fcport/rport state-transitioning. */ - if (fcport->drport) - goto qc_target_busy; - - if (atomic_read(&fcport->state) != FCS_ONLINE) { - if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&vha->loop_state) == LOOP_DEAD) { - cmd->result = DID_NO_CONNECT << 16; - goto qc_fail_command; - } - goto qc_target_busy; - } - - spin_unlock_irq(vha->host->host_lock); - - sp = qla2x00_get_new_sp(vha, fcport, cmd, done); - if (!sp) - goto qc_host_busy_lock; - - rval = ha->isp_ops->start_scsi(sp); - if (rval != QLA_SUCCESS) - goto qc_host_busy_free_sp; - - spin_lock_irq(vha->host->host_lock); - - return 0; - -qc_host_busy_free_sp: - qla2x00_sp_free_dma(sp); - mempool_free(sp, ha->srb_mempool); - -qc_host_busy_lock: - spin_lock_irq(vha->host->host_lock); - return SCSI_MLQUEUE_HOST_BUSY; - -qc_target_busy: - return SCSI_MLQUEUE_TARGET_BUSY; - -qc_fail_command: - done(cmd); - - return 0; -} - - -static int -qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -507,7 +407,10 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) int rval; if (unlikely(pci_channel_offline(ha->pdev))) { - cmd->result = DID_REQUEUE << 16; + if (ha->pdev->error_state == pci_channel_io_frozen) + cmd->result = DID_REQUEUE << 16; + else + cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } @@ -635,6 +538,34 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) return (return_status); } +int +qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) +{ + int return_status; + unsigned long wait_reset; + struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + + wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ); + while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || + test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || + ha->dpc_active) && time_before(jiffies, wait_reset)) { + + msleep(1000); + + if (!test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) && + ha->flags.chip_reset_done) + break; + } + if (ha->flags.chip_reset_done) + return_status = QLA_SUCCESS; + else + return_status = QLA_FUNCTION_FAILED; + + return return_status; +} + /* * qla2x00_wait_for_loop_ready * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop @@ -1163,7 +1094,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) continue; for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = req->outstanding_cmds[cnt]; - if (sp && sp->fcport->vha == vha) { + if (sp) { req->outstanding_cmds[cnt] = NULL; sp->cmd->result = res; qla2x00_sp_compl(ha, sp); @@ -1351,9 +1282,6 @@ static struct isp_operations qla2100_isp_ops = { .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, - .wrt_req_reg = NULL, - .wrt_rsp_reg = NULL, - .rd_req_reg = NULL, }; static struct isp_operations qla2300_isp_ops = { @@ -1389,9 +1317,6 @@ static struct isp_operations qla2300_isp_ops = { .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, - .wrt_req_reg = NULL, - .wrt_rsp_reg = NULL, - .rd_req_reg = NULL, }; static struct isp_operations qla24xx_isp_ops = { @@ -1427,9 +1352,6 @@ static struct isp_operations qla24xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, - .wrt_req_reg = qla24xx_wrt_req_reg, - .wrt_rsp_reg = qla24xx_wrt_rsp_reg, - .rd_req_reg = qla24xx_rd_req_reg, }; static struct isp_operations qla25xx_isp_ops = { @@ -1465,9 +1387,6 @@ static struct isp_operations qla25xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, - .wrt_req_reg = qla24xx_wrt_req_reg, - .wrt_rsp_reg = qla24xx_wrt_rsp_reg, - .rd_req_reg = qla24xx_rd_req_reg, }; static struct isp_operations qla81xx_isp_ops = { @@ -1493,8 +1412,8 @@ static struct isp_operations qla81xx_isp_ops = { .build_iocbs = NULL, .prep_ms_iocb = qla24xx_prep_ms_iocb, .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = qla25xx_read_nvram_data, - .write_nvram = qla25xx_write_nvram_data, + .read_nvram = NULL, + .write_nvram = NULL, .fw_dump = qla81xx_fw_dump, .beacon_on = qla24xx_beacon_on, .beacon_off = qla24xx_beacon_off, @@ -1503,9 +1422,6 @@ static struct isp_operations qla81xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, - .wrt_req_reg = qla24xx_wrt_req_reg, - .wrt_rsp_reg = qla24xx_wrt_rsp_reg, - .rd_req_reg = qla24xx_rd_req_reg, }; static inline void @@ -1727,7 +1643,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) struct rsp_que *rsp = NULL; bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); - sht = &qla2x00_driver_template; + sht = &qla2xxx_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || @@ -1736,7 +1652,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) { bars = pci_select_bars(pdev, IORESOURCE_MEM); - sht = &qla24xx_driver_template; mem_only = 1; } @@ -1927,10 +1842,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->rsp_q_map[0] = rsp; ha->req_q_map[0] = req; + /* FWI2-capable only. */ + req->req_q_in = &ha->iobase->isp24.req_q_in; + req->req_q_out = &ha->iobase->isp24.req_q_out; + rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in; + rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out; if (ha->mqenable) { - ha->isp_ops->wrt_req_reg = qla25xx_wrt_req_reg; - ha->isp_ops->wrt_rsp_reg = qla25xx_wrt_rsp_reg; - ha->isp_ops->rd_req_reg = qla25xx_rd_req_reg; + req->req_q_in = &ha->mqiobase->isp25mq.req_q_in; + req->req_q_out = &ha->mqiobase->isp25mq.req_q_out; + rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in; + rsp->rsp_q_out = &ha->mqiobase->isp25mq.rsp_q_out; } if (qla2x00_initialize_adapter(base_vha)) { @@ -2000,6 +1921,16 @@ probe_init_failed: ha->max_queues = 0; probe_failed: + if (base_vha->timer_active) + qla2x00_stop_timer(base_vha); + base_vha->flags.online = 0; + if (ha->dpc_thread) { + struct task_struct *t = ha->dpc_thread; + + ha->dpc_thread = NULL; + kthread_stop(t); + } + qla2x00_free_device(base_vha); scsi_host_put(base_vha->host); @@ -2033,10 +1964,30 @@ qla2x00_remove_one(struct pci_dev *pdev) set_bit(UNLOADING, &base_vha->dpc_flags); + 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; + + /* Kill the kernel thread for this host */ + if (ha->dpc_thread) { + struct task_struct *t = ha->dpc_thread; + + /* + * qla2xxx_wake_dpc checks for ->dpc_thread + * so we need to zero it out. + */ + ha->dpc_thread = NULL; + kthread_stop(t); + } + qla2x00_free_sysfs_attr(base_vha); fc_remove_host(base_vha->host); @@ -2065,25 +2016,6 @@ static void qla2x00_free_device(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; - qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); - - /* Disable timer */ - if (vha->timer_active) - qla2x00_stop_timer(vha); - - vha->flags.online = 0; - - /* Kill the kernel thread for this host */ - if (ha->dpc_thread) { - struct task_struct *t = ha->dpc_thread; - - /* - * qla2xxx_wake_dpc checks for ->dpc_thread - * so we need to zero it out. - */ - ha->dpc_thread = NULL; - kthread_stop(t); - } if (ha->flags.fce_enabled) qla2x00_disable_fce_trace(vha, NULL, NULL); @@ -2313,9 +2245,19 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, } else ha->npiv_info = NULL; + /* Get consistent memory allocated for EX-INIT-CB. */ + if (IS_QLA81XX(ha)) { + ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->ex_init_cb_dma); + if (!ha->ex_init_cb) + goto fail_ex_init_cb; + } + INIT_LIST_HEAD(&ha->vp_list); return 1; +fail_ex_init_cb: + kfree(ha->npiv_info); fail_npiv_info: dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) * sizeof(response_t), (*rsp)->ring, (*rsp)->dma); @@ -2398,18 +2340,22 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->sfp_data) dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); + if (ha->edc_data) + dma_pool_free(ha->s_dma_pool, ha->edc_data, ha->edc_data_dma); + if (ha->ms_iocb) dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); + if (ha->ex_init_cb) + dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); + if (ha->s_dma_pool) dma_pool_destroy(ha->s_dma_pool); - if (ha->gid_list) dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, ha->gid_list_dma); - if (ha->init_cb) dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); @@ -2428,6 +2374,8 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->ms_iocb_dma = 0; ha->init_cb = NULL; ha->init_cb_dma = 0; + ha->ex_init_cb = NULL; + ha->ex_init_cb_dma = 0; ha->s_dma_pool = NULL; @@ -2914,19 +2862,11 @@ qla2x00_timer(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags); } - set_bit(ABORT_QUEUES_NEEDED, &vha->dpc_flags); start_dpc++; } /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - " - "restarting queues.\n", - vha->host_no)); - - set_bit(RESTART_QUEUES_NEEDED, &vha->dpc_flags); - start_dpc++; - if (!(vha->device_flags & DFLG_NO_CABLE) && !vha->vp_idx) { DEBUG(printk("scsi(%ld): Loop down - " @@ -3053,6 +2993,8 @@ qla2x00_release_firmware(void) static pci_ers_result_t qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + switch (state) { case pci_channel_io_normal: return PCI_ERS_RESULT_CAN_RECOVER; @@ -3060,7 +3002,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) pci_disable_device(pdev); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: - qla2x00_remove_one(pdev); + qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); return PCI_ERS_RESULT_DISCONNECT; } return PCI_ERS_RESULT_NEED_RESET; |