[PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru
From: shao.mingyin
Date: Wed Nov 04 2026 - 09:14:06 EST
From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
ata_scsi_pass_thru() translates 12, 16 and 32-byte ATA pass-through CDBs.
For a 32-byte CDB (VARIABLE_LENGTH_CMD with the ATA_32 service action) the
ATA command descriptor starts at byte offset 9, so the function adds
cdb_offset when reading the protocol (cdb[1 + cdb_offset]) and T_LENGTH
(cdb[2 + cdb_offset]) fields.
The PIO multi-sector sanity check and the multi_count computation,
however, still read cdb[1] without adding cdb_offset:
if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf))
...
unsigned int multi_count = 1 << (cdb[1] >> 5);
For a 32-byte CDB, cdb[1] is the variable length CDB control byte and
its bits 7:5 do not carry MULTIPLE_COUNT. As a result, the sanity check
that rejects a multi-sector count on a non-multi taskfile is silently
skipped, and multi_count is always computed as 1 << 0 = 1, so the
comparison against dev->multi_count either emits a spurious
"invalid multi_count 1 ignored" warning for devices configured with a
different multi-sector size or misses a real mismatch.
Read the count field from cdb[1 + cdb_offset], matching the rest of the
function, and report the field pointer relative to the same byte so that
a rejected multi-sector count points at the MULTIPLE_COUNT field instead
of byte 1. For 12 and 16-byte CDBs cdb_offset is zero, so their
behavior is unchanged.
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 / QEMU IDE) at /dev/sda. A 32-byte ATA PASS-THROUGH(32)
CDB for a non-multi command (READ SECTORS) with the multi-sector
count field set (cdb[10] bits 7:5) is sent via SG_IO; a control CDB
with the count field clear is accepted on both kernels.
unpatched patched
command accepted, rejected with
read completes (status GOOD) CHECK CONDITION,
ILLEGAL_REQUEST,
INVALID FIELD IN CDB (0x5/0x24)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a61fb0331279..927e75b7498d 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3574,13 +3574,13 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
}
/* sanity check for pio multi commands */
- if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) {
+ if ((cdb[1 + cdb_offset] & 0xe0) && !is_multi_taskfile(tf)) {
- fp = 1;
+ fp = 1 + cdb_offset;
goto invalid_fld;
}
if (is_multi_taskfile(tf)) {
- unsigned int multi_count = 1 << (cdb[1] >> 5);
+ unsigned int multi_count = 1 << (cdb[1 + cdb_offset] >> 5);
if (!dev->multi_count) {
ata_scsi_set_sense(dev, scmd, ABORTED_COMMAND,