diff options
author | Tejun Heo <htejun@gmail.com> | 2006-05-31 05:27:27 -0400 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-05-31 05:27:27 -0400 |
commit | c6cf9e99d1de5ca6a08fb639bb73031ffe50d802 (patch) | |
tree | 555a47d45b5b80ef14ff53ccb4c6d1439460e251 /drivers/scsi/libata-eh.c | |
parent | 7395acb2c840fd4d0cacc91d6fb71440057141ab (diff) |
[PATCH] libata: implement ata_eh_wait()
Implement ata_eh_wait(). On return from this function, it's
guaranteed that the EH which was pending or in progress when the
function was called is complete - including the tailing part of SCSI
EH. This will be used by hotplug and others to synchronize with EH.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r-- | drivers/scsi/libata-eh.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index b88f492eab12..9173d8f2ce5d 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -237,6 +237,7 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
237 | ap->eh_context.i = ap->eh_info; | 237 | ap->eh_context.i = ap->eh_info; |
238 | memset(&ap->eh_info, 0, sizeof(ap->eh_info)); | 238 | memset(&ap->eh_info, 0, sizeof(ap->eh_info)); |
239 | 239 | ||
240 | ap->flags |= ATA_FLAG_EH_IN_PROGRESS; | ||
240 | ap->flags &= ~ATA_FLAG_EH_PENDING; | 241 | ap->flags &= ~ATA_FLAG_EH_PENDING; |
241 | 242 | ||
242 | spin_unlock_irqrestore(hs_lock, flags); | 243 | spin_unlock_irqrestore(hs_lock, flags); |
@@ -290,12 +291,49 @@ void ata_scsi_error(struct Scsi_Host *host) | |||
290 | ata_port_printk(ap, KERN_INFO, "EH complete\n"); | 291 | ata_port_printk(ap, KERN_INFO, "EH complete\n"); |
291 | ap->flags &= ~ATA_FLAG_RECOVERED; | 292 | ap->flags &= ~ATA_FLAG_RECOVERED; |
292 | 293 | ||
294 | /* tell wait_eh that we're done */ | ||
295 | ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS; | ||
296 | wake_up_all(&ap->eh_wait_q); | ||
297 | |||
293 | spin_unlock_irqrestore(hs_lock, flags); | 298 | spin_unlock_irqrestore(hs_lock, flags); |
294 | 299 | ||
295 | DPRINTK("EXIT\n"); | 300 | DPRINTK("EXIT\n"); |
296 | } | 301 | } |
297 | 302 | ||
298 | /** | 303 | /** |
304 | * ata_port_wait_eh - Wait for the currently pending EH to complete | ||
305 | * @ap: Port to wait EH for | ||
306 | * | ||
307 | * Wait until the currently pending EH is complete. | ||
308 | * | ||
309 | * LOCKING: | ||
310 | * Kernel thread context (may sleep). | ||
311 | */ | ||
312 | void ata_port_wait_eh(struct ata_port *ap) | ||
313 | { | ||
314 | unsigned long flags; | ||
315 | DEFINE_WAIT(wait); | ||
316 | |||
317 | retry: | ||
318 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
319 | |||
320 | while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) { | ||
321 | prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE); | ||
322 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
323 | schedule(); | ||
324 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
325 | } | ||
326 | |||
327 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
328 | |||
329 | /* make sure SCSI EH is complete */ | ||
330 | if (scsi_host_in_recovery(ap->host)) { | ||
331 | msleep(10); | ||
332 | goto retry; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /** | ||
299 | * ata_qc_timeout - Handle timeout of queued command | 337 | * ata_qc_timeout - Handle timeout of queued command |
300 | * @qc: Command that timed out | 338 | * @qc: Command that timed out |
301 | * | 339 | * |