Skip to content

Commit 890e1e5

Browse files
Szuying Chengregkh
Szuying Chen
authored andcommitted
ata: libahci: clear pending interrupt status
commit 737dd81 upstream. When a CRC error occurs, the HBA asserts an interrupt to indicate an interface fatal error (PxIS.IFS). The ISR clears PxIE and PxIS, then does error recovery. If the adapter receives another SDB FIS with an error (PxIS.TFES) from the device before the start of the EH recovery process, the interrupt signaling the new SDB cannot be serviced as PxIE was cleared already. This in turn results in the HBA inability to issue any command during the error recovery process after setting PxCMD.ST to 1 because PxIS.TFES is still set. According to AHCI 1.3.1 specifications section 6.2.2, fatal errors notified by setting PxIS.HBFS, PxIS.HBDS, PxIS.IFS or PxIS.TFES will cause the HBA to enter the ERR:Fatal state. In this state, the HBA shall not issue any new commands. To avoid this situation, introduce the function ahci_port_clear_pending_irq() to clear pending interrupts before executing a COMRESET. This follows the AHCI 1.3.1 - section 6.2.2.2 specification. Signed-off-by: Szuying Chen <Chloe_Chen@asmedia.com.tw> Fixes: e0bfd14 ("[PATCH] ahci: stop engine during hard reset") Cc: stable@vger.kernel.org Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com> Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a3517ee commit 890e1e5

File tree

1 file changed

+23
-12
lines changed

1 file changed

+23
-12
lines changed

drivers/ata/libahci.c

+23-12
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,26 @@ static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
12551255
return sprintf(buf, "%d\n", emp->blink_policy);
12561256
}
12571257

1258+
static void ahci_port_clear_pending_irq(struct ata_port *ap)
1259+
{
1260+
struct ahci_host_priv *hpriv = ap->host->private_data;
1261+
void __iomem *port_mmio = ahci_port_base(ap);
1262+
u32 tmp;
1263+
1264+
/* clear SError */
1265+
tmp = readl(port_mmio + PORT_SCR_ERR);
1266+
dev_dbg(ap->host->dev, "PORT_SCR_ERR 0x%x\n", tmp);
1267+
writel(tmp, port_mmio + PORT_SCR_ERR);
1268+
1269+
/* clear port IRQ */
1270+
tmp = readl(port_mmio + PORT_IRQ_STAT);
1271+
dev_dbg(ap->host->dev, "PORT_IRQ_STAT 0x%x\n", tmp);
1272+
if (tmp)
1273+
writel(tmp, port_mmio + PORT_IRQ_STAT);
1274+
1275+
writel(1 << ap->port_no, hpriv->mmio + HOST_IRQ_STAT);
1276+
}
1277+
12581278
static void ahci_port_init(struct device *dev, struct ata_port *ap,
12591279
int port_no, void __iomem *mmio,
12601280
void __iomem *port_mmio)
@@ -1269,18 +1289,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
12691289
if (rc)
12701290
dev_warn(dev, "%s (%d)\n", emsg, rc);
12711291

1272-
/* clear SError */
1273-
tmp = readl(port_mmio + PORT_SCR_ERR);
1274-
dev_dbg(dev, "PORT_SCR_ERR 0x%x\n", tmp);
1275-
writel(tmp, port_mmio + PORT_SCR_ERR);
1276-
1277-
/* clear port IRQ */
1278-
tmp = readl(port_mmio + PORT_IRQ_STAT);
1279-
dev_dbg(dev, "PORT_IRQ_STAT 0x%x\n", tmp);
1280-
if (tmp)
1281-
writel(tmp, port_mmio + PORT_IRQ_STAT);
1282-
1283-
writel(1 << port_no, mmio + HOST_IRQ_STAT);
1292+
ahci_port_clear_pending_irq(ap);
12841293

12851294
/* mark esata ports */
12861295
tmp = readl(port_mmio + PORT_CMD);
@@ -1601,6 +1610,8 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class,
16011610
tf.status = ATA_BUSY;
16021611
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
16031612

1613+
ahci_port_clear_pending_irq(ap);
1614+
16041615
rc = sata_link_hardreset(link, timing, deadline, online,
16051616
ahci_check_ready);
16061617

0 commit comments

Comments
 (0)