Merge patch series "mpi3mr: Support PCI Error Recovery"
Sumit Saxena <sumit.saxena@broadcom.com> says: This patch series contains the changes done in the driver to support PCI error recovery. It is rework of older patch series from Ranjan Kumar, see [1]. [1] https://lore.kernel.org/all/20231214205900.270488-1-ranjan.kumar@broadcom.com/ Link: https://lore.kernel.org/r/20240627101735.18286-1-sumit.saxena@broadcom.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
6cd48c8f62
@ -23,6 +23,7 @@
|
|||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/aer.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@ -56,8 +57,8 @@ extern struct list_head mrioc_list;
|
|||||||
extern int prot_mask;
|
extern int prot_mask;
|
||||||
extern atomic64_t event_counter;
|
extern atomic64_t event_counter;
|
||||||
|
|
||||||
#define MPI3MR_DRIVER_VERSION "8.9.1.0.50"
|
#define MPI3MR_DRIVER_VERSION "8.9.1.0.51"
|
||||||
#define MPI3MR_DRIVER_RELDATE "14-May-2024"
|
#define MPI3MR_DRIVER_RELDATE "29-May-2024"
|
||||||
|
|
||||||
#define MPI3MR_DRIVER_NAME "mpi3mr"
|
#define MPI3MR_DRIVER_NAME "mpi3mr"
|
||||||
#define MPI3MR_DRIVER_LICENSE "GPL"
|
#define MPI3MR_DRIVER_LICENSE "GPL"
|
||||||
@ -129,6 +130,7 @@ extern atomic64_t event_counter;
|
|||||||
#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180
|
#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180
|
||||||
#define MPI3MR_RESET_ACK_TIMEOUT 30
|
#define MPI3MR_RESET_ACK_TIMEOUT 30
|
||||||
#define MPI3MR_MUR_TIMEOUT 120
|
#define MPI3MR_MUR_TIMEOUT 120
|
||||||
|
#define MPI3MR_RESET_TIMEOUT 510
|
||||||
|
|
||||||
#define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */
|
#define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */
|
||||||
|
|
||||||
@ -517,6 +519,7 @@ struct mpi3mr_throttle_group_info {
|
|||||||
|
|
||||||
/* HBA port flags */
|
/* HBA port flags */
|
||||||
#define MPI3MR_HBA_PORT_FLAG_DIRTY 0x01
|
#define MPI3MR_HBA_PORT_FLAG_DIRTY 0x01
|
||||||
|
#define MPI3MR_HBA_PORT_FLAG_NEW 0x02
|
||||||
|
|
||||||
/* IOCTL data transfer sge*/
|
/* IOCTL data transfer sge*/
|
||||||
#define MPI3MR_NUM_IOCTL_SGE 256
|
#define MPI3MR_NUM_IOCTL_SGE 256
|
||||||
@ -1153,6 +1156,8 @@ struct scmd_priv {
|
|||||||
* @trace_release_trigger_active: Trace trigger active flag
|
* @trace_release_trigger_active: Trace trigger active flag
|
||||||
* @fw_release_trigger_active: Fw release trigger active flag
|
* @fw_release_trigger_active: Fw release trigger active flag
|
||||||
* @snapdump_trigger_active: Snapdump trigger active flag
|
* @snapdump_trigger_active: Snapdump trigger active flag
|
||||||
|
* @pci_err_recovery: PCI error recovery in progress
|
||||||
|
* @block_on_pci_err: Block IO during PCI error recovery
|
||||||
*/
|
*/
|
||||||
struct mpi3mr_ioc {
|
struct mpi3mr_ioc {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
@ -1353,6 +1358,8 @@ struct mpi3mr_ioc {
|
|||||||
bool snapdump_trigger_active;
|
bool snapdump_trigger_active;
|
||||||
bool trace_release_trigger_active;
|
bool trace_release_trigger_active;
|
||||||
bool fw_release_trigger_active;
|
bool fw_release_trigger_active;
|
||||||
|
bool pci_err_recovery;
|
||||||
|
bool block_on_pci_err;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -846,7 +846,7 @@ static int mpi3mr_bsg_pel_abort(struct mpi3mr_ioc *mrioc)
|
|||||||
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
|
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
|
||||||
return -1;
|
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__);
|
dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1492,6 +1492,9 @@ static long mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mrioc->unrecoverable || mrioc->block_on_pci_err)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||||
job->request_payload.sg_cnt,
|
job->request_payload.sg_cnt,
|
||||||
&adpreset, sizeof(adpreset));
|
&adpreset, sizeof(adpreset));
|
||||||
@ -2575,7 +2578,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job)
|
|||||||
mutex_unlock(&mrioc->bsg_cmds.mutex);
|
mutex_unlock(&mrioc->bsg_cmds.mutex);
|
||||||
goto out;
|
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__);
|
dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
|
||||||
rval = -EAGAIN;
|
rval = -EAGAIN;
|
||||||
mutex_unlock(&mrioc->bsg_cmds.mutex);
|
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);
|
ioc_state = mpi3mr_get_iocstate(mrioc);
|
||||||
if (ioc_state == MRIOC_STATE_UNRECOVERABLE)
|
if (ioc_state == MRIOC_STATE_UNRECOVERABLE)
|
||||||
adp_state = MPI3MR_BSG_ADPSTATE_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;
|
adp_state = MPI3MR_BSG_ADPSTATE_IN_RESET;
|
||||||
else if (ioc_state == MRIOC_STATE_FAULT)
|
else if (ioc_state == MRIOC_STATE_FAULT)
|
||||||
adp_state = MPI3MR_BSG_ADPSTATE_FAULT;
|
adp_state = MPI3MR_BSG_ADPSTATE_FAULT;
|
||||||
|
@ -608,7 +608,7 @@ int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
|
|||||||
mrioc = (struct mpi3mr_ioc *)shost->hostdata;
|
mrioc = (struct mpi3mr_ioc *)shost->hostdata;
|
||||||
|
|
||||||
if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
|
if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
|
||||||
mrioc->unrecoverable))
|
mrioc->unrecoverable || mrioc->pci_err_recovery))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
num_entries = mpi3mr_process_op_reply_q(mrioc,
|
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;
|
retval = -EAGAIN;
|
||||||
goto out;
|
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_entry = (u8 *)mrioc->admin_req_base +
|
||||||
(areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
|
(areq_pi * MPI3MR_ADMIN_REQ_FRAME_SZ);
|
||||||
memset(areq_entry, 0, 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;
|
retval = -EAGAIN;
|
||||||
goto out;
|
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;
|
segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
|
||||||
req_entry = (u8 *)segment_base_addr +
|
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;
|
union mpi3mr_trigger_data trigger_data;
|
||||||
u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
|
u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
|
||||||
|
|
||||||
if (mrioc->reset_in_progress)
|
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
|
if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
|
||||||
@ -4268,7 +4279,7 @@ retry_init:
|
|||||||
goto out_failed_noretry;
|
goto out_failed_noretry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_resume) {
|
if (is_resume || mrioc->block_on_pci_err) {
|
||||||
dprint_reset(mrioc, "setting up single ISR\n");
|
dprint_reset(mrioc, "setting up single ISR\n");
|
||||||
retval = mpi3mr_setup_isr(mrioc, 1);
|
retval = mpi3mr_setup_isr(mrioc, 1);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
@ -4319,7 +4330,7 @@ retry_init:
|
|||||||
goto out_failed;
|
goto out_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_resume) {
|
if (is_resume || mrioc->block_on_pci_err) {
|
||||||
dprint_reset(mrioc, "setting up multiple ISR\n");
|
dprint_reset(mrioc, "setting up multiple ISR\n");
|
||||||
retval = mpi3mr_setup_isr(mrioc, 0);
|
retval = mpi3mr_setup_isr(mrioc, 0);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
@ -4807,7 +4818,8 @@ void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
|
|||||||
|
|
||||||
ioc_state = mpi3mr_get_iocstate(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)) {
|
(ioc_state == MRIOC_STATE_READY)) {
|
||||||
if (mpi3mr_issue_and_process_mur(mrioc,
|
if (mpi3mr_issue_and_process_mur(mrioc,
|
||||||
MPI3MR_RESET_FROM_CTLR_CLEANUP))
|
MPI3MR_RESET_FROM_CTLR_CLEANUP))
|
||||||
|
@ -956,7 +956,7 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
struct mpi3mr_tgt_dev *tgtdev;
|
struct mpi3mr_tgt_dev *tgtdev;
|
||||||
|
|
||||||
if (mrioc->reset_in_progress)
|
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
|
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;
|
struct mpi3_device_page0 *dev_pg0 = NULL;
|
||||||
u16 perst_id, handle, dev_info;
|
u16 perst_id, handle, dev_info;
|
||||||
struct mpi3_device0_sas_sata_format *sasinf = NULL;
|
struct mpi3_device0_sas_sata_format *sasinf = NULL;
|
||||||
|
unsigned int timeout;
|
||||||
|
|
||||||
mpi3mr_fwevt_del_from_list(mrioc, fwevt);
|
mpi3mr_fwevt_del_from_list(mrioc, fwevt);
|
||||||
mrioc->current_event = 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:
|
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);
|
msleep(500);
|
||||||
|
if (!timeout--) {
|
||||||
|
mrioc->unrecoverable = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mrioc->unrecoverable || mrioc->pci_err_recovery)
|
||||||
|
break;
|
||||||
|
|
||||||
dprint_event_bh(mrioc,
|
dprint_event_bh(mrioc,
|
||||||
"scan for non responding and newly added devices after soft reset started\n");
|
"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);
|
mutex_unlock(&drv_cmd->mutex);
|
||||||
goto out;
|
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->state = MPI3MR_CMD_PENDING;
|
||||||
drv_cmd->is_waiting = 1;
|
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;
|
struct mpi3mr_sdev_priv_data *sdev_priv_data;
|
||||||
u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
|
u8 dev_type = MPI3_DEVICE_DEVFORM_VD;
|
||||||
int retval = FAILED;
|
int retval = FAILED;
|
||||||
|
unsigned int timeout = MPI3MR_RESET_TIMEOUT;
|
||||||
|
|
||||||
sdev_priv_data = scmd->device->hostdata;
|
sdev_priv_data = scmd->device->hostdata;
|
||||||
if (sdev_priv_data && sdev_priv_data->tgt_priv_data) {
|
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) {
|
if (dev_type == MPI3_DEVICE_DEVFORM_VD) {
|
||||||
mpi3mr_wait_for_host_io(mrioc,
|
mpi3mr_wait_for_host_io(mrioc,
|
||||||
MPI3MR_RAID_ERRREC_RESET_TIMEOUT);
|
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;
|
retval = SUCCESS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (retval == FAILED)
|
if (retval == FAILED)
|
||||||
mpi3mr_print_pending_host_io(mrioc);
|
mpi3mr_print_pending_host_io(mrioc);
|
||||||
|
|
||||||
|
out:
|
||||||
sdev_printk(KERN_INFO, scmd->device,
|
sdev_printk(KERN_INFO, scmd->device,
|
||||||
"Bus reset is %s for scmd(%p)\n",
|
"Bus reset is %s for scmd(%p)\n",
|
||||||
((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||||
@ -4879,7 +4910,8 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
|
|||||||
goto out;
|
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;
|
retval = SCSI_MLQUEUE_HOST_BUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -5362,7 +5394,14 @@ static void mpi3mr_remove(struct pci_dev *pdev)
|
|||||||
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
|
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
|
||||||
ssleep(1);
|
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;
|
mrioc->unrecoverable = 1;
|
||||||
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
|
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
|
||||||
}
|
}
|
||||||
@ -5546,6 +5585,197 @@ mpi3mr_resume(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpi3mr_pcierr_error_detected - PCI error detected callback
|
||||||
|
* @pdev: PCI device instance
|
||||||
|
* @state: channel state
|
||||||
|
*
|
||||||
|
* This function is called by the PCI error recovery driver and
|
||||||
|
* based on the state passed the driver decides what actions to
|
||||||
|
* be recommended back to PCI driver.
|
||||||
|
*
|
||||||
|
* For all of the states if there is no valid mrioc or scsi host
|
||||||
|
* references in the PCI device then this function will return
|
||||||
|
* the result as disconnect.
|
||||||
|
*
|
||||||
|
* For normal state, this function will return the result as can
|
||||||
|
* recover.
|
||||||
|
*
|
||||||
|
* For frozen state, this function will block for any pending
|
||||||
|
* controller initialization or re-initialization to complete,
|
||||||
|
* stop any new interactions with the controller and return
|
||||||
|
* status as reset required.
|
||||||
|
*
|
||||||
|
* For permanent failure state, this function will mark the
|
||||||
|
* controller as unrecoverable and return status as disconnect.
|
||||||
|
*
|
||||||
|
* Returns: PCI_ERS_RESULT_NEED_RESET or CAN_RECOVER or
|
||||||
|
* DISCONNECT based on the controller state.
|
||||||
|
*/
|
||||||
|
static pci_ers_result_t
|
||||||
|
mpi3mr_pcierr_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *shost;
|
||||||
|
struct mpi3mr_ioc *mrioc;
|
||||||
|
unsigned int timeout = MPI3MR_RESET_TIMEOUT;
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "%s: callback invoked state(%d)\n", __func__,
|
||||||
|
state);
|
||||||
|
|
||||||
|
shost = pci_get_drvdata(pdev);
|
||||||
|
mrioc = shost_priv(shost);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case pci_channel_io_normal:
|
||||||
|
return PCI_ERS_RESULT_CAN_RECOVER;
|
||||||
|
case pci_channel_io_frozen:
|
||||||
|
mrioc->pci_err_recovery = true;
|
||||||
|
mrioc->block_on_pci_err = true;
|
||||||
|
do {
|
||||||
|
if (mrioc->reset_in_progress || mrioc->is_driver_loading)
|
||||||
|
ssleep(1);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} while (--timeout);
|
||||||
|
|
||||||
|
if (!timeout) {
|
||||||
|
mrioc->pci_err_recovery = true;
|
||||||
|
mrioc->block_on_pci_err = true;
|
||||||
|
mrioc->unrecoverable = 1;
|
||||||
|
mpi3mr_stop_watchdog(mrioc);
|
||||||
|
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
|
||||||
|
return PCI_ERS_RESULT_DISCONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
scsi_block_requests(mrioc->shost);
|
||||||
|
mpi3mr_stop_watchdog(mrioc);
|
||||||
|
mpi3mr_cleanup_resources(mrioc);
|
||||||
|
return PCI_ERS_RESULT_NEED_RESET;
|
||||||
|
case pci_channel_io_perm_failure:
|
||||||
|
mrioc->pci_err_recovery = true;
|
||||||
|
mrioc->block_on_pci_err = true;
|
||||||
|
mrioc->unrecoverable = 1;
|
||||||
|
mpi3mr_stop_watchdog(mrioc);
|
||||||
|
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc);
|
||||||
|
return PCI_ERS_RESULT_DISCONNECT;
|
||||||
|
default:
|
||||||
|
return PCI_ERS_RESULT_DISCONNECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpi3mr_pcierr_slot_reset - Post slot reset callback
|
||||||
|
* @pdev: PCI device instance
|
||||||
|
*
|
||||||
|
* This function is called by the PCI error recovery driver
|
||||||
|
* after a slot or link reset issued by it for the recovery, the
|
||||||
|
* driver is expected to bring back the controller and
|
||||||
|
* initialize it.
|
||||||
|
*
|
||||||
|
* This function restores PCI state and reinitializes controller
|
||||||
|
* resources and the controller, this blocks for any pending
|
||||||
|
* reset to complete.
|
||||||
|
*
|
||||||
|
* Returns: PCI_ERS_RESULT_DISCONNECT on failure or
|
||||||
|
* PCI_ERS_RESULT_RECOVERED
|
||||||
|
*/
|
||||||
|
static pci_ers_result_t mpi3mr_pcierr_slot_reset(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *shost;
|
||||||
|
struct mpi3mr_ioc *mrioc;
|
||||||
|
unsigned int timeout = MPI3MR_RESET_TIMEOUT;
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "%s: callback invoked\n", __func__);
|
||||||
|
|
||||||
|
shost = pci_get_drvdata(pdev);
|
||||||
|
mrioc = shost_priv(shost);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (mrioc->reset_in_progress)
|
||||||
|
ssleep(1);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} while (--timeout);
|
||||||
|
|
||||||
|
if (!timeout)
|
||||||
|
goto out_failed;
|
||||||
|
|
||||||
|
pci_restore_state(pdev);
|
||||||
|
|
||||||
|
if (mpi3mr_setup_resources(mrioc)) {
|
||||||
|
ioc_err(mrioc, "setup resources failed\n");
|
||||||
|
goto out_failed;
|
||||||
|
}
|
||||||
|
mrioc->unrecoverable = 0;
|
||||||
|
mrioc->pci_err_recovery = false;
|
||||||
|
|
||||||
|
if (mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0))
|
||||||
|
goto out_failed;
|
||||||
|
|
||||||
|
return PCI_ERS_RESULT_RECOVERED;
|
||||||
|
|
||||||
|
out_failed:
|
||||||
|
mrioc->unrecoverable = 1;
|
||||||
|
mrioc->block_on_pci_err = false;
|
||||||
|
scsi_unblock_requests(shost);
|
||||||
|
mpi3mr_start_watchdog(mrioc);
|
||||||
|
return PCI_ERS_RESULT_DISCONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpi3mr_pcierr_resume - PCI error recovery resume
|
||||||
|
* callback
|
||||||
|
* @pdev: PCI device instance
|
||||||
|
*
|
||||||
|
* This function enables all I/O and IOCTLs post reset issued as
|
||||||
|
* part of the PCI error recovery
|
||||||
|
*
|
||||||
|
* Return: Nothing.
|
||||||
|
*/
|
||||||
|
static void mpi3mr_pcierr_resume(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *shost;
|
||||||
|
struct mpi3mr_ioc *mrioc;
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "%s: callback invoked\n", __func__);
|
||||||
|
|
||||||
|
shost = pci_get_drvdata(pdev);
|
||||||
|
mrioc = shost_priv(shost);
|
||||||
|
|
||||||
|
if (mrioc->block_on_pci_err) {
|
||||||
|
mrioc->block_on_pci_err = false;
|
||||||
|
scsi_unblock_requests(shost);
|
||||||
|
mpi3mr_start_watchdog(mrioc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpi3mr_pcierr_mmio_enabled - PCI error recovery callback
|
||||||
|
* @pdev: PCI device instance
|
||||||
|
*
|
||||||
|
* This is called only if mpi3mr_pcierr_error_detected returns
|
||||||
|
* PCI_ERS_RESULT_CAN_RECOVER.
|
||||||
|
*
|
||||||
|
* Return: PCI_ERS_RESULT_DISCONNECT when the controller is
|
||||||
|
* unrecoverable or when the shost/mrioc reference cannot be
|
||||||
|
* found, else return PCI_ERS_RESULT_RECOVERED
|
||||||
|
*/
|
||||||
|
static pci_ers_result_t mpi3mr_pcierr_mmio_enabled(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *shost;
|
||||||
|
struct mpi3mr_ioc *mrioc;
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "%s: callback invoked\n", __func__);
|
||||||
|
|
||||||
|
shost = pci_get_drvdata(pdev);
|
||||||
|
mrioc = shost_priv(shost);
|
||||||
|
|
||||||
|
if (mrioc->unrecoverable)
|
||||||
|
return PCI_ERS_RESULT_DISCONNECT;
|
||||||
|
|
||||||
|
return PCI_ERS_RESULT_RECOVERED;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pci_device_id mpi3mr_pci_id_table[] = {
|
static const struct pci_device_id mpi3mr_pci_id_table[] = {
|
||||||
{
|
{
|
||||||
PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
|
PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM,
|
||||||
@ -5563,6 +5793,13 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = {
|
|||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
|
MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table);
|
||||||
|
|
||||||
|
static struct pci_error_handlers mpi3mr_err_handler = {
|
||||||
|
.error_detected = mpi3mr_pcierr_error_detected,
|
||||||
|
.mmio_enabled = mpi3mr_pcierr_mmio_enabled,
|
||||||
|
.slot_reset = mpi3mr_pcierr_slot_reset,
|
||||||
|
.resume = mpi3mr_pcierr_resume,
|
||||||
|
};
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(mpi3mr_pm_ops, mpi3mr_suspend, mpi3mr_resume);
|
static SIMPLE_DEV_PM_OPS(mpi3mr_pm_ops, mpi3mr_suspend, mpi3mr_resume);
|
||||||
|
|
||||||
static struct pci_driver mpi3mr_pci_driver = {
|
static struct pci_driver mpi3mr_pci_driver = {
|
||||||
@ -5571,6 +5808,7 @@ static struct pci_driver mpi3mr_pci_driver = {
|
|||||||
.probe = mpi3mr_probe,
|
.probe = mpi3mr_probe,
|
||||||
.remove = mpi3mr_remove,
|
.remove = mpi3mr_remove,
|
||||||
.shutdown = mpi3mr_shutdown,
|
.shutdown = mpi3mr_shutdown,
|
||||||
|
.err_handler = &mpi3mr_err_handler,
|
||||||
.driver.pm = &mpi3mr_pm_ops,
|
.driver.pm = &mpi3mr_pm_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,6 +151,11 @@ static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
|
|||||||
return -EFAULT;
|
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_out_sz = sizeof(struct rep_manu_request);
|
||||||
data_in_sz = sizeof(struct rep_manu_reply);
|
data_in_sz = sizeof(struct rep_manu_reply);
|
||||||
data_out = dma_alloc_coherent(&mrioc->pdev->dev,
|
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;
|
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,
|
if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
|
||||||
sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
|
sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
|
||||||
ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
|
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;
|
hba_port->port_id = port_id;
|
||||||
ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
|
ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
|
||||||
hba_port, hba_port->port_id);
|
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);
|
list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
|
||||||
return hba_port;
|
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_node *mr_sas_node;
|
||||||
struct mpi3mr_sas_phy *mr_sas_phy;
|
struct mpi3mr_sas_phy *mr_sas_phy;
|
||||||
|
|
||||||
if (mrioc->reset_in_progress)
|
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock_irqsave(&mrioc->sas_node_lock, flags);
|
spin_lock_irqsave(&mrioc->sas_node_lock, flags);
|
||||||
@ -1978,7 +1992,7 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
|
|||||||
if (!handle)
|
if (!handle)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (mrioc->reset_in_progress)
|
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
|
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 */
|
/* remove sibling ports attached to this expander */
|
||||||
list_for_each_entry_safe(mr_sas_port, next,
|
list_for_each_entry_safe(mr_sas_port, next,
|
||||||
&sas_expander->sas_port_list, port_list) {
|
&sas_expander->sas_port_list, port_list) {
|
||||||
if (mrioc->reset_in_progress)
|
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
|
||||||
return;
|
return;
|
||||||
if (mr_sas_port->remote_identify.device_type ==
|
if (mr_sas_port->remote_identify.device_type ==
|
||||||
SAS_END_DEVICE)
|
SAS_END_DEVICE)
|
||||||
@ -2234,7 +2248,7 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
|
|||||||
struct mpi3mr_sas_node *sas_expander;
|
struct mpi3mr_sas_node *sas_expander;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (mrioc->reset_in_progress)
|
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!hba_port)
|
if (!hba_port)
|
||||||
@ -2545,6 +2559,11 @@ static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
|
|||||||
return -EFAULT;
|
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_out_sz = sizeof(struct phy_error_log_request);
|
||||||
data_in_sz = sizeof(struct phy_error_log_reply);
|
data_in_sz = sizeof(struct phy_error_log_reply);
|
||||||
sz = data_out_sz + data_in_sz;
|
sz = data_out_sz + data_in_sz;
|
||||||
@ -2804,6 +2823,12 @@ mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
|
|||||||
return -EFAULT;
|
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_out_sz = sizeof(struct phy_control_request);
|
||||||
data_in_sz = sizeof(struct phy_control_reply);
|
data_in_sz = sizeof(struct phy_control_reply);
|
||||||
sz = data_out_sz + data_in_sz;
|
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;
|
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,
|
rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
|
||||||
&dma_addr_out, &dma_len_out, &addr_out);
|
&dma_addr_out, &dma_len_out, &addr_out);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
Loading…
Reference in New Issue
Block a user