scsi: qla2xxx: Fix oops in qla2x00_probe_one error path
[sfrench/cifs-2.6.git] / drivers / scsi / qla2xxx / qla_os.c
index df57655779edc0f047f65299bba126272567a224..dce42a416876573087e497c9cf7242e267b04b4d 100644 (file)
@@ -113,12 +113,12 @@ MODULE_PARM_DESC(ql2xfdmienable,
                "Enables FDMI registrations. "
                "0 - no FDMI. Default is 1 - perform FDMI.");
 
-#define MAX_Q_DEPTH    32
+#define MAX_Q_DEPTH    64
 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. "
-               "Default is 32.");
+               "Default is 64.");
 
 #if (IS_ENABLED(CONFIG_NVME_FC))
 int ql2xenabledif;
@@ -200,7 +200,7 @@ MODULE_PARM_DESC(ql2xgffidenable,
                "Enables GFF_ID checks of port type. "
                "Default is 0 - Do not use GFF_ID information.");
 
-int ql2xasynctmfenable;
+int ql2xasynctmfenable = 1;
 module_param(ql2xasynctmfenable, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xasynctmfenable,
                "Enables issue of TM IOCBs asynchronously via IOCB mechanism"
@@ -262,6 +262,12 @@ MODULE_PARM_DESC(ql2xmvasynctoatio,
                "0 (Default). Do not move IOCBs"
                "1 - Move IOCBs.");
 
+int ql2xautodetectsfp = 1;
+module_param(ql2xautodetectsfp, int, 0444);
+MODULE_PARM_DESC(ql2xautodetectsfp,
+                "Detect SFP range and set appropriate distance.\n"
+                "1 (Default): Enable\n");
+
 /*
  * SCSI host template entry points
  */
@@ -379,6 +385,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
        ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0;
        ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q];
        INIT_LIST_HEAD(&ha->base_qpair->hints_list);
+       INIT_LIST_HEAD(&ha->base_qpair->nvme_done_list);
        ha->base_qpair->enable_class_2 = ql2xenableclass2;
        /* init qpair to this cpu. Will adjust at run time. */
        qla_cpu_update(rsp->qpair, smp_processor_id());
@@ -710,7 +717,7 @@ qla2x00_sp_free_dma(void *ptr)
        }
 
 end:
-       if ((sp->type != SRB_NVME_CMD) && (sp->type != SRB_NVME_LS)) {
+       if (sp->type != SRB_NVME_CMD && sp->type != SRB_NVME_LS) {
                CMD_SP(cmd) = NULL;
                qla2x00_rel_sp(sp);
        }
@@ -735,7 +742,7 @@ qla2x00_sp_compl(void *ptr, int res)
        if (!atomic_dec_and_test(&sp->ref_count))
                return;
 
-       qla2x00_sp_free_dma(sp);
+       sp->free(sp);
        cmd->scsi_done(cmd);
 }
 
@@ -807,7 +814,7 @@ qla2xxx_qpair_sp_compl(void *ptr, int res)
        if (!atomic_dec_and_test(&sp->ref_count))
                return;
 
-       qla2xxx_qpair_sp_free_dma(sp);
+       sp->free(sp);
        cmd->scsi_done(cmd);
 }
 
@@ -928,7 +935,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        return 0;
 
 qc24_host_busy_free_sp:
-       qla2x00_sp_free_dma(sp);
+       sp->free(sp);
 
 qc24_host_busy:
        return SCSI_MLQUEUE_HOST_BUSY;
@@ -1017,7 +1024,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
        return 0;
 
 qc24_host_busy_free_sp:
-       qla2xxx_qpair_sp_free_dma(sp);
+       sp->free(sp);
 
 qc24_host_busy:
        return SCSI_MLQUEUE_HOST_BUSY;
@@ -1134,7 +1141,7 @@ qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha)
 {
        qla2x00_mark_all_devices_lost(vha, 0);
 
-       wait_event(vha->fcport_waitQ, test_fcport_count(vha));
+       wait_event_timeout(vha->fcport_waitQ, test_fcport_count(vha), 10*HZ);
 }
 
 /*
@@ -1715,8 +1722,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
                        if (sp) {
                                req->outstanding_cmds[cnt] = NULL;
                                if (sp->cmd_type == TYPE_SRB) {
-                                       if ((sp->type == SRB_NVME_CMD) ||
-                                           (sp->type == SRB_NVME_LS)) {
+                                       if (sp->type == SRB_NVME_CMD ||
+                                           sp->type == SRB_NVME_LS) {
                                                sp_get(sp);
                                                spin_unlock_irqrestore(
                                                    &ha->hardware_lock, flags);
@@ -1725,6 +1732,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
                                                    &ha->hardware_lock, flags);
                                        } else if (GET_CMD_SP(sp) &&
                                            !ha->flags.eeh_busy &&
+                                           (!test_bit(ABORT_ISP_ACTIVE,
+                                               &vha->dpc_flags)) &&
                                            (sp->type == SRB_SCSI_CMD)) {
                                                /*
                                                 * Don't abort commands in
@@ -2751,6 +2760,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init(&ha->tgt.sess_lock);
        spin_lock_init(&ha->tgt.atio_lock);
 
+       atomic_set(&ha->nvme_active_aen_cnt, 0);
 
        /* Clear our data area */
        ha->bars = bars;
