]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: mpi3mr: Prevent PCI writes from driver during PCI error recovery
authorSumit Saxena <sumit.saxena@broadcom.com>
Thu, 27 Jun 2024 10:17:34 +0000 (15:47 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 5 Jul 2024 03:37:07 +0000 (23:37 -0400)
Prevent interaction with the hardware while the error recovery in progress.

Co-developed-by: Sathya Prakash <sathya.prakash@broadcom.com>
Signed-off-by: Sathya Prakash <sathya.prakash@broadcom.com>
Co-developed-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
Link: https://lore.kernel.org/r/20240627101735.18286-3-sumit.saxena@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpi3mr/mpi3mr.h
drivers/scsi/mpi3mr/mpi3mr_app.c
drivers/scsi/mpi3mr/mpi3mr_fw.c
drivers/scsi/mpi3mr/mpi3mr_os.c
drivers/scsi/mpi3mr/mpi3mr_transport.c

index 2b1d5645ba9b2b81d4e6be5004d3b61317f83c16..e99bb8ec428c5b6eadb1c85379f301e37ded6f6a 100644 (file)
@@ -519,6 +519,7 @@ struct mpi3mr_throttle_group_info {
 
 /* HBA port flags */
 #define MPI3MR_HBA_PORT_FLAG_DIRTY     0x01
+#define MPI3MR_HBA_PORT_FLAG_NEW       0x02
 
 /* IOCTL data transfer sge*/
 #define MPI3MR_NUM_IOCTL_SGE           256
index f73f265c7921a48d224b42e9f663f2e705519821..c369f58fc93a1226a76f822046047e3ac2643980 100644 (file)
@@ -846,7 +846,7 @@ static int mpi3mr_bsg_pel_abort(struct mpi3mr_ioc *mrioc)
                dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
                return -1;
        }
-       if (mrioc->stop_bsgs) {
+       if (mrioc->stop_bsgs || mrioc->block_on_pci_err) {
                dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
                return -1;
        }
@@ -1492,6 +1492,9 @@ static long mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc,
                goto out;
        }
 
+       if (mrioc->unrecoverable || mrioc->block_on_pci_err)
+               return -EINVAL;
+
        sg_copy_to_buffer(job->request_payload.sg_list,
                          job->request_payload.sg_cnt,
                          &adpreset, sizeof(adpreset));
@@ -2575,7 +2578,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
                mutex_unlock(&mrioc->bsg_cmds.mutex);
                goto out;
        }
-       if (mrioc->stop_bsgs) {
+       if (mrioc->stop_bsgs || mrioc->block_on_pci_err) {
                dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
                rval = -EAGAIN;
                mutex_unlock(&mrioc->bsg_cmds.mutex);
@@ -3108,7 +3111,8 @@ adp_state_show(struct device *dev, struct device_attribute *attr,
        ioc_state = mpi3mr_get_iocstate(mrioc);
        if (ioc_state == MRIOC_STATE_UNRECOVERABLE)
                adp_state = MPI3MR_BSG_ADPSTATE_UNRECOVERABLE;
-       else if ((mrioc->reset_in_progress) || (mrioc->stop_bsgs))
+       else if (mrioc->reset_in_progress || mrioc->stop_bsgs ||
+                mrioc->block_on_pci_err)
                adp_state = MPI3MR_BSG_ADPSTATE_IN_RESET;
        else if (ioc_state == MRIOC_STATE_FAULT)
                adp_state = MPI3MR_BSG_ADPSTATE_FAULT;
index 458c856dda4bc0ffa25035c82bd9f04a10e28726..c196dc14ad2063b7514bcd934a03be8adcaf2abd 100644 (file)
@@ -608,7 +608,7 @@ int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
        mrioc = (struct mpi3mr_ioc *)shost->hostdata;
 
        if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
-           mrioc->unrecoverable))
+           mrioc->unrecoverable || mrioc->pci_err_recovery))
                return 0;
 
        num_entries = mpi3mr_process_op_reply_q(mrioc,
@@ -1693,6 +1693,12 @@ int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req,
                retval = -EAGAIN;
                goto out;
        }
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "admin request queue submission failed due to pci error recovery in progress\n");
+               retval = -EAGAIN;
+               goto out;
+       }
+
        areq_entry = (u8 *)mrioc->admin_req_base +
            (areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
        memset(areq_entry, 0, MPI3MR_ADMIN_REQ_FRAME_SZ);
@@ -2363,6 +2369,11 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
                retval = -EAGAIN;
                goto out;
        }
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "operational request queue submission failed due to pci error recovery in progress\n");
+               retval = -EAGAIN;
+               goto out;
+       }
 
        segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
        req_entry = (u8 *)segment_base_addr +
