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 | |
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')
-rw-r--r-- | drivers/scsi/libata-core.c | 1 | ||||
-rw-r--r-- | drivers/scsi/libata-eh.c | 38 | ||||
-rw-r--r-- | drivers/scsi/libata.h | 1 |
3 files changed, 40 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 11df827e166f..66df895c9617 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -5189,6 +5189,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, | |||
5189 | 5189 | ||
5190 | INIT_WORK(&ap->port_task, NULL, NULL); | 5190 | INIT_WORK(&ap->port_task, NULL, NULL); |
5191 | INIT_LIST_HEAD(&ap->eh_done_q); | 5191 | INIT_LIST_HEAD(&ap->eh_done_q); |
5192 | init_waitqueue_head(&ap->eh_wait_q); | ||
5192 | 5193 | ||
5193 | /* set cable type */ | 5194 | /* set cable type */ |
5194 | ap->cbl = ATA_CBL_NONE; | 5195 | ap->cbl = ATA_CBL_NONE; |
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 | * |
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index b76ad7d7062a..d56d9e1d73dc 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h | |||
@@ -103,6 +103,7 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); | |||
103 | /* libata-eh.c */ | 103 | /* libata-eh.c */ |
104 | extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); | 104 | extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); |
105 | extern void ata_scsi_error(struct Scsi_Host *host); | 105 | extern void ata_scsi_error(struct Scsi_Host *host); |
106 | extern void ata_port_wait_eh(struct ata_port *ap); | ||
106 | extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); | 107 | extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); |
107 | 108 | ||
108 | #endif /* __LIBATA_H__ */ | 109 | #endif /* __LIBATA_H__ */ |