[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>
This commit is contained in:
parent
7395acb2c8
commit
c6cf9e99d1
@ -5189,6 +5189,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
|
|||||||
|
|
||||||
INIT_WORK(&ap->port_task, NULL, NULL);
|
INIT_WORK(&ap->port_task, NULL, NULL);
|
||||||
INIT_LIST_HEAD(&ap->eh_done_q);
|
INIT_LIST_HEAD(&ap->eh_done_q);
|
||||||
|
init_waitqueue_head(&ap->eh_wait_q);
|
||||||
|
|
||||||
/* set cable type */
|
/* set cable type */
|
||||||
ap->cbl = ATA_CBL_NONE;
|
ap->cbl = ATA_CBL_NONE;
|
||||||
|
@ -237,6 +237,7 @@ void ata_scsi_error(struct Scsi_Host *host)
|
|||||||
ap->eh_context.i = ap->eh_info;
|
ap->eh_context.i = ap->eh_info;
|
||||||
memset(&ap->eh_info, 0, sizeof(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;
|
ap->flags &= ~ATA_FLAG_EH_PENDING;
|
||||||
|
|
||||||
spin_unlock_irqrestore(hs_lock, flags);
|
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");
|
ata_port_printk(ap, KERN_INFO, "EH complete\n");
|
||||||
ap->flags &= ~ATA_FLAG_RECOVERED;
|
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);
|
spin_unlock_irqrestore(hs_lock, flags);
|
||||||
|
|
||||||
DPRINTK("EXIT\n");
|
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
|
* ata_qc_timeout - Handle timeout of queued command
|
||||||
* @qc: Command that timed out
|
* @qc: Command that timed out
|
||||||
|
@ -103,6 +103,7 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
|
|||||||
/* libata-eh.c */
|
/* libata-eh.c */
|
||||||
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
|
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
|
||||||
extern void ata_scsi_error(struct Scsi_Host *host);
|
extern void ata_scsi_error(struct Scsi_Host *host);
|
||||||
|
extern void ata_port_wait_eh(struct ata_port *ap);
|
||||||
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
|
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
|
||||||
|
|
||||||
#endif /* __LIBATA_H__ */
|
#endif /* __LIBATA_H__ */
|
||||||
|
@ -157,6 +157,7 @@ enum {
|
|||||||
ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
|
ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
|
||||||
|
|
||||||
ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
|
ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
|
||||||
|
ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
|
||||||
ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
|
ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
|
||||||
ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
|
ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
|
||||||
|
|
||||||
@ -490,6 +491,7 @@ struct ata_port {
|
|||||||
|
|
||||||
u32 msg_enable;
|
u32 msg_enable;
|
||||||
struct list_head eh_done_q;
|
struct list_head eh_done_q;
|
||||||
|
wait_queue_head_t eh_wait_q;
|
||||||
|
|
||||||
void *private_data;
|
void *private_data;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user