aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Hancock <hancockr@shaw.ca>2007-01-23 21:09:02 -0500
committerJeff Garzik <jeff@garzik.org>2007-01-24 02:01:49 -0500
commitf740d1689d91415cfc749d17138a11ed03b7d38b (patch)
tree6c329d53cbb44e3d483cce99068a93b30409cbb8
parent82490c0937cb455e7e4150455ff52e89a9fc5ab8 (diff)
sata_nv: don't rely on NV_INT_DEV indication with ADMA
Several people reported issues with certain drive commands timing out on sata_nv controllers running in ADMA mode. The commands in question were non-DMA-mapped commands, usually FLUSH CACHE or FLUSH CACHE EXT. From experimentation it appears that the NV_INT_DEV indication isn't always set when a legitimate command completion interrupt is received on a legacy-mode command, at least not on these controllers in ADMA mode. When a command is pending on the port, force the flag on always in the irq_stat value before calling nv_host_intr so that the drive busy state is always checked by ata_host_intr. This also fixes some questionable code in nv_host_intr which called ata_check_status when a command was pending and ata_host_intr returned "unhandled". If the device interrupted at just the wrong time this could cause interrupts to be lost. Signed-off-by: Robert Hancock <hancockr@shaw.ca> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/sata_nv.c14
1 files changed, 6 insertions, 8 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index f6d498e1cf80..f7a963eb1f02 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -700,7 +700,6 @@ static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
700static int nv_host_intr(struct ata_port *ap, u8 irq_stat) 700static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
701{ 701{
702 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); 702 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
703 int handled;
704 703
705 /* freeze if hotplugged */ 704 /* freeze if hotplugged */
706 if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { 705 if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -719,13 +718,7 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
719 } 718 }
720 719
721 /* handle interrupt */ 720 /* handle interrupt */
722 handled = ata_host_intr(ap, qc); 721 return ata_host_intr(ap, qc);
723 if (unlikely(!handled)) {
724 /* spurious, clear it */
725 ata_check_status(ap);
726 }
727
728 return 1;
729} 722}
730 723
731static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) 724static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
@@ -752,6 +745,11 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
752 if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { 745 if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
753 u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) 746 u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804)
754 >> (NV_INT_PORT_SHIFT * i); 747 >> (NV_INT_PORT_SHIFT * i);
748 if(ata_tag_valid(ap->active_tag))
749 /** NV_INT_DEV indication seems unreliable at times
750 at least in ADMA mode. Force it on always when a
751 command is active, to prevent losing interrupts. */
752 irq_stat |= NV_INT_DEV;
755 handled += nv_host_intr(ap, irq_stat); 753 handled += nv_host_intr(ap, irq_stat);
756 continue; 754 continue;
757 } 755 }