Skip to content

Commit

Permalink
scsi: mpi3mr: Prevent PCI writes from driver during PCI error recovery
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sumit Saxena authored and Martin K. Petersen committed Jul 5, 2024
1 parent 30bafe1 commit 1c342b0
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 17 deletions.
1 change: 1 addition & 0 deletions drivers/scsi/mpi3mr/mpi3mr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions drivers/scsi/mpi3mr/mpi3mr_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
22 changes: 17 additions & 5 deletions drivers/scsi/mpi3mr/mpi3mr_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 +
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -4268,7 +4279,7 @@ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
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) {
Expand Down Expand Up @@ -4319,7 +4330,7 @@ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
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) {
Expand Down Expand Up @@ -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))
Expand Down
49 changes: 44 additions & 5 deletions drivers/scsi/mpi3mr/mpi3mr_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down
39 changes: 35 additions & 4 deletions drivers/scsi/mpi3mr/mpi3mr_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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__);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 1c342b0

Please sign in to comment.