@@ -3051,6 +3061,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            host->max_cmd_len, host->max_channel, host->max_lun,
            host->transportt, sht->vendor_id);
 
+       INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn);
+
        /* Set up the irqs */
        ret = qla2x00_request_irqs(ha, rsp);
        if (ret)
@@ -3168,7 +3180,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ha->mqenable) {
                bool mq = false;
                bool startit = false;
-               ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
+               ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0);
 
                if (QLA_TGT_MODE_ENABLED()) {
                        mq = true;
@@ -3200,6 +3212,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ql_log(ql_log_fatal, base_vha, 0x00ed,
                    "Failed to start DPC thread.\n");
                ret = PTR_ERR(ha->dpc_thread);
+               ha->dpc_thread = NULL;
                goto probe_failed;
        }
        ql_dbg(ql_dbg_init, base_vha, 0x00ee,
@@ -3213,7 +3226,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
         */
        qla2xxx_wake_dpc(base_vha);
 
-       INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn);
        INIT_WORK(&ha->board_disable, qla2x00_disable_board_on_pci_error);
 
        if (IS_QLA8031(ha) || IS_MCTP_CAPABLE(ha)) {
@@ -3328,6 +3340,13 @@ skip_dpc:
        if (test_bit(UNLOADING, &base_vha->dpc_flags))
                return -ENODEV;
 
+       if (ha->flags.detected_lr_sfp) {
+               ql_log(ql_log_info, base_vha, 0xffff,
+                   "Reset chip to pick up LR SFP setting\n");
+               set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+               qla2xxx_wake_dpc(base_vha);
+       }
+
        return 0;
 
 probe_init_failed:
@@ -3383,12 +3402,22 @@ qla2x00_shutdown(struct pci_dev *pdev)
        scsi_qla_host_t *vha;
        struct qla_hw_data  *ha;
 
-       if (!atomic_read(&pdev->enable_cnt))
-               return;
-
        vha = pci_get_drvdata(pdev);
        ha = vha->hw;
 
+       ql_log(ql_log_info, vha, 0xfffa,
+               "Adapter shutdown\n");
+
+       /*
+        * Prevent future board_disable and wait
+        * until any pending board_disable has completed.
+        */
+       set_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags);
+       cancel_work_sync(&ha->board_disable);
+
+       if (!atomic_read(&pdev->enable_cnt))
+               return;
+
        /* Notify ISPFX00 firmware */
        if (IS_QLAFX00(ha))
                qlafx00_driver_shutdown(vha, 20);
@@ -3419,8 +3448,9 @@ qla2x00_shutdown(struct pci_dev *pdev)
 
        qla2x00_free_fw_dump(ha);
 
-       pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
+       ql_log(ql_log_info, vha, 0xfffe,
+               "Adapter shutdown successfully.\n");
 }
 
 /* Deletes all the virtual ports for a given ha */
@@ -4006,8 +4036,18 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                    "loop_id_map=%p.\n", ha->loop_id_map);
        }
 
+       ha->sfp_data = dma_alloc_coherent(&ha->pdev->dev,
+           SFP_DEV_SIZE, &ha->sfp_data_dma, GFP_KERNEL);
+       if (!ha->sfp_data) {
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
+                   "Unable to allocate memory for SFP read-data.\n");
+               goto fail_sfp_data;
+       }
+
        return 0;
 
+fail_sfp_data:
+       kfree(ha->loop_id_map);
 fail_loop_id_map:
        dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
 fail_async_pd:
@@ -4345,7 +4385,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
                ha->ct_sns, ha->ct_sns_dma);
 
        if (ha->sfp_data)
-               dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
+               dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data,
+                   ha->sfp_data_dma);
 
        if (ha->ms_iocb)
                dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
