From: Damien Le Moal <dlemoal@kernel.org>
To: linux-ide@vger.kernel.org, Niklas Cassel <cassel@kernel.org>
Subject: [PATCH v1 2/6] ata: libata-scsi: refactor ata_scsi_report_supported_opcodes()
Date: Thu, 2 Jul 2026 10:56:42 +0900 [thread overview]
Message-ID: <20260702015646.1702539-3-dlemoal@kernel.org> (raw)
In-Reply-To: <20260702015646.1702539-1-dlemoal@kernel.org>
ata_scsi_report_supported_opcodes() is very limited in functionality as it
lacks support for the all command format and also does not handle
correctly commands that have a service action.
In preparation for adding these missing features, refactor how
ata_scsi_report_supported_opcodes() operates to make modifications and
extensions easier. To do so, introduce the array of supported commands
ata_supported_cmds. This array entries are of type struct ata_scsi_cmd.
This structure stores the operation code, service action (0 if there is
not any) and CDB length of a supported SCSI command that libata SAT can
translate or emulate.
The helper function ata_scsi_get_supported_cmd() is implemented to search
for a particular command by opcode in this array. This function is used in
ata_scsi_cmd_is_supported() together with a struct ata_scsi_cmd_support to
check based on the target device features if the specified command is
supported.
ata_scsi_cmd_is_supported() is used as the main function in
ata_scsi_report_supported_opcodes() to determine if a particular command
is supported and fill the command reply rbuf as needed. In the case of a
command that is not supported, the support field is set to 1 as specified
in SPC, indicating that the command is not supported.
Of note is that the old ata_scsi_report_supported_opcodes() code did not
handle the WRITE_SAME_16 and VARIABLE_LENGTH_CMD commands which are both
supported and translated by libata-scsi. The ata_supported_cmds array
includes these commands.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
drivers/ata/libata-scsi.c | 164 +++++++++++++++++++++++++-------------
1 file changed, 109 insertions(+), 55 deletions(-)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index b8aabd08f786..380ca3886a77 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3590,88 +3590,142 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
return 1;
}
-static unsigned int ata_scsi_report_supported_opcodes(struct ata_device *dev,
- struct scsi_cmnd *cmd,
- u8 *rbuf)
+struct ata_scsi_cmd {
+ u8 op;
+ u8 cdb_len;
+ u16 sa;
+};
+
+/*
+ * List of supported commands for translation or emulation, sorted in
+ * alphabetical order. All of these commands are processed either in
+ * ata_xlat_func() or in ata_scsi_simulate();
+ */
+static const struct ata_scsi_cmd ata_supported_cmds[] = {
+ { ATA_12, 12, 0 },
+ { ATA_16, 16, 0 },
+ { INQUIRY, 6, 0 },
+ { MAINTENANCE_IN, 12, MI_REPORT_SUPPORTED_OPERATION_CODES },
+ { MODE_SENSE, 6, 0 },
+ { MODE_SENSE_10, 10, 0 },
+ { MODE_SELECT, 6, 0 },
+ { MODE_SELECT_10, 10, 0 },
+ { READ_6, 6, 0 },
+ { READ_10, 10, 0 },
+ { READ_16, 16, 0 },
+ { READ_CAPACITY, 10, 0 },
+ { REPORT_LUNS, 12, 0 },
+ { REQUEST_SENSE, 6, 0 },
+ { REZERO_UNIT, 6, 0 },
+ { SECURITY_PROTOCOL_IN, 12, 0 },
+ { SECURITY_PROTOCOL_OUT, 12, 0 },
+ { SEEK_6, 6, 0 },
+ { SEEK_10, 10, 0 },
+ { SEND_DIAGNOSTIC, 6, 0 },
+ { SERVICE_ACTION_IN_16, 16, SAI_READ_CAPACITY_16 },
+ { START_STOP, 6, 0 },
+ { SYNCHRONIZE_CACHE, 10, 0 },
+ { SYNCHRONIZE_CACHE_16, 16, 0 },
+ { TEST_UNIT_READY, 6, 0 },
+ { WRITE_6, 6, 0 },
+ { WRITE_10, 10, 0 },
+ { WRITE_16, 16, 0 },
+ { WRITE_SAME_16, 16, 0 },
+ { VERIFY, 10, 0 },
+ { VERIFY_16, 16, 0 },
+ { VARIABLE_LENGTH_CMD, 32, 0 },
+ { ZBC_IN, 16, ZI_REPORT_ZONES },
+ { ZBC_OUT, 16, ZO_CLOSE_ZONE },
+ { ZBC_OUT, 16, ZO_FINISH_ZONE },
+ { ZBC_OUT, 16, ZO_OPEN_ZONE },
+ { ZBC_OUT, 16, ZO_RESET_WRITE_POINTER },
+};
+
+static const struct ata_scsi_cmd *ata_scsi_get_supported_cmd(u8 op)
{
- u8 *cdb = cmd->cmnd;
- u8 supported = 0, cdlp = 0, rwcdlp = 0;
+ const struct ata_scsi_cmd *cmd;
+ int i;
- if (cdb[2] != 1 && cdb[2] != 3) {
- ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
- ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
- return 0;
+ for (i = 0; i < ARRAY_SIZE(ata_supported_cmds); i++) {
+ cmd = &ata_supported_cmds[i];
+ if (cmd->op == op)
+ return cmd;
}
- switch (cdb[3]) {
- case INQUIRY:
- case MODE_SENSE:
- case MODE_SENSE_10:
- case READ_CAPACITY:
- case SERVICE_ACTION_IN_16:
- case REPORT_LUNS:
- case REQUEST_SENSE:
- case SYNCHRONIZE_CACHE:
- case SYNCHRONIZE_CACHE_16:
- case REZERO_UNIT:
- case SEEK_6:
- case SEEK_10:
- case TEST_UNIT_READY:
- case SEND_DIAGNOSTIC:
- case MAINTENANCE_IN:
- case READ_6:
- case READ_10:
- case WRITE_6:
- case WRITE_10:
- case ATA_12:
- case ATA_16:
- case VERIFY:
- case VERIFY_16:
- case MODE_SELECT:
- case MODE_SELECT_10:
- case START_STOP:
- supported = 3;
- break;
+ return NULL;
+}
+
+struct ata_scsi_cmd_support {
+ u8 cdlp;
+ u8 rwcdlp;
+};
+
+static bool ata_scsi_cmd_is_supported(struct ata_device *dev, u8 op,
+ struct ata_scsi_cmd_support *sup)
+{
+ const struct ata_scsi_cmd *cmd;
+
+ /* First, see if we support the command. */
+ cmd = ata_scsi_get_supported_cmd(op);
+ if (!cmd)
+ return false;
+
+ /* Now refine the support report depending on the device features. */
+ memset(sup, 0, sizeof(*sup));
+ switch (op) {
case READ_16:
- supported = 3;
if (dev->flags & ATA_DFLAG_CDL) {
/*
* CDL read descriptors map to the T2A page, that is,
* rwcdlp = 0x01 and cdlp = 0x01
*/
- rwcdlp = 0x01;
- cdlp = 0x01 << 3;
+ sup->rwcdlp = 0x01;
+ sup->cdlp = 0x01;
}
- break;
+ return true;
case WRITE_16:
- supported = 3;
if (dev->flags & ATA_DFLAG_CDL) {
/*
* CDL write descriptors map to the T2B page, that is,
* rwcdlp = 0x01 and cdlp = 0x02
*/
- rwcdlp = 0x01;
- cdlp = 0x02 << 3;
+ sup->rwcdlp = 0x01;
+ sup->cdlp = 0x02;
}
- break;
+ return true;
case ZBC_IN:
case ZBC_OUT:
- if (ata_id_zoned_cap(dev->id) ||
- dev->class == ATA_DEV_ZAC)
- supported = 3;
- break;
+ return ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC;
case SECURITY_PROTOCOL_IN:
case SECURITY_PROTOCOL_OUT:
- if (dev->flags & ATA_DFLAG_TRUSTED)
- supported = 3;
- break;
+ return dev->flags & ATA_DFLAG_TRUSTED;
default:
break;
}
+ return true;
+}
+
+static unsigned int ata_scsi_report_supported_opcodes(struct ata_device *dev,
+ struct scsi_cmnd *cmd,
+ u8 *rbuf)
+{
+ struct ata_scsi_cmd_support sup;
+ u8 *cdb = cmd->cmnd;
+
+ if (cdb[2] != 1 && cdb[2] != 3) {
+ ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
+ ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
+ return 0;
+ }
+
/* One command format */
- rbuf[0] = rwcdlp;
- rbuf[1] = cdlp | supported;
+ if (ata_scsi_cmd_is_supported(dev, cdb[3], &sup)) {
+ rbuf[0] = sup.rwcdlp;
+ rbuf[1] = (sup.cdlp << 3) | 0x03;
+ } else {
+ rbuf[1] = 0x01;
+ }
return 4;
}
--
2.54.0
next prev parent reply other threads:[~2026-07-02 1:56 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-02 1:56 [PATCH v1 0/6] Improve ata_scsi_report_supported_opcodes() Damien Le Moal
2026-07-02 1:56 ` [PATCH v1 1/6] ata: libata: rename ata_dev_is_zac() Damien Le Moal
2026-07-02 1:56 ` Damien Le Moal [this message]
2026-07-02 1:56 ` [PATCH v1 3/6] ata: libata-scsi: improve service action support in ata_scsi_report_supported_opcodes() Damien Le Moal
2026-07-02 2:11 ` sashiko-bot
2026-07-02 1:56 ` [PATCH v1 4/6] ata: libata-scsi: improves checks for ZBC_IN and ZBC_OUT commands support Damien Le Moal
2026-07-02 2:07 ` sashiko-bot
2026-07-02 2:19 ` Damien Le Moal
2026-07-02 1:56 ` [PATCH v1 5/6] ata: libata-scsi: support reporting options 2 in REPORT SUPPORTED OPERATION CODES Damien Le Moal
2026-07-02 2:13 ` sashiko-bot
2026-07-02 1:56 ` [PATCH v1 6/6] ata: libata-scsi: support the all command format for reporting supported commands Damien Le Moal
2026-07-02 2:11 ` sashiko-bot
2026-07-02 2:27 ` Damien Le Moal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260702015646.1702539-3-dlemoal@kernel.org \
--to=dlemoal@kernel.org \
--cc=cassel@kernel.org \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox