scsi: mpt3sas: Handle fault during HBA initialization

During HBA initialization time, if handshake operation fails due to some
firmware fault then currently driver is terminating the HBA
initialization. It is possible that HBA may come up properly if diag reset
is issued.

So improvement is made in driver in such a way that before terminating the
HBA initialization, driver checks the IOC state and if IOC state is in
fault state then issue diag reset for once. If diag reset is successful
then continue with HBA initialization else terminate the HBA
initialization.

Signed-off-by: Suganath Prabu <suganath-prabu.subramani@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Suganath Prabu 2019-08-03 09:59:54 -04:00 committed by Martin K. Petersen
parent 3ac8e47bbf
commit 9c067c053f
1 changed files with 62 additions and 13 deletions

View File

@ -3181,6 +3181,37 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
} }
} }
static int
_base_diag_reset(struct MPT3SAS_ADAPTER *ioc);
/**
* _base_check_for_fault_and_issue_reset - check if IOC is in fault state
* and if it is in fault state then issue diag reset.
* @ioc: per adapter object
*
* Returns: 0 for success, non-zero for failure.
*/
static int
_base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc)
{
u32 ioc_state;
int rc = -EFAULT;
dinitprintk(ioc, pr_info("%s\n", __func__));
if (ioc->pci_error_recovery)
return 0;
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
dhsprintk(ioc, pr_info("%s: ioc_state(0x%08x)\n", __func__, ioc_state));
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
mpt3sas_base_fault_info(ioc, ioc_state &
MPI2_DOORBELL_DATA_MASK);
rc = _base_diag_reset(ioc);
}
return rc;
}
/** /**
* mpt3sas_base_map_resources - map in controller resources (io/irq/memap) * mpt3sas_base_map_resources - map in controller resources (io/irq/memap)
* @ioc: per adapter object * @ioc: per adapter object
@ -3193,7 +3224,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
struct pci_dev *pdev = ioc->pdev; struct pci_dev *pdev = ioc->pdev;
u32 memap_sz; u32 memap_sz;
u32 pio_sz; u32 pio_sz;
int i, r = 0; int i, r = 0, rc;
u64 pio_chip = 0; u64 pio_chip = 0;
phys_addr_t chip_phys = 0; phys_addr_t chip_phys = 0;
struct adapter_reply_queue *reply_q; struct adapter_reply_queue *reply_q;
@ -3254,8 +3285,11 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
_base_mask_interrupts(ioc); _base_mask_interrupts(ioc);
r = _base_get_ioc_facts(ioc); r = _base_get_ioc_facts(ioc);
if (r) if (r) {
rc = _base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_get_ioc_facts(ioc)))
goto out_fail; goto out_fail;
}
if (!ioc->rdpq_array_enable_assigned) { if (!ioc->rdpq_array_enable_assigned) {
ioc->rdpq_array_enable = ioc->rdpq_array_capable; ioc->rdpq_array_enable = ioc->rdpq_array_capable;
@ -5414,8 +5448,6 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout)
* *
* Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
*/ */
static int
_base_diag_reset(struct MPT3SAS_ADAPTER *ioc);
static int static int
_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout)
@ -6691,7 +6723,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
static int static int
_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
{ {
int r, i, index; int r, i, index, rc;
unsigned long flags; unsigned long flags;
u32 reply_address; u32 reply_address;
u16 smid; u16 smid;
@ -6794,9 +6826,20 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
skip_init_reply_post_free_queue: skip_init_reply_post_free_queue:
r = _base_send_ioc_init(ioc); r = _base_send_ioc_init(ioc);
if (r) if (r) {
/*
* No need to check IOC state for fault state & issue
* diag reset during host reset. This check is need
* only during driver load time.
*/
if (!ioc->is_driver_loading)
return r; return r;
rc = _base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_send_ioc_init(ioc)))
return r;
}
/* initialize reply free host index */ /* initialize reply free host index */
ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
@ -6887,7 +6930,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
int int
mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
{ {
int r, i; int r, i, rc;
int cpu_id, last_cpu_id = 0; int cpu_id, last_cpu_id = 0;
dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__));
@ -6931,8 +6974,11 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
pci_set_drvdata(ioc->pdev, ioc->shost); pci_set_drvdata(ioc->pdev, ioc->shost);
r = _base_get_ioc_facts(ioc); r = _base_get_ioc_facts(ioc);
if (r) if (r) {
rc = _base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_get_ioc_facts(ioc)))
goto out_free_resources; goto out_free_resources;
}
switch (ioc->hba_mpi_version_belonged) { switch (ioc->hba_mpi_version_belonged) {
case MPI2_VERSION: case MPI2_VERSION:
@ -7000,9 +7046,12 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
r = _base_get_port_facts(ioc, i); r = _base_get_port_facts(ioc, i);
if (r) if (r) {
rc = _base_check_for_fault_and_issue_reset(ioc);
if (rc || (_base_get_port_facts(ioc, i)))
goto out_free_resources; goto out_free_resources;
} }
}
r = _base_allocate_memory_pools(ioc); r = _base_allocate_memory_pools(ioc);
if (r) if (r)