aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKashyap, Desai <kashyap.desai@lsi.com>2009-08-07 10:07:59 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-08-13 17:30:23 -0400
commite4750c989f732555fca86dd73d488c79972362db (patch)
tree8987b1c48b6e987b000c2e114ea233aeacdd5e6d
parent6bd4e1e4d6023f4da069fd68729c502cc4e6dfd0 (diff)
[SCSI] mpt2sas: fix crash due to Watchdog is active while OS in standby mode
Fix oops ocurring at hibernation time. This oops was due to the firmware fault watchdog timer still running after we freed resources. To fix the issue we need to terminate the watchdog timer at hibernation time. Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c88
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c2
3 files changed, 64 insertions, 28 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index ed9965e4b96b..c29c4f9851b9 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -119,6 +119,64 @@ _base_fault_reset_work(struct work_struct *work)
119 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 119 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
120} 120}
121 121
122/**
123 * mpt2sas_base_start_watchdog - start the fault_reset_work_q
124 * @ioc: pointer to scsi command object
125 * Context: sleep.
126 *
127 * Return nothing.
128 */
129void
130mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc)
131{
132 unsigned long flags;
133
134 if (ioc->fault_reset_work_q)
135 return;
136
137 /* initialize fault polling */
138 INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
139 snprintf(ioc->fault_reset_work_q_name,
140 sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
141 ioc->fault_reset_work_q =
142 create_singlethread_workqueue(ioc->fault_reset_work_q_name);
143 if (!ioc->fault_reset_work_q) {
144 printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n",
145 ioc->name, __func__, __LINE__);
146 return;
147 }
148 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
149 if (ioc->fault_reset_work_q)
150 queue_delayed_work(ioc->fault_reset_work_q,
151 &ioc->fault_reset_work,
152 msecs_to_jiffies(FAULT_POLLING_INTERVAL));
153 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
154}
155
156/**
157 * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q
158 * @ioc: pointer to scsi command object
159 * Context: sleep.
160 *
161 * Return nothing.
162 */
163void
164mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc)
165{
166 unsigned long flags;
167 struct workqueue_struct *wq;
168
169 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
170 wq = ioc->fault_reset_work_q;
171 ioc->fault_reset_work_q = NULL;
172 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
173 if (wq) {
174 if (!cancel_delayed_work(&ioc->fault_reset_work))
175 flush_workqueue(wq);
176 destroy_workqueue(wq);
177 }
178}
179
122#ifdef CONFIG_SCSI_MPT2SAS_LOGGING 180#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
123/** 181/**
124 * _base_sas_ioc_info - verbose translation of the ioc status 182 * _base_sas_ioc_info - verbose translation of the ioc status
@@ -3209,7 +3267,6 @@ int
3209mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) 3267mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
3210{ 3268{
3211 int r, i; 3269 int r, i;
3212 unsigned long flags;
3213 3270
3214 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, 3271 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
3215 __func__)); 3272 __func__));
@@ -3292,23 +3349,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
3292 if (r) 3349 if (r)
3293 goto out_free_resources; 3350 goto out_free_resources;
3294 3351
3295 /* initialize fault polling */ 3352 mpt2sas_base_start_watchdog(ioc);
3296 INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
3297 snprintf(ioc->fault_reset_work_q_name,
3298 sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
3299 ioc->fault_reset_work_q =
3300 create_singlethread_workqueue(ioc->fault_reset_work_q_name);
3301 if (!ioc->fault_reset_work_q) {
3302 printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n",
3303 ioc->name, __func__, __LINE__);
3304 goto out_free_resources;
3305 }
3306 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
3307 if (ioc->fault_reset_work_q)
3308 queue_delayed_work(ioc->fault_reset_work_q,
3309 &ioc->fault_reset_work,
3310 msecs_to_jiffies(FAULT_POLLING_INTERVAL));
3311 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
3312 return 0; 3353 return 0;
3313 3354
3314 out_free_resources: 3355 out_free_resources:
@@ -3341,20 +3382,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
3341void 3382void
3342mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) 3383mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
3343{ 3384{
3344 unsigned long flags;
3345 struct workqueue_struct *wq;
3346 3385
3347 dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, 3386 dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
3348 __func__)); 3387 __func__));
3349 3388
3350 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 3389 mpt2sas_base_stop_watchdog(ioc);
3351 wq = ioc->fault_reset_work_q;
3352 ioc->fault_reset_work_q = NULL;
3353 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
3354 if (!cancel_delayed_work(&ioc->fault_reset_work))
3355 flush_workqueue(wq);
3356 destroy_workqueue(wq);
3357
3358 mpt2sas_base_free_resources(ioc); 3390 mpt2sas_base_free_resources(ioc);
3359 _base_release_memory_pools(ioc); 3391 _base_release_memory_pools(ioc);
3360 kfree(ioc->pfacts); 3392 kfree(ioc->pfacts);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 286c185fa9e4..a29935726e7a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -673,6 +673,8 @@ typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
673 673
674/* base shared API */ 674/* base shared API */
675extern struct list_head mpt2sas_ioc_list; 675extern struct list_head mpt2sas_ioc_list;
676void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc);
677void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc);
676 678
677int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc); 679int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc);
678void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc); 680void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 25c8d8294af6..2e9a4445596f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -5824,6 +5824,7 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
5824 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); 5824 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5825 u32 device_state; 5825 u32 device_state;
5826 5826
5827 mpt2sas_base_stop_watchdog(ioc);
5827 flush_scheduled_work(); 5828 flush_scheduled_work();
5828 scsi_block_requests(shost); 5829 scsi_block_requests(shost);
5829 device_state = pci_choose_state(pdev, state); 5830 device_state = pci_choose_state(pdev, state);
@@ -5866,6 +5867,7 @@ _scsih_resume(struct pci_dev *pdev)
5866 5867
5867 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); 5868 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
5868 scsi_unblock_requests(shost); 5869 scsi_unblock_requests(shost);
5870 mpt2sas_base_start_watchdog(ioc);
5869 return 0; 5871 return 0;
5870} 5872}
5871#endif /* CONFIG_PM */ 5873#endif /* CONFIG_PM */