[PATCH 3/3] ata: sata_dwc_460ex: preserve sactive_issued state across ISR invocations

From: Rosen Penev

Date: Wed Jul 22 2026 - 20:18:33 EST


Zeroing hsdev->sactive_issued on every ISR entry destroys the NCQ tag
tracking that must persist across interrupts. This field is populated
in the NEWFP (DMA Setup FIS) handler and used in subsequent DMAT (DMA
Transfer Complete) interrupts to determine which tags have completed
via the formula tag_mask = (sactive_issued | sactive) ^ sactive.

With the zeroing in place, sactive_issued is always cleared before a
DMAT interrupt can read it, so the NCQ completion path never identifies
completed tags correctly. The command completion then falls back to
the non-NCQ path using ap->link.active_tag, which works for a single
outstanding command but produces wrong results when multiple NCQ tags
are in flight.

Remove the spurious zeroing and fix the NCQ/non-NCQ discrimination:
when tag_mask is zero but the active command is NCQ, all tracked tags
are still in SCR_ACTIVE and no completion processing is needed.

Fixes: 2d20da00c324b ("ata: sata_dwc_460ex: get rid of global data")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
---
drivers/ata/sata_dwc_460ex.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 73bacdfd0bd3..025b5d968c78 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -467,7 +467,6 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
struct sata_dwc_device_port *hsdevp;

spin_lock_irqsave(&host->lock, flags);
- hsdev->sactive_issued = 0;

/* Read the interrupt register */
intpr = sata_dwc_readl(&hsdev->sata_dwc_regs->intpr);
@@ -517,8 +516,11 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
sata_dwc_scr_read(&ap->link, SCR_ACTIVE, &sactive);
tag_mask = (hsdev->sactive_issued | sactive) ^ sactive;

- /* If no sactive issued and tag_mask is zero then this is not NCQ */
- if (hsdev->sactive_issued == 0 && tag_mask == 0) {
+ /*
+ * If tag_mask is zero and the active command is not NCQ this is a
+ * non-NCQ completion.
+ */
+ if (tag_mask == 0) {
if (ap->link.active_tag == ATA_TAG_POISON)
tag = 0;
else
@@ -534,6 +536,12 @@ static irqreturn_t sata_dwc_isr(int irq, void *dev_instance)
handled = 1;
goto DONE;
}
+ if (ata_is_ncq(qc->tf.protocol)) {
+ /* NCQ commands still in flight; no tag completed. */
+ ap->ops->sff_check_status(ap);
+ handled = 1;
+ goto DONE;
+ }
status = ap->ops->sff_check_status(ap);

qc->ap->link.active_tag = tag;
--
2.55.0