[PATCH v2 3/4] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32)
From: shao.mingyin
Date: Wed Nov 11 2026 - 09:33:23 EST
From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
ata_scsi_qc_complete() only recognizes ATA PASS-THROUGH(12) and (16).
The 32-byte form takes the ordinary completion path, so CK_COND is
ignored and errors lack the ATA Status Return descriptor. Successful
commands with CK_COND set therefore complete GOOD instead of returning
CHECK CONDITION with the ATA register values.
Recognize ATA PASS-THROUGH(32) by its service action and read CK_COND
from byte 11 instead of byte 2, which belongs to the variable-length
CDB header.
Fixes: b1ffbf854e08 ("libata: Support for an ATA PASS-THROUGH(32) command.")
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: Damien Le Moal <dlemoal@xxxxxxxxxx>
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
Changes in v2 (Niklas Cassel):
- Move the unrelated invalid-PROTOCOL hunk to patch 1; this patch only
changes the completion path.
- Regenerate with git format-patch so the index matches the diff.
- Keep the Reviewed-by tag; apart from the moved hunk this patch is
unchanged from v1.
v1: https://lore.kernel.org/all/202611042211545962bhKeo8yjWPGFgya4g6LG@xxxxxxxxxx/
Validation on x86-64 with GCC 13 and UBSAN: a userspace harness compiled
ata_scsi_qc_complete() verbatim with sense/completion stubs. For ATA_32,
CK_COND in byte 11 now selected pass-through sense and CHECK CONDITION;
CK_COND clear remained GOOD. Error and preexisting-sense paths selected
the pass-through helpers, and byte 2 did not act as CK_COND. The short
CDB paths and unsupported service-action control were also checked.
drivers/ata/libata-scsi.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3fffa2617339fb7aa8a9035bbd88258794e1bf63..645899c2625424c7e305c7a2d426cdcc217dde43 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1888,9 +1888,12 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
struct ata_link *link = qc->dev->link;
struct scsi_cmnd *cmd = qc->scsicmd;
u8 *cdb = cmd->cmnd;
+ u16 cdb_offset = cdb[0] == VARIABLE_LENGTH_CMD ? 9 : 0;
bool have_sense = qc->flags & ATA_QCFLAG_SENSE_VALID;
- bool is_ata_passthru = cdb[0] == ATA_16 || cdb[0] == ATA_12;
- bool is_ck_cond_request = cdb[2] & 0x20;
+ bool is_ata_passthru = cdb[0] == ATA_16 || cdb[0] == ATA_12 ||
+ (cdb[0] == VARIABLE_LENGTH_CMD &&
+ get_unaligned_be16(&cdb[8]) == ATA_32);
+ bool is_ck_cond_request = cdb[2 + cdb_offset] & 0x20;
bool is_error = qc->err_mask != 0;
/* For ATA pass thru (SAT) commands, generate a sense block if