@@ -253,6 +253,55 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
253253 return 0 ;
254254}
255255
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+
256305/*
257306 * Process turbo (context) reply...
258307 */
@@ -1616,6 +1665,22 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
16161665 /* Find lookup slot. */
16171666 INIT_LIST_HEAD (& ioc -> list );
16181667
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+
16191684 dinitprintk (ioc , printk (MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n" ,
16201685 ioc -> name , & ioc -> facts , & ioc -> pfacts [0 ]));
16211686
@@ -1722,6 +1787,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
17221787 iounmap (ioc -> memmap );
17231788 if (r != -5 )
17241789 pci_release_selected_regions (pdev , ioc -> bars );
1790+
1791+ destroy_workqueue (ioc -> reset_work_q );
1792+ ioc -> reset_work_q = NULL ;
1793+
17251794 kfree (ioc );
17261795 pci_set_drvdata (pdev , NULL );
17271796 return r ;
@@ -1754,6 +1823,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
17541823 }
17551824#endif
17561825
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+
17571830 return 0 ;
17581831}
17591832
@@ -1769,6 +1842,19 @@ mpt_detach(struct pci_dev *pdev)
17691842 MPT_ADAPTER * ioc = pci_get_drvdata (pdev );
17701843 char pname [32 ];
17711844 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+
17721858
17731859 sprintf (pname , MPT_PROCFS_MPTBASEDIR "/%s/summary" , ioc -> name );
17741860 remove_proc_entry (pname , NULL );
0 commit comments