@@ -2627,7 +2638,7 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
        union mpi3mr_trigger_data trigger_data;
        u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
 
-       if (mrioc->reset_in_progress)
+       if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
                return;
 
        if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
@@ -4268,7 +4279,7 @@ retry_init:
                goto out_failed_noretry;
        }
 
-       if (is_resume) {
+       if (is_resume || mrioc->block_on_pci_err) {
                dprint_reset(mrioc, "setting up single ISR\n");
                retval = mpi3mr_setup_isr(mrioc, 1);
                if (retval) {
@@ -4319,7 +4330,7 @@ retry_init:
                goto out_failed;
        }
 
-       if (is_resume) {
+       if (is_resume || mrioc->block_on_pci_err) {
                dprint_reset(mrioc, "setting up multiple ISR\n");
                retval = mpi3mr_setup_isr(mrioc, 0);
                if (retval) {
@@ -4807,7 +4818,8 @@ void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
 
        ioc_state = mpi3mr_get_iocstate(mrioc);
 
-       if ((!mrioc->unrecoverable) && (!mrioc->reset_in_progress) &&
+       if (!mrioc->unrecoverable && !mrioc->reset_in_progress &&
+           !mrioc->pci_err_recovery &&
            (ioc_state == MRIOC_STATE_READY)) {
                if (mpi3mr_issue_and_process_mur(mrioc,
                    MPI3MR_RESET_FROM_CTLR_CLEANUP))
index 0986b362e5f0acd62289085777af27ad38fd5b39..69b14918de59ea02aed9f6ac17d9843423dcc82c 100644 (file)
@@ -956,7 +956,7 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
        int retval = 0;
        struct mpi3mr_tgt_dev *tgtdev;
 
-       if (mrioc->reset_in_progress)
+       if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
                return -1;
 
        tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
@@ -2007,6 +2007,7 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
        struct mpi3_device_page0 *dev_pg0 = NULL;
        u16 perst_id, handle, dev_info;
        struct mpi3_device0_sas_sata_format *sasinf = NULL;
+       unsigned int timeout;
 
        mpi3mr_fwevt_del_from_list(mrioc, fwevt);
        mrioc->current_event = fwevt;
@@ -2097,8 +2098,18 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
        }
        case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH:
        {
-               while (mrioc->device_refresh_on)
+               timeout = MPI3MR_RESET_TIMEOUT * 2;
+               while ((mrioc->device_refresh_on || mrioc->block_on_pci_err) &&
+                   !mrioc->unrecoverable && !mrioc->pci_err_recovery) {
                        msleep(500);
+                       if (!timeout--) {
+                               mrioc->unrecoverable = 1;
+                               break;
+                       }
+               }
+
+               if (mrioc->unrecoverable || mrioc->pci_err_recovery)
+                       break;
 
                dprint_event_bh(mrioc,
                    "scan for non responding and newly added devices after soft reset started\n");
@@ -3796,6 +3807,13 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
                mutex_unlock(&drv_cmd->mutex);
                goto out;
        }
+       if (mrioc->block_on_pci_err) {
+               retval = -1;
+               dprint_tm(mrioc, "sending task management failed due to\n"
+                               "pci error recovery in progress\n");
+               mutex_unlock(&drv_cmd->mutex);
+               goto out;
+       }
 
        drv_cmd->state = MPI3MR_CMD_PENDING;
        drv_cmd->is_waiting = 1;
@@ -4181,6 +4199,7 @@ static int mpi3mr_eh_bus_reset(struct scsi_cmnd *scmd)
        struct mpi3mr_sdev_priv_data *sdev_priv_data;
        u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
        int retval = FAILED;
+       unsigned int timeout = MPI3MR_RESET_TIMEOUT;
 
        sdev_priv_data = scmd->device->hostdata;
        if (sdev_priv_data && sdev_priv_data->tgt_priv_data) {
@@ -4191,12 +4210,24 @@ static int mpi3mr_eh_bus_reset(struct scsi_cmnd *scmd)
        if (dev_type == MPI3_DEVICE_DEVFORM_VD) {
                mpi3mr_wait_for_host_io(mrioc,
                        MPI3MR_RAID_ERRREC_RESET_TIMEOUT);
-               if (!mpi3mr_get_fw_pending_ios(mrioc))
+               if (!mpi3mr_get_fw_pending_ios(mrioc)) {
+                       while (mrioc->reset_in_progress ||
+                              mrioc->prepare_for_reset ||
+                              mrioc->block_on_pci_err) {
+                               ssleep(1);
+                               if (!timeout--) {
+                                       retval = FAILED;
+                                       goto out;
+                               }
+                       }
                        retval = SUCCESS;
+                       goto out;
+               }
        }
        if (retval == FAILED)
                mpi3mr_print_pending_host_io(mrioc);
 
+out:
        sdev_printk(KERN_INFO, scmd->device,
                "Bus reset is %s for scmd(%p)\n",
                ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
@@ -4879,7 +4910,8 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
                goto out;
        }
 
-       if (mrioc->reset_in_progress) {
+       if (mrioc->reset_in_progress || mrioc->prepare_for_reset
+           || mrioc->block_on_pci_err) {
                retval = SCSI_MLQUEUE_HOST_BUSY;
                goto out;
        }
@@ -5362,7 +5394,14 @@ static void mpi3mr_remove(struct pci_dev *pdev)
        while (mrioc->reset_in_progress || mrioc->is_driver_loading)
                ssleep(1);
 
-       if (!pci_device_is_present(mrioc->pdev)) {
+       if (mrioc->block_on_pci_err) {
+               mrioc->block_on_pci_err = false;
+               scsi_unblock_requests(shost);
+               mrioc->unrecoverable = 1;
+       }
+
+       if (!pci_device_is_present(mrioc->pdev) ||
+           mrioc->pci_err_recovery) {
                mrioc->unrecoverable = 1;
                mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
        }
index 329cc6ec3b589177f5ea1c870e877200ed428be1..8612780f6e9ee7e00a323cddd61cc65df56cc2cc 100644 (file)
@@ -151,6 +151,11 @@ static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
                return -EFAULT;
        }
 
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
+               return -EFAULT;
+       }
+
        data_out_sz = sizeof(struct rep_manu_request);
        data_in_sz = sizeof(struct rep_manu_reply);
        data_out = dma_alloc_coherent(&mrioc->pdev->dev,
@@ -790,6 +795,12 @@ static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
                return -EFAULT;
        }
 
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "%s: pci error recovery in progress!\n",
+                   __func__);
+               return -EFAULT;
+       }
+
        if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
            sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
                ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
@@ -1007,6 +1018,9 @@ mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
        hba_port->port_id = port_id;
        ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
            hba_port, hba_port->port_id);
+       if (mrioc->reset_in_progress ||
+               mrioc->pci_err_recovery)
+               hba_port->flags = MPI3MR_HBA_PORT_FLAG_NEW;
        list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
        return hba_port;
 }
@@ -1055,7 +1069,7 @@ void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
        struct mpi3mr_sas_node *mr_sas_node;
        struct mpi3mr_sas_phy *mr_sas_phy;
 
-       if (mrioc->reset_in_progress)
+       if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
                return;
 
        spin_lock_irqsave(&mrioc->sas_node_lock, flags);
@@ -1978,7 +1992,7 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
        if (!handle)
                return -1;
 
-       if (mrioc->reset_in_progress)
+       if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
                return -1;
 
        if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
@@ -2184,7 +2198,7 @@ void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
        /* remove sibling ports attached to this expander */
        list_for_each_entry_safe(mr_sas_port, next,
           &sas_expander->sas_port_list, port_list) {
-               if (mrioc->reset_in_progress)
+               if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
                        return;
                if (mr_sas_port->remote_identify.device_type ==
                    SAS_END_DEVICE)
@@ -2234,7 +2248,7 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
        struct mpi3mr_sas_node *sas_expander;
        unsigned long flags;
 
-       if (mrioc->reset_in_progress)
+       if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
                return;
 
        if (!hba_port)
@@ -2545,6 +2559,11 @@ static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
                return -EFAULT;
        }
 
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
+               return -EFAULT;
+       }
+
        data_out_sz = sizeof(struct phy_error_log_request);
        data_in_sz = sizeof(struct phy_error_log_reply);
        sz = data_out_sz + data_in_sz;
@@ -2804,6 +2823,12 @@ mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
                return -EFAULT;
        }
 
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "%s: pci error recovery in progress!\n",
+                   __func__);
+               return -EFAULT;
+       }
+
        data_out_sz = sizeof(struct phy_control_request);
        data_in_sz = sizeof(struct phy_control_reply);
        sz = data_out_sz + data_in_sz;
@@ -3227,6 +3252,12 @@ mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
                goto out;
        }
 
+       if (mrioc->pci_err_recovery) {
+               ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
+               rc = -EFAULT;
+               goto out;
+       }
+
        rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
            &dma_addr_out, &dma_len_out, &addr_out);
        if (rc)