summary refs log tree commit diff
path: root/drivers/scsi/ahci.c
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 /drivers/scsi/ahci.c
parent4ba529a8a39e15688b6a3d31b11930d1f8a1edad (diff)
downloadlinux-ad36d1a533da91d3448029b4da1113c5b880f25d.tar.gz
[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.
Diffstat (limited to 'drivers/scsi/ahci.c')
-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 4e96ec5f2ff9..c710a7def7a7 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;