mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] ata: libata-scsi: fix ATA PASS-THROUGH(32) handling
@ 2026-11-04 14:08 shao.mingyin
  2026-11-04 14:09 ` [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru shao.mingyin
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: shao.mingyin @ 2026-11-04 14:08 UTC (permalink / raw)
  To: dlemoal, cassel, linux-ide; +Cc: linux-kernel

ATA PASS-THROUGH(32) uses the variable length CDB opcode 7Fh with
service action 1FF0h.  Commit b1ffbf854e08 added support for it, but
three paths still use the offsets of the 12- and 16-byte CDBs, or do
not recognize the 32-byte form at all.

Patch 1 fixes the PIO multi-sector sanity check and the multi_count
computation, which read cdb[1] instead of cdb[1 + cdb_offset], and
reports the field pointer for the same byte.

Patch 2 makes an unsupported service action fail with INVALID FIELD IN
CDB.  It currently returns 1 without setting sense data, so the command
completes with SAM_STAT_GOOD even though no ATA command was issued.

Patch 3 teaches the completion path to recognize ATA PASS-THROUGH(32)
and to read CK_COND from byte 11.  Without it, CK_COND is ignored and
the ATA Status Return sense descriptor is not built.

The three patches are independent and can be applied in any order.  All
were tested with a 32-byte CDB sent through SG_IO to a QEMU IDE disk;
the per-patch test descriptions are included after the --- line.

Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>
---
base-commit: 7649ba73f9e7e1e04d0b46213e39c79ae09dd55c

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru
  2026-11-04 14:08 [PATCH 0/3] ata: libata-scsi: fix ATA PASS-THROUGH(32) handling shao.mingyin
@ 2026-11-04 14:09 ` shao.mingyin
  2026-11-05  3:16   ` Damien Le Moal
  2026-11-04 14:11 ` [PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions shao.mingyin
  2026-11-04 14:11 ` [PATCH 3/3] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32) shao.mingyin
  2 siblings, 1 reply; 7+ messages in thread
From: shao.mingyin @ 2026-11-04 14:09 UTC (permalink / raw)
  To: dlemoal, cassel, linux-ide; +Cc: linux-kernel

From: Shao Mingyin <shao.mingyin@zte.com.cn>

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@zte.com.cn>
---
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,

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions
  2026-11-04 14:08 [PATCH 0/3] ata: libata-scsi: fix ATA PASS-THROUGH(32) handling shao.mingyin
  2026-11-04 14:09 ` [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru shao.mingyin
@ 2026-11-04 14:11 ` shao.mingyin
  2026-11-05  3:18   ` Damien Le Moal
  2026-11-04 14:11 ` [PATCH 3/3] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32) shao.mingyin
  2 siblings, 1 reply; 7+ messages in thread
From: shao.mingyin @ 2026-11-04 14:11 UTC (permalink / raw)
  To: dlemoal, cassel, linux-ide; +Cc: linux-kernel

From: Shao Mingyin <shao.mingyin@zte.com.cn>

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@zte.com.cn>
---
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;
 }

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 3/3] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32)
  2026-11-04 14:08 [PATCH 0/3] ata: libata-scsi: fix ATA PASS-THROUGH(32) handling shao.mingyin
  2026-11-04 14:09 ` [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru shao.mingyin
  2026-11-04 14:11 ` [PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions shao.mingyin
@ 2026-11-04 14:11 ` shao.mingyin
  2026-11-05  3:19   ` Damien Le Moal
  2 siblings, 1 reply; 7+ messages in thread
From: shao.mingyin @ 2026-11-04 14:11 UTC (permalink / raw)
  To: dlemoal, cassel, linux-ide; +Cc: linux-kernel

From: Shao Mingyin <shao.mingyin@zte.com.cn>

ata_scsi_qc_complete() detects ATA pass-through commands by the ATA_12
and ATA_16 opcodes only.  ATA PASS-THROUGH (32) uses the variable
length CDB opcode 7Fh with service action ATA_32, so for those commands
the function takes the ordinary completion path: the CK_COND bit is
never honored and the ATA Status Return sense descriptor is never
built.  A successful command with CK_COND set is reported as GOOD
instead of CHECK CONDITION, and a failed command gets the generic ATA
sense data without the ATA register values.

The byte that carries T_LENGTH and CK_COND is byte 2 for 12- and
16-byte CDBs, but byte 11 for a 32-byte CDB, whose byte 2 is part of the
variable length CDB header.  Detect ATA PASS-THROUGH (32) through its
service action and read CK_COND from the correct byte.

Fixes: b1ffbf854e08 ("libata: Support for an ATA PASS-THROUGH(32) command.")
Cc: stable@vger.kernel.org
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>
---
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 ATA PASS-THROUGH(32) READ SECTORS CDB with CK_COND set in
cdb[11] and a 512-byte data-in buffer is sent with SG_IO.  The same
CDB with CK_COND clear is the control and completes GOOD on both.

  unpatched                            patched
  status 0x00, no sense data           status 0x02 (CHECK CONDITION)
                                       sk 0x01, asc/ascq 0x00/0x1d
                                       ATA descriptor 0x09 present
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a61fb0331279..97adeecc7736 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
@@ -3389,6 +3392,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
 	tf->protocol = ata_scsi_map_proto(cdb[1 + cdb_offset]);
 	if (tf->protocol == ATA_PROT_UNKNOWN) {
-		fp = 1;
+		fp = 1 + cdb_offset;
 		goto invalid_fld;
 	}

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru
  2026-11-04 14:09 ` [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru shao.mingyin
@ 2026-11-05  3:16   ` Damien Le Moal
  0 siblings, 0 replies; 7+ messages in thread
From: Damien Le Moal @ 2026-11-05  3:16 UTC (permalink / raw)
  To: shao.mingyin, cassel, linux-ide; +Cc: linux-kernel

On 11/4/26 23:09, shao.mingyin@zte.com.cn wrote:
> From: Shao Mingyin <shao.mingyin@zte.com.cn>
> 
> 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@zte.com.cn>

Looks OK.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions
  2026-11-04 14:11 ` [PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions shao.mingyin
@ 2026-11-05  3:18   ` Damien Le Moal
  0 siblings, 0 replies; 7+ messages in thread
From: Damien Le Moal @ 2026-11-05  3:18 UTC (permalink / raw)
  To: shao.mingyin, cassel, linux-ide; +Cc: linux-kernel

On 11/4/26 23:11, shao.mingyin@zte.com.cn wrote:
> From: Shao Mingyin <shao.mingyin@zte.com.cn>
> 
> 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@zte.com.cn>

Looks OK.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32)
  2026-11-04 14:11 ` [PATCH 3/3] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32) shao.mingyin
@ 2026-11-05  3:19   ` Damien Le Moal
  0 siblings, 0 replies; 7+ messages in thread
From: Damien Le Moal @ 2026-11-05  3:19 UTC (permalink / raw)
  To: shao.mingyin, cassel, linux-ide; +Cc: linux-kernel

On 11/4/26 23:11, shao.mingyin@zte.com.cn wrote:
> From: Shao Mingyin <shao.mingyin@zte.com.cn>
> 
> ata_scsi_qc_complete() detects ATA pass-through commands by the ATA_12
> and ATA_16 opcodes only.  ATA PASS-THROUGH (32) uses the variable
> length CDB opcode 7Fh with service action ATA_32, so for those commands
> the function takes the ordinary completion path: the CK_COND bit is
> never honored and the ATA Status Return sense descriptor is never
> built.  A successful command with CK_COND set is reported as GOOD
> instead of CHECK CONDITION, and a failed command gets the generic ATA
> sense data without the ATA register values.
> 
> The byte that carries T_LENGTH and CK_COND is byte 2 for 12- and
> 16-byte CDBs, but byte 11 for a 32-byte CDB, whose byte 2 is part of the
> variable length CDB header.  Detect ATA PASS-THROUGH (32) through its
> service action and read CK_COND from the correct byte.
> 
> Fixes: b1ffbf854e08 ("libata: Support for an ATA PASS-THROUGH(32) command.")
> Cc: stable@vger.kernel.org
> Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>

Looks OK.

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>

-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-05  3:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 14:08 [PATCH 0/3] ata: libata-scsi: fix ATA PASS-THROUGH(32) handling shao.mingyin
2026-11-04 14:09 ` [PATCH 1/3] ata: libata-scsi: fix the multi_count check for 32-byte passthru shao.mingyin
2026-11-05  3:16   ` Damien Le Moal
2026-11-04 14:11 ` [PATCH 2/3] ata: libata-scsi: reject unsupported ATA-32 service actions shao.mingyin
2026-11-05  3:18   ` Damien Le Moal
2026-11-04 14:11 ` [PATCH 3/3] ata: libata-scsi: generate SAT sense data for ATA PASS-THROUGH(32) shao.mingyin
2026-11-05  3:19   ` Damien Le Moal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®