aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/ahci.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-12-06 22:46:23 -0500
committerJeff Garzik <jeff@garzik.org>2007-12-07 15:27:54 -0500
commit459ad68893a84fb0881e57919340b97edbbc3dc7 (patch)
tree04e7d419836214e3cb8a21f97a79697d0d9f0035 /drivers/ata/ahci.c
parentc4f7792c021cda9bbf65d0bc2253a593fd652b91 (diff)
libata: kill spurious NCQ completion detection
Spurious NCQ completion detection implemented in ahci was incorrect. On AHCI receving and processing FISes and raising interrupts are not interlocked and spurious interrupts are expected. For example, if an interrupt occurs while interrupt handler is running and the running interrupt handler handles the event the new IRQ indicated, after IRQ handler finishes, it will be executed again because IRQ pending bit is set by the new interrupt but there won't be anything to process. Please read the following message for more information. http://article.gmane.org/gmane.linux.ide/26012 This patch... * Removes all spurious IRQ whining from ahci. Spurious NCQ completion detection was completely wrong. Spurious D2H Register FIS taught us that some early drives send spurious D2H Register FIS with I bit set while NCQ commands are in progress but none of recent drives does that and even the ones which show such behavior can do NCQ fine. * Kills all NCQ blacklist entries which were added because of spurious NCQ completions. I tracked down each commit and verified all removed ones are actually added because of spurious completions. WD740ADFD-00NLR1 wasn't deleted but moved upward because the drive not only had spurious NCQ completions but also is slow on sequential data transfers if NCQ is enabled. Maxtor 7V300F0 was added by 0e3dbc01d53940fe10e5a5cfec15ede3e929c918 from Alan Cox. I can only find evidences that the drive only had troubles with spuruious completions by searching the mailing list. This entry needs to be verified and removed if it doesn't have other NCQ related problems. Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r--drivers/ata/ahci.c74
1 files changed, 3 insertions, 71 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index cb7853b7335d..54f38c21dd95 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1640,7 +1640,7 @@ static void ahci_port_intr(struct ata_port *ap)
1640 struct ahci_host_priv *hpriv = ap->host->private_data; 1640 struct ahci_host_priv *hpriv = ap->host->private_data;
1641 int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING); 1641 int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
1642 u32 status, qc_active; 1642 u32 status, qc_active;
1643 int rc, known_irq = 0; 1643 int rc;
1644 1644
1645 status = readl(port_mmio + PORT_IRQ_STAT); 1645 status = readl(port_mmio + PORT_IRQ_STAT);
1646 writel(status, port_mmio + PORT_IRQ_STAT); 1646 writel(status, port_mmio + PORT_IRQ_STAT);
@@ -1698,80 +1698,12 @@ static void ahci_port_intr(struct ata_port *ap)
1698 1698
1699 rc = ata_qc_complete_multiple(ap, qc_active, NULL); 1699 rc = ata_qc_complete_multiple(ap, qc_active, NULL);
1700 1700
1701 /* If resetting, spurious or invalid completions are expected, 1701 /* while resetting, invalid completions are expected */
1702 * return unconditionally. 1702 if (unlikely(rc < 0 && !resetting)) {
1703 */
1704 if (resetting)
1705 return;
1706
1707 if (rc > 0)
1708 return;
1709 if (rc < 0) {
1710 ehi->err_mask |= AC_ERR_HSM; 1703 ehi->err_mask |= AC_ERR_HSM;
1711 ehi->action |= ATA_EH_SOFTRESET; 1704 ehi->action |= ATA_EH_SOFTRESET;
1712 ata_port_freeze(ap); 1705 ata_port_freeze(ap);
1713 return;
1714 }
1715
1716 /* hmmm... a spurious interrupt */
1717
1718 /* if !NCQ, ignore. No modern ATA device has broken HSM
1719 * implementation for non-NCQ commands.
1720 */
1721 if (!ap->link.sactive)
1722 return;
1723
1724 if (status & PORT_IRQ_D2H_REG_FIS) {
1725 if (!pp->ncq_saw_d2h)
1726 ata_port_printk(ap, KERN_INFO,
1727 "D2H reg with I during NCQ, "
1728 "this message won't be printed again\n");
1729 pp->ncq_saw_d2h = 1;
1730 known_irq = 1;
1731 }
1732
1733 if (status & PORT_IRQ_DMAS_FIS) {
1734 if (!pp->ncq_saw_dmas)
1735 ata_port_printk(ap, KERN_INFO,
1736 "DMAS FIS during NCQ, "
1737 "this message won't be printed again\n");
1738 pp->ncq_saw_dmas = 1;
1739 known_irq = 1;
1740 } 1706 }
1741
1742 if (status & PORT_IRQ_SDB_FIS) {
1743 const __le32 *f = pp->rx_fis + RX_FIS_SDB;
1744
1745 if (le32_to_cpu(f[1])) {
1746 /* SDB FIS containing spurious completions
1747 * might be dangerous, whine and fail commands
1748 * with HSM violation. EH will turn off NCQ
1749 * after several such failures.
1750 */
1751 ata_ehi_push_desc(ehi,
1752 "spurious completions during NCQ "
1753 "issue=0x%x SAct=0x%x FIS=%08x:%08x",
1754 readl(port_mmio + PORT_CMD_ISSUE),
1755 readl(port_mmio + PORT_SCR_ACT),
1756 le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1757 ehi->err_mask |= AC_ERR_HSM;
1758 ehi->action |= ATA_EH_SOFTRESET;
1759 ata_port_freeze(ap);
1760 } else {
1761 if (!pp->ncq_saw_sdb)
1762 ata_port_printk(ap, KERN_INFO,
1763 "spurious SDB FIS %08x:%08x during NCQ, "
1764 "this message won't be printed again\n",
1765 le32_to_cpu(f[0]), le32_to_cpu(f[1]));
1766 pp->ncq_saw_sdb = 1;
1767 }
1768 known_irq = 1;
1769 }
1770
1771 if (!known_irq)
1772 ata_port_printk(ap, KERN_INFO, "spurious interrupt "
1773 "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
1774 status, ap->link.active_tag, ap->link.sactive);
1775} 1707}
1776 1708
1777static void ahci_irq_clear(struct ata_port *ap) 1709static void ahci_irq_clear(struct ata_port *ap)