printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
ioc->name, (unsigned long long)pio_chip, pio_sz);
+ /* Save PCI configuration state for recovery from PCI AER/EEH errors */
+ pci_save_state(pdev);
+
return 0;
out_fail:
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
+ if (ioc->pci_error_recovery)
+ return 0;
+
ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
ioc->name, __func__, ioc_state));
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
+ if (ioc->pci_error_recovery) {
+ printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n",
+ ioc->name, __func__);
+ r = 0;
+ goto out;
+ }
+
if (mpt2sas_fwfault_debug)
mpt2sas_halt_firmware(ioc);
goto err_out;
}
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
rc = FAILED;
unsigned long flags;
struct _tr_list *delayed_tr;
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
"progress!\n", __func__, ioc->name));
return;
u16 smid;
struct _tr_list *delayed_tr;
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
"progress!\n", __func__, ioc->name));
return;
Mpi2SCSITaskManagementReply_t *mpi_reply =
mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
"progress!\n", __func__, ioc->name));
return 1;
Mpi2SasIoUnitControlRequest_t *mpi_request;
u16 smid_sas_ctrl;
- if (ioc->shost_recovery || ioc->remove_host) {
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
"progress!\n", __func__, ioc->name));
return 1;
count++;
mpt2sas_base_free_smid(ioc, smid);
scsi_dma_unmap(scmd);
- scmd->result = DID_RESET << 16;
+ if (ioc->pci_error_recovery)
+ scmd->result = DID_NO_CONNECT << 16;
+ else
+ scmd->result = DID_RESET << 16;
scmd->scsi_done(scmd);
}
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
return 0;
}
+ if (ioc->pci_error_recovery) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+
sas_target_priv_data = sas_device_priv_data->sas_target;
/* invalid device handle */
if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
if (!handle)
return -1;
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
return -1;
if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
_scsih_sas_topology_change_event_debug(ioc, event_data);
#endif
- if (ioc->shost_recovery || ioc->remove_host)
+ if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
return;
if (!ioc->sas_hba.num_phys)
"expander event\n", ioc->name));
return;
}
- if (ioc->shost_recovery || ioc->remove_host)
+ if (ioc->shost_recovery || ioc->remove_host ||
+ ioc->pci_error_recovery)
return;
phy_number = event_data->StartPhyNum + i;
reason_code = event_data->PHY[i].PhyStatus &
struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
/* the queue is being flushed so ignore this event */
- if (ioc->remove_host || fw_event->cancel_pending_work) {
+ if (ioc->remove_host || fw_event->cancel_pending_work ||
+ ioc->pci_error_recovery) {
_scsih_fw_event_free(ioc, fw_event);
return;
}
u16 sz;
/* events turned off due to host reset or driver unloading */
- if (ioc->remove_host)
+ if (ioc->remove_host || ioc->pci_error_recovery)
return 1;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
case pci_channel_io_normal:
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
+ /* Fatal error, prepare for slot reset */
+ ioc->pci_error_recovery = 1;
scsi_block_requests(ioc->shost);
mpt2sas_base_stop_watchdog(ioc);
mpt2sas_base_free_resources(ioc);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
- _scsih_remove(pdev);
+ /* Permanent error, prepare for device removal */
+ ioc->pci_error_recovery = 1;
+ mpt2sas_base_stop_watchdog(ioc);
+ _scsih_flush_running_cmds(ioc);
return PCI_ERS_RESULT_DISCONNECT;
}
return PCI_ERS_RESULT_NEED_RESET;
printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
ioc->name);
+ ioc->pci_error_recovery = 0;
ioc->pdev = pdev;
+ pci_restore_state(pdev);
rc = mpt2sas_base_map_resources(ioc);
if (rc)
return PCI_ERS_RESULT_DISCONNECT;