mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-17 20:25:19 +00:00
[SCSI] mptfusion: Better handling of DEAD IOC PCI-E Link down error condition
Find Non-Operation IOC and remove it from OS: Detecting dead(non-functional) ioc will be done reading doorbell register value from fault reset thread, which has been called from work thread context after each specific interval. If doorbell value is 0xFFFFFFFF, it will be considered as IOC is non-operational and marked as dead ioc. Once Dead IOC has been detected, it will be removed at pci layer using "pci_remove_bus_device" API. Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
3850b14e51
commit
e62cca19a9
5 changed files with 105 additions and 30 deletions
|
@ -63,6 +63,8 @@
|
|||
#ifdef CONFIG_MTRR
|
||||
#include <asm/mtrr.h>
|
||||
#endif
|
||||
#include <linux/kthread.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "mptbase.h"
|
||||
#include "lsi/mpi_log_fc.h"
|
||||
|
@ -323,6 +325,32 @@ mpt_is_discovery_complete(MPT_ADAPTER *ioc)
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mpt_remove_dead_ioc_func - kthread context to remove dead ioc
|
||||
* @arg: input argument, used to derive ioc
|
||||
*
|
||||
* Return 0 if controller is removed from pci subsystem.
|
||||
* Return -1 for other case.
|
||||
*/
|
||||
static int mpt_remove_dead_ioc_func(void *arg)
|
||||
{
|
||||
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
|
||||
struct pci_dev *pdev;
|
||||
|
||||
if ((ioc == NULL))
|
||||
return -1;
|
||||
|
||||
pdev = ioc->pcidev;
|
||||
if ((pdev == NULL))
|
||||
return -1;
|
||||
|
||||
pci_remove_bus_device(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* mpt_fault_reset_work - work performed on workq after ioc fault
|
||||
* @work: input argument, used to derive ioc
|
||||
|
@ -336,12 +364,45 @@ mpt_fault_reset_work(struct work_struct *work)
|
|||
u32 ioc_raw_state;
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
MPT_SCSI_HOST *hd;
|
||||
struct task_struct *p;
|
||||
|
||||
if (ioc->ioc_reset_in_progress || !ioc->active)
|
||||
goto out;
|
||||
|
||||
|
||||
ioc_raw_state = mpt_GetIocState(ioc, 0);
|
||||
if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
|
||||
if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) {
|
||||
printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n",
|
||||
ioc->name, __func__);
|
||||
|
||||
/*
|
||||
* Call mptscsih_flush_pending_cmds callback so that we
|
||||
* flush all pending commands back to OS.
|
||||
* This call is required to aovid deadlock at block layer.
|
||||
* Dead IOC will fail to do diag reset,and this call is safe
|
||||
* since dead ioc will never return any command back from HW.
|
||||
*/
|
||||
hd = shost_priv(ioc->sh);
|
||||
ioc->schedule_dead_ioc_flush_running_cmds(hd);
|
||||
|
||||
/*Remove the Dead Host */
|
||||
p = kthread_run(mpt_remove_dead_ioc_func, ioc,
|
||||
"mpt_dead_ioc_%d", ioc->id);
|
||||
if (IS_ERR(p)) {
|
||||
printk(MYIOC_s_ERR_FMT
|
||||
"%s: Running mpt_dead_ioc thread failed !\n",
|
||||
ioc->name, __func__);
|
||||
} else {
|
||||
printk(MYIOC_s_WARN_FMT
|
||||
"%s: Running mpt_dead_ioc thread success !\n",
|
||||
ioc->name, __func__);
|
||||
}
|
||||
return; /* don't rearm timer */
|
||||
}
|
||||
|
||||
if ((ioc_raw_state & MPI_IOC_STATE_MASK)
|
||||
== MPI_IOC_STATE_FAULT) {
|
||||
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
|
||||
ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
|
||||
printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue