aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-31 05:27:27 -0400
committerTejun Heo <htejun@gmail.com>2006-05-31 05:27:27 -0400
commitc6cf9e99d1de5ca6a08fb639bb73031ffe50d802 (patch)
tree555a47d45b5b80ef14ff53ccb4c6d1439460e251
parent7395acb2c840fd4d0cacc91d6fb71440057141ab (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>
-rw-r--r--drivers/scsi/libata-core.c1
-rw-r--r--drivers/scsi/libata-eh.c38
-rw-r--r--drivers/scsi/libata.h1
-rw-r--r--include/linux/libata.h2
4 files changed, 42 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 11df827e166..66df895c961 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 b88f492eab1..9173d8f2ce5 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 */
312void 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 b76ad7d7062..d56d9e1d73d 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 */
104extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); 104extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
105extern void ata_scsi_error(struct Scsi_Host *host); 105extern void ata_scsi_error(struct Scsi_Host *host);
106extern void ata_port_wait_eh(struct ata_port *ap);
106extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); 107extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
107 108
108#endif /* __LIBATA_H__ */ 109#endif /* __LIBATA_H__ */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 3f9c65f1aaf..2eb5828839e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -157,6 +157,7 @@ enum {
157 ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */ 157 ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
158 158
159 ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */ 159 ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
160 ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
160 ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */ 161 ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
161 ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */ 162 ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
162 163
@@ -490,6 +491,7 @@ struct ata_port {
490 491
491 u32 msg_enable; 492 u32 msg_enable;
492 struct list_head eh_done_q; 493 struct list_head eh_done_q;
494 wait_queue_head_t eh_wait_q;
493 495
494 void *private_data; 496 void *private_data;
495 497