[PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions
From: shao.mingyin
Date: Wed Nov 04 2026 - 09:15:10 EST
From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
ata_scsi_var_len_cdb_xlat() handles a variable length CDB only when its
service action is ATA_32 (ATA PASS-THROUGH (32)). For any other service
action it returns 1, which tells ata_scsi_translate() that the command
has been handled and that scmd->result and the sense buffer were set by
the translation function.
No sense data is set in that path, so ata_scsi_translate() frees the qc
and calls scsi_done() with scmd->result still zero. The command thus
completes with SAM_STAT_GOOD even though no ATA command was issued and
no data was transferred. Before ATA PASS-THROUGH (32) support was added,
such CDBs were not claimed by ata_get_xlat_func() and were rejected by
ata_scsi_simulate() with ILLEGAL REQUEST/INVALID COMMAND OPERATION CODE.
Fail unsupported service actions with ILLEGAL REQUEST/INVALID FIELD IN
CDB and point the field pointer at the SERVICE ACTION field.
Fixes: b1ffbf854e08 ("libata: Support for an ATA PASS-THROUGH(32) command.")
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
Tested on 7.3.0-next-20261030 (QEMU/TCG guest) with an ATA disk
(ata_piix, /dev/sda); no special hardware is needed.
A 32-byte VARIABLE_LENGTH_CMD CDB with service action 0x1234 (not
ATA_32) and a 512-byte data-in buffer is sent with SG_IO. A valid
ATA PASS-THROUGH(32) READ SECTORS CDB is the control and is accepted
on both kernels.
unpatched patched
status 0x00 (SAM_STAT_GOOD) status 0x02 (CHECK CONDITION)
sk 0x05, asc 0x24
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a61fb0331279..d29b54688b53 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -5027,7 +5027,13 @@ static unsigned int ata_scsi_var_len_cdb_xlat(struct ata_queued_cmd *qc)
if (sa == ATA_32)
return ata_scsi_pass_thru(qc);
- /* unsupported service action */
+ /*
+ * Unsupported service action. Set the sense data explicitly, as
+ * returning 1 without it makes ata_scsi_translate() complete the
+ * command with the SCSI result still zero, that is, with
+ * SAM_STAT_GOOD.
+ */
+ ata_scsi_set_invalid_field(qc->dev, scmd, 8, 0xff);
return 1;
}