summaryrefslogtreecommitdiff
path: root/drivers/ata/libahci.c
diff options
context:
space:
mode:
authorNiklas Cassel <niklas.cassel@wdc.com>2022-10-03 21:46:52 +0200
committerDamien Le Moal <damien.lemoal@opensource.wdc.com>2022-10-17 11:31:52 +0900
commit4ba09d202657d2004859f4c05fa3272873ceb08f (patch)
tree96bb889102550ab2da6acefb3081c9a039cd41c6 /drivers/ata/libahci.c
parent013115d90e007585bb85b45a5dc301ef1be62aab (diff)
ata: libahci: read correct status and error field for NCQ commands
Currently, for PIO commands, ahci_qc_fill_rtf() reads the status and error fields from the PIO Setup FIS area of the Received FIS Structure. For any non-PIO command, ahci_qc_fill_rtf() currently reads the status and error fields from the D2H Register FIS area of the Received FIS Structure. This is simply not correct. According to the SATA 3.5a specification: 11.10 DMA DATA-IN command protocol and 11.11 DMA DATA-OUT command protocol: READ DMA and WRITE DMA (non-NCQ commands) will end with the Send_status state, which transmits a Register D2H FIS. Likewise, in: 11.15 FPDMA QUEUED command protocol: READ FPDMA QUEUED and WRITE FPDMA QUEUED (NCQ commands) will end with the SendStatus state, which transmits a Set Device Bits FIS. So, for NCQ commands, there is never a D2H Register FIS sent. Reading the status and error fields from the D2H Register FIS area for a NCQ command, will result in us returning the status and error values for the last non-NCQ command, which is incorrect. Update ahci_qc_fill_rtf() to read the status and error fields from the correct area in the Received FIS Structure for NCQ commands. Once reason why this has not been detected before, could be because, in case of an NCQ error, ata_eh_analyze_ncq_error() will overwrite the (incorrect) status and error values set by ahci_qc_fill_rtf(). However, even successful NCQ commands can have bits set in the status field (e.g. the sense data available bit), so it is mandatory to read the status from the correct area also for NCQ commands. Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com> Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r--drivers/ata/libahci.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 954386a2b500..96bef8007856 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -2071,6 +2071,20 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
!(qc->flags & ATA_QCFLAG_FAILED)) {
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15];
+
+ /*
+ * For NCQ commands, we never get a D2H FIS, so reading the D2H Register
+ * FIS area of the Received FIS Structure (which contains a copy of the
+ * last D2H FIS received) will contain an outdated status code.
+ * For NCQ commands, we instead get a SDB FIS, so read the SDB FIS area
+ * instead. However, the SDB FIS does not contain the LBA, so we can't
+ * use the ata_tf_from_fis() helper.
+ */
+ } else if (ata_is_ncq(qc->tf.protocol)) {
+ const u8 *fis = rx_fis + RX_FIS_SDB;
+
+ qc->result_tf.status = fis[2];
+ qc->result_tf.error = fis[3];
} else
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);