@@ -4638,9 +4679,10 @@ static
 void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
 {
        unsigned long flags;
-       fc_port_t *fcport =  NULL;
+       fc_port_t *fcport =  NULL, *tfcp;
        struct qlt_plogi_ack_t *pla =
            (struct qlt_plogi_ack_t *)e->u.new_sess.pla;
+       uint8_t free_fcport = 0;
 
        spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
        fcport = qla2x00_find_fcport_by_wwpn(vha, e->u.new_sess.port_name, 1);
@@ -4655,6 +4697,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                        pla->ref_count--;
                }
        } else {
+               spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
                fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
                if (fcport) {
                        fcport->d_id = e->u.new_sess.id;
@@ -4664,6 +4707,29 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
 
                        memcpy(fcport->port_name, e->u.new_sess.port_name,
                            WWN_SIZE);
+               } else {
+                       ql_dbg(ql_dbg_disc, vha, 0xffff,
+                                  "%s %8phC mem alloc fail.\n",
+                                  __func__, e->u.new_sess.port_name);
+
+                       if (pla)
+                               kmem_cache_free(qla_tgt_plogi_cachep, pla);
+                       return;
+               }
+
+               spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+               /* search again to make sure one else got ahead */
+               tfcp = qla2x00_find_fcport_by_wwpn(vha,
+                   e->u.new_sess.port_name, 1);
+               if (tfcp) {
+                       /* should rarily happen */
+                       ql_dbg(ql_dbg_disc, vha, 0xffff,
+                           "%s %8phC found existing fcport b4 add. DS %d LS %d\n",
+                           __func__, tfcp->port_name, tfcp->disc_state,
+                           tfcp->fw_login_state);
+
+                       free_fcport = 1;
+               } else {
                        list_add_tail(&fcport->list, &vha->vp_fcports);
 
                        if (pla) {
@@ -4681,6 +4747,12 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                else
                        qla24xx_async_gnl(vha, fcport);
        }
+
+       if (free_fcport) {
+               qla2x00_free_fcport(fcport);
+               if (pla)
+                       kmem_cache_free(qla_tgt_plogi_cachep, pla);
+       }
 }
 
 void
@@ -5493,6 +5565,13 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
        ql_log(ql_log_warn, base_vha, 0x015b,
            "Disabling adapter.\n");
 
+       if (!atomic_read(&pdev->enable_cnt)) {
+               ql_log(ql_log_info, base_vha, 0xfffc,
+                   "PCI device disabled, no action req for PCI error=%lx\n",
+                   base_vha->pci_flags);
+               return;
+       }
+
        qla2x00_wait_for_sess_deletion(base_vha);
 
        set_bit(UNLOADING, &base_vha->dpc_flags);
@@ -5687,6 +5766,16 @@ qla2x00_do_dpc(void *data)
                        }
                }
 
+               if (test_and_clear_bit(DETECT_SFP_CHANGE,
+                       &base_vha->dpc_flags) &&
+                   !test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) {
+                       qla24xx_detect_sfp(base_vha);
+
+                       if (ha->flags.detected_lr_sfp !=
+                           ha->flags.using_lr_setting)
+                               set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+               }
+
                if (test_and_clear_bit(ISP_ABORT_NEEDED,
                                                &base_vha->dpc_flags)) {
 
@@ -5828,6 +5917,17 @@ intr_on_check:
                        mutex_unlock(&ha->mq_lock);
                }
 
+               if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, &base_vha->dpc_flags)) {
+                       ql_log(ql_log_info, base_vha, 0xffffff,
+                               "nvme: SET ZIO Activity exchange threshold to %d.\n",
+                                               ha->nvme_last_rptd_aen);
+                       if (qla27xx_set_zio_threshold(base_vha, ha->nvme_last_rptd_aen)) {
+                               ql_log(ql_log_info, base_vha, 0xffffff,
+                                       "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n",
+                                               ha->nvme_last_rptd_aen);
+                       }
+               }
+
                if (!IS_QLAFX00(ha))
                        qla2x00_do_dpc_all_vps(base_vha);
 
@@ -6025,12 +6125,15 @@ qla2x00_timer(scsi_qla_host_t *vha)
         * FC-NVME
         * see if the active AEN count has changed from what was last reported.
         */
-       if (atomic_read(&vha->nvme_active_aen_cnt) != vha->nvme_last_rptd_aen) {
-               vha->nvme_last_rptd_aen =
-                   atomic_read(&vha->nvme_active_aen_cnt);
+       if (!vha->vp_idx &&
+               atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen &&
+               ha->zio_mode == QLA_ZIO_MODE_6) {
                ql_log(ql_log_info, vha, 0x3002,
-                   "reporting new aen count of %d to the fw\n",
-                   vha->nvme_last_rptd_aen);
+                       "nvme: Sched: Set ZIO exchange threshold to %d.\n",
+                       ha->nvme_last_rptd_aen);
+               ha->nvme_last_rptd_aen = atomic_read(&ha->nvme_active_aen_cnt);
+               set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags);
+               start_dpc++;
        }
 
        /* Schedule the DPC routine if needed */
@@ -6181,6 +6284,12 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
        ql_dbg(ql_dbg_aer, vha, 0x9000,
            "PCI error detected, state %x.\n", state);
 
+       if (!atomic_read(&pdev->enable_cnt)) {
+               ql_log(ql_log_info, vha, 0xffff,
+                       "PCI device is disabled,state %x\n", state);
+               return PCI_ERS_RESULT_NEED_RESET;
+       }
+
        switch (state) {
        case pci_channel_io_normal:
                ha->flags.eeh_busy = 0;
@@ -6574,6 +6683,8 @@ qla2x00_module_init(void)
        strcpy(qla2x00_version_str, QLA2XXX_VERSION);
        if (ql2xextended_error_logging)
                strcat(qla2x00_version_str, "-debug");
+       if (ql2xextended_error_logging == 1)
+               ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK;
 
        qla2xxx_transport_template =
            fc_attach_transport(&qla2xxx_transport_functions);