diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/message/fusion/mptbase.c | 86 | ||||
| -rw-r--r-- | drivers/message/fusion/mptbase.h | 8 |
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 | **/ | ||
| 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); |
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 | /* |
