aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-11-14 13:56:37 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-11-14 13:56:37 -0500
commitad36d1a533da91d3448029b4da1113c5b880f25d (patch)
tree00e66685a3572daed99fa8def4580ea6022b6db7
parent4ba529a8a39e15688b6a3d31b11930d1f8a1edad (diff)
[libata ahci] error handling fixes
Needed to get ATAPI working. - dump hardware error bits, if hardware signals an error - only reset hardware during timeout if a command was active - call ata_qc_complete() with a fine-grained error mask. Needed so that atapi_qc_complete() can distinguish between device errors and other errors.
-rw-r--r--drivers/scsi/ahci.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 4e96ec5f2ff..c710a7def7a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -603,7 +603,12 @@ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
writel(tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
- printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
+ printk(KERN_WARNING "ata%u: error occurred, port reset (%s%s%s%s)\n",
+ ap->id,
+ irq_stat & PORT_IRQ_TF_ERR ? "taskf " : "",
+ irq_stat & PORT_IRQ_HBUS_ERR ? "hbus " : "",
+ irq_stat & PORT_IRQ_HBUS_DATA_ERR ? "hbus_data " : "",
+ irq_stat & PORT_IRQ_IF_ERR ? "if " : "");
}
static void ahci_eng_timeout(struct ata_port *ap)
@@ -618,13 +623,13 @@ static void ahci_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host_set->lock, flags);
- ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
-
qc = ata_qc_from_tag(ap, ap->active_tag);
if (!qc) {
printk(KERN_ERR "ata%u: BUG: timeout without command\n",
ap->id);
} else {
+ ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
+
/* hack alert! We cannot use the supplied completion
* function from inside the ->eh_strategy_handler() thread.
* libata is the only user of ->eh_strategy_handler() in
@@ -659,9 +664,18 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
}
if (status & PORT_IRQ_FATAL) {
- ahci_intr_error(ap, status);
+ unsigned int err_mask;
+ if (status & PORT_IRQ_TF_ERR)
+ err_mask = AC_ERR_DEV;
+ else if (status & PORT_IRQ_IF_ERR)
+ err_mask = AC_ERR_ATA_BUS;
+ else
+ err_mask = AC_ERR_HOST_BUS;
+
+ if (err_mask != AC_ERR_DEV)
+ ahci_intr_error(ap, status);
if (qc)
- ata_qc_complete(qc, AC_ERR_OTHER);
+ ata_qc_complete(qc, err_mask);
}
return 1;