ata: libata: fix NCQ autosense logic
authorNiklas Cassel <niklas.cassel@wdc.com>
Mon, 26 Sep 2022 20:53:06 +0000 (20:53 +0000)
committerDamien Le Moal <damien.lemoal@opensource.wdc.com>
Mon, 17 Oct 2022 02:31:52 +0000 (11:31 +0900)
Currently, the logic if we should call ata_scsi_set_sense()
(and set flag ATA_QCFLAG_SENSE_VALID to indicate that we have
successfully added sense data to the struct ata_queued_cmd)
looks like this:

if (dev->class == ATA_DEV_ZAC &&
    ((qc->result_tf.status & ATA_SENSE) || qc->result_tf.auxiliary))

The problem with this is that a drive can support the NCQ command
error log without supporting NCQ autosense.

On such a drive, if the failing command has sense data, the status
field in the NCQ command error log will have the ATA_SENSE bit set.

It is just that this sense data is not included in the NCQ command
error log when NCQ autosense is not supported. Instead the sense
data has to be fetched using the REQUEST SENSE DATA EXT command.

Therefore, we should only add the sense data if the drive supports
NCQ autosense AND the ATA_SENSE bit is set in the status field.

Fix this, and at the same time, remove the duplicated ATA_DEV_ZAC
check. The struct ata_taskfile supplied to ata_eh_read_log_10h()
is memset:ed before calling the function, so simply checking if
qc->result_tf.auxiliary is set is sufficient to tell us that the
log actually contained sense data.

Fixes: d238ffd59d3c ("libata: do not attempt to retrieve sense code twice")
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
drivers/ata/libata-sata.c

index b6806d41a8c508fd4e330e5878d9498f736b543d..fd4dccc253896c1d77053a3d1eb15a8e6d9a1733 100644 (file)
@@ -1392,7 +1392,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
        tf->hob_lbah = buf[10];
        tf->nsect = buf[12];
        tf->hob_nsect = buf[13];
-       if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id))
+       if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id) &&
+           (tf->status & ATA_SENSE))
                tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
 
        return 0;
@@ -1456,8 +1457,12 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
        memcpy(&qc->result_tf, &tf, sizeof(tf));
        qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
        qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
-       if (dev->class == ATA_DEV_ZAC &&
-           ((qc->result_tf.status & ATA_SENSE) || qc->result_tf.auxiliary)) {
+
+       /*
+        * If the device supports NCQ autosense, ata_eh_read_log_10h() will have
+        * stored the sense data in qc->result_tf.auxiliary.
+        */
+       if (qc->result_tf.auxiliary) {
                char sense_key, asc, ascq;
 
                sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;