aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrakash, Sathya <sathya.prakash@lsi.com>2008-05-20 15:32:18 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 09:22:15 -0400
commitd54d48b80fb523ce1b1a644e4876b08835ad757f (patch)
treea6dd5fe8e71dd95eb0720d0d5ebeb70226296423
parentcc4724492ddf920475ad7f12bfcb81ffca16f777 (diff)
[SCSI] mpt fusion : Adding FAULT Reset polling work
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>
-rw-r--r--drivers/message/fusion/mptbase.c86
-rw-r--r--drivers/message/fusion/mptbase.h8
2 files changed, 94 insertions, 0 deletions
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 30a800effe51..9bc35617b871 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -253,6 +253,55 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
253 return 0; 253 return 0;
254} 254}
255 255
256/**
257 * mpt_fault_reset_work - work performed on workq after ioc fault
258 * @work: input argument, used to derive ioc
259 *
260**/
261static void
262mpt_fault_reset_work(struct work_struct *work)
263{
264 MPT_ADAPTER *ioc =
265 container_of(work, MPT_ADAPTER, fault_reset_work.work);
266 u32 ioc_raw_state;
267 int rc;
268 unsigned long flags;
269
270 if (ioc->diagPending || !ioc->active)
271 goto out;
272
273 ioc_raw_state = mpt_GetIocState(ioc, 0);
274 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
275 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
276 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
277 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
278 ioc->name, __FUNCTION__);
279 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
280 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
281 __FUNCTION__, (rc == 0) ? "success" : "failed");
282 ioc_raw_state = mpt_GetIocState(ioc, 0);
283 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
284 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
285 "reset (%04xh)\n", ioc->name, ioc_raw_state &
286 MPI_DOORBELL_DATA_MASK);
287 }
288
289 out:
290 /*
291 * Take turns polling alternate controller
292 */
293 if (ioc->alt_ioc)
294 ioc = ioc->alt_ioc;
295
296 /* rearm the timer */
297 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
298 if (ioc->reset_work_q)
299 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
300 msecs_to_jiffies(MPT_POLLING_INTERVAL));
301 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
302}
303
304
256/* 305/*
257 * Process turbo (context) reply... 306 * Process turbo (context) reply...
258 */ 307 */
@@ -1616,6 +1665,22 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
1616 /* Find lookup slot. */ 1665 /* Find lookup slot. */
1617 INIT_LIST_HEAD(&ioc->list); 1666 INIT_LIST_HEAD(&ioc->list);
1618 1667
1668
1669 /* Initialize workqueue */
1670 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1671 spin_lock_init(&ioc->fault_reset_work_lock);
1672
1673 snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
1674 ioc->reset_work_q =
1675 create_singlethread_workqueue(ioc->reset_work_q_name);
1676 if (!ioc->reset_work_q) {
1677 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1678 ioc->name);
1679 pci_release_selected_regions(pdev, ioc->bars);
1680 kfree(ioc);
1681 return -ENOMEM;
1682 }
1683
1619 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", 1684 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1620 ioc->name, &ioc->facts, &ioc->pfacts[0])); 1685 ioc->name, &ioc->facts, &ioc->pfacts[0]));
1621 1686
@@ -1722,6 +1787,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
1722 iounmap(ioc->memmap); 1787 iounmap(ioc->memmap);
1723 if (r != -5) 1788 if (r != -5)
1724 pci_release_selected_regions(pdev, ioc->bars); 1789 pci_release_selected_regions(pdev, ioc->bars);
1790
1791 destroy_workqueue(ioc->reset_work_q);
1792 ioc->reset_work_q = NULL;
1793
1725 kfree(ioc); 1794 kfree(ioc);
1726 pci_set_drvdata(pdev, NULL); 1795 pci_set_drvdata(pdev, NULL);
1727 return r; 1796 return r;
@@ -1754,6 +1823,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
1754 } 1823 }
1755#endif 1824#endif
1756 1825
1826 if (!ioc->alt_ioc)
1827 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1828 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1829
1757 return 0; 1830 return 0;
1758} 1831}
1759 1832
@@ -1769,6 +1842,19 @@ mpt_detach(struct pci_dev *pdev)
1769 MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 1842 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1770 char pname[32]; 1843 char pname[32];
1771 u8 cb_idx; 1844 u8 cb_idx;
1845 unsigned long flags;
1846 struct workqueue_struct *wq;
1847
1848 /*
1849 * Stop polling ioc for fault condition
1850 */
1851 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
1852 wq = ioc->reset_work_q;
1853 ioc->reset_work_q = NULL;
1854 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
1855 cancel_delayed_work(&ioc->fault_reset_work);
1856 destroy_workqueue(wq);
1857
1772 1858
1773 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); 1859 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
1774 remove_proc_entry(pname, NULL); 1860 remove_proc_entry(pname, NULL);
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 7496793db2c8..6adab648dbb9 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -176,6 +176,8 @@
176/* debug print string length used for events and iocstatus */ 176/* debug print string length used for events and iocstatus */
177# define EVENT_DESCR_STR_SZ 100 177# define EVENT_DESCR_STR_SZ 100
178 178
179#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */
180
179#ifdef __KERNEL__ /* { */ 181#ifdef __KERNEL__ /* { */
180/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
181 183
@@ -709,6 +711,12 @@ typedef struct _MPT_ADAPTER
709 struct workqueue_struct *fc_rescan_work_q; 711 struct workqueue_struct *fc_rescan_work_q;
710 struct scsi_cmnd **ScsiLookup; 712 struct scsi_cmnd **ScsiLookup;
711 spinlock_t scsi_lookup_lock; 713 spinlock_t scsi_lookup_lock;
714
715 char reset_work_q_name[KOBJ_NAME_LEN];
716 struct workqueue_struct *reset_work_q;
717 struct delayed_work fault_reset_work;
718 spinlock_t fault_reset_work_lock;
719
712} MPT_ADAPTER; 720} MPT_ADAPTER;
713 721
714/* 722/*