diff options
Diffstat (limited to 'drivers/message/fusion/mptbase.c')
-rw-r--r-- | drivers/message/fusion/mptbase.c | 86 |
1 files changed, 86 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 | **/ | ||
261 | static void | ||
262 | mpt_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); |