diff options
author | 2022-10-03 21:46:52 +0200 | |
---|---|---|
committer | 2022-10-17 11:31:52 +0900 | |
commit | 4ba09d202657d2004859f4c05fa3272873ceb08f (patch) | |
tree | 96bb889102550ab2da6acefb3081c9a039cd41c6 /drivers/ata/libahci.c | |
parent | ata: libata: fetch sense data for ATA devices supporting sense reporting (diff) | |
download | linux-4ba09d202657d2004859f4c05fa3272873ceb08f.tar.gz linux-4ba09d202657d2004859f4c05fa3272873ceb08f.tar.bz2 linux-4ba09d202657d2004859f4c05fa3272873ceb08f.zip |
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.c | 14 |
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); |