diff options
-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 | ||||
-rw-r--r-- | include/linux/libata.h | 2 |
4 files changed, 42 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__ */ |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 3f9c65f1aafa..2eb5828839e4 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 | ||