diff options
Diffstat (limited to 'drivers/message/fusion/mptbase.c')
| -rw-r--r-- | drivers/message/fusion/mptbase.c | 91 | 
1 files changed, 88 insertions, 3 deletions
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index d40d6d15ae20..75e599b85b64 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5,7 +5,7 @@   *      For use with LSI PCI chip/adapter(s)   *      running LSI Fusion MPT (Message Passing Technology) firmware.   * - *  Copyright (c) 1999-2007 LSI Corporation + *  Copyright (c) 1999-2008 LSI Corporation   *  (mailto:[email protected])   *   */ @@ -103,7 +103,7 @@ static int mfcounter = 0;   *  Public data...   */ -struct proc_dir_entry *mpt_proc_root_dir; +static struct proc_dir_entry *mpt_proc_root_dir;  #define WHOINIT_UNKNOWN		0xAA @@ -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...   */ @@ -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])); @@ -1727,6 +1792,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; @@ -1759,6 +1828,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;  } @@ -1774,6 +1847,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); @@ -7456,7 +7542,6 @@ EXPORT_SYMBOL(mpt_resume);  EXPORT_SYMBOL(mpt_suspend);  #endif  EXPORT_SYMBOL(ioc_list); -EXPORT_SYMBOL(mpt_proc_root_dir);  EXPORT_SYMBOL(mpt_register);  EXPORT_SYMBOL(mpt_deregister);  EXPORT_SYMBOL(mpt_event_register);  |