Skip to content

Commit

Permalink
[SCSI] mpt fusion : Adding FAULT Reset polling work
Browse files Browse the repository at this point in the history
When the firmware is in Fault state it will be identifed only when the next time
the driver access the IOC state.
This patch includes a polling function in the driver which will be executed in
regular interval to check the status of the firmware and if it is in Fault
state, then the firmware will be reset by the driver.

Signed-off-by: Sathya Prakash <sathya.prakash@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Prakash, Sathya authored and James Bottomley committed Jul 12, 2008
1 parent cc47244 commit d54d48b
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 0 deletions.
86 changes: 86 additions & 0 deletions drivers/message/fusion/mptbase.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,55 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
return 0;
}

/**
* mpt_fault_reset_work - work performed on workq after ioc fault
* @work: input argument, used to derive ioc
*
**/
static void
mpt_fault_reset_work(struct work_struct *work)
{
MPT_ADAPTER *ioc =
container_of(work, MPT_ADAPTER, fault_reset_work.work);
u32 ioc_raw_state;
int rc;
unsigned long flags;

if (ioc->diagPending || !ioc->active)
goto out;

ioc_raw_state = mpt_GetIocState(ioc, 0);
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",
ioc->name, __FUNCTION__);
rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
__FUNCTION__, (rc == 0) ? "success" : "failed");
ioc_raw_state = mpt_GetIocState(ioc, 0);
if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
"reset (%04xh)\n", ioc->name, ioc_raw_state &
MPI_DOORBELL_DATA_MASK);
}

out:
/*
* Take turns polling alternate controller
*/
if (ioc->alt_ioc)
ioc = ioc->alt_ioc;

/* rearm the timer */
spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
if (ioc->reset_work_q)
queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
msecs_to_jiffies(MPT_POLLING_INTERVAL));
spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
}


/*
* Process turbo (context) reply...
*/
Expand Down Expand Up @@ -1616,6 +1665,22 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
/* Find lookup slot. */
INIT_LIST_HEAD(&ioc->list);


/* Initialize workqueue */
INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
spin_lock_init(&ioc->fault_reset_work_lock);

snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
ioc->reset_work_q =
create_singlethread_workqueue(ioc->reset_work_q_name);
if (!ioc->reset_work_q) {
printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
ioc->name);
pci_release_selected_regions(pdev, ioc->bars);
kfree(ioc);
return -ENOMEM;
}

dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
ioc->name, &ioc->facts, &ioc->pfacts[0]));

Expand Down Expand Up @@ -1722,6 +1787,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
iounmap(ioc->memmap);
if (r != -5)
pci_release_selected_regions(pdev, ioc->bars);

destroy_workqueue(ioc->reset_work_q);
ioc->reset_work_q = NULL;

kfree(ioc);
pci_set_drvdata(pdev, NULL);
return r;
Expand Down Expand Up @@ -1754,6 +1823,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
}
#endif

if (!ioc->alt_ioc)
queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
msecs_to_jiffies(MPT_POLLING_INTERVAL));

return 0;
}

Expand All @@ -1769,6 +1842,19 @@ mpt_detach(struct pci_dev *pdev)
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
char pname[32];
u8 cb_idx;
unsigned long flags;
struct workqueue_struct *wq;

/*
* Stop polling ioc for fault condition
*/
spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
wq = ioc->reset_work_q;
ioc->reset_work_q = NULL;
spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
cancel_delayed_work(&ioc->fault_reset_work);
destroy_workqueue(wq);


sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
remove_proc_entry(pname, NULL);
Expand Down
8 changes: 8 additions & 0 deletions drivers/message/fusion/mptbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@
/* debug print string length used for events and iocstatus */
# define EVENT_DESCR_STR_SZ 100

#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */

#ifdef __KERNEL__ /* { */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

Expand Down Expand Up @@ -709,6 +711,12 @@ typedef struct _MPT_ADAPTER
struct workqueue_struct *fc_rescan_work_q;
struct scsi_cmnd **ScsiLookup;
spinlock_t scsi_lookup_lock;

char reset_work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *reset_work_q;
struct delayed_work fault_reset_work;
spinlock_t fault_reset_work_lock;

} MPT_ADAPTER;

/*
Expand Down

0 comments on commit d54d48b

Please sign in to comment.