提交 dafadcde 编写于 作者: T Tejun Heo

[PATCH] libata-eh-fw: implement new EH scheduling from PIO

PIO executes without holding host_set lock, so it cannot be
synchronized using the same mechanism as interrupt driven execution.
port_task framework makes sure that EH is not entered until PIO task
is flushed, so PIO task can be sure the qc in progress won't go away
underneath it.  One thing it cannot be sure of is whether the qc has
already been scheduled for EH by another exception condition while
host_set lock was released.

This patch makes ata_poll_qc-complete() handle such conditions
properly and make it freeze the port if HSM violation is detected
during PIO execution.
Signed-off-by: NTejun Heo <htejun@gmail.com>
上级 e3180499
...@@ -3430,16 +3430,31 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) ...@@ -3430,16 +3430,31 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
* LOCKING: * LOCKING:
* None. (grabs host lock) * None. (grabs host lock)
*/ */
void ata_poll_qc_complete(struct ata_queued_cmd *qc) void ata_poll_qc_complete(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ap->host_set->lock, flags); spin_lock_irqsave(&ap->host_set->lock, flags);
ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap); if (ap->ops->error_handler) {
ata_qc_complete(qc); /* EH might have kicked in while host_set lock is released */
qc = ata_qc_from_tag(ap, qc->tag);
if (qc) {
if (!(qc->err_mask & AC_ERR_HSM)) {
ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc);
} else
ata_port_freeze(ap);
}
} else {
/* old EH */
ap->flags &= ~ATA_FLAG_NOINTR;
ata_irq_on(ap);
ata_qc_complete(qc);
}
spin_unlock_irqrestore(&ap->host_set->lock, flags); spin_unlock_irqrestore(&ap->host_set->lock, flags);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册