Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Robert Hancock and committed by
Jeff Garzik
f740d168 82490c09

+6 -8
+6 -8
drivers/ata/sata_nv.c
··· 700 700 static int nv_host_intr(struct ata_port *ap, u8 irq_stat) 701 701 { 702 702 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); 703 - int handled; 704 703 705 704 /* freeze if hotplugged */ 706 705 if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { ··· 718 719 } 719 720 720 721 /* handle interrupt */ 721 - handled = ata_host_intr(ap, qc); 722 - if (unlikely(!handled)) { 723 - /* spurious, clear it */ 724 - ata_check_status(ap); 725 - } 726 - 727 - return 1; 722 + return ata_host_intr(ap, qc); 728 723 } 729 724 730 725 static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) ··· 745 752 if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { 746 753 u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) 747 754 >> (NV_INT_PORT_SHIFT * i); 755 + if(ata_tag_valid(ap->active_tag)) 756 + /** NV_INT_DEV indication seems unreliable at times 757 + at least in ADMA mode. Force it on always when a 758 + command is active, to prevent losing interrupts. */ 759 + irq_stat |= NV_INT_DEV; 748 760 handled += nv_host_intr(ap, irq_stat); 749 761 continue; 750 762 }