From c6cf9e99d1de5ca6a08fb639bb73031ffe50d802 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 31 May 2006 18:27:27 +0900 Subject: [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 --- drivers/scsi/libata-eh.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/scsi/libata-eh.c') 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) ap->eh_context.i = ap->eh_info; memset(&ap->eh_info, 0, sizeof(ap->eh_info)); + ap->flags |= ATA_FLAG_EH_IN_PROGRESS; ap->flags &= ~ATA_FLAG_EH_PENDING; spin_unlock_irqrestore(hs_lock, flags); @@ -290,11 +291,48 @@ void ata_scsi_error(struct Scsi_Host *host) ata_port_printk(ap, KERN_INFO, "EH complete\n"); ap->flags &= ~ATA_FLAG_RECOVERED; + /* tell wait_eh that we're done */ + ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS; + wake_up_all(&ap->eh_wait_q); + spin_unlock_irqrestore(hs_lock, flags); DPRINTK("EXIT\n"); } +/** + * ata_port_wait_eh - Wait for the currently pending EH to complete + * @ap: Port to wait EH for + * + * Wait until the currently pending EH is complete. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_port_wait_eh(struct ata_port *ap) +{ + unsigned long flags; + DEFINE_WAIT(wait); + + retry: + spin_lock_irqsave(&ap->host_set->lock, flags); + + while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) { + prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + schedule(); + spin_lock_irqsave(&ap->host_set->lock, flags); + } + + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + /* make sure SCSI EH is complete */ + if (scsi_host_in_recovery(ap->host)) { + msleep(10); + goto retry; + } +} + /** * ata_qc_timeout - Handle timeout of queued command * @qc: Command that timed out -- cgit v1.2.3