summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-06 14:53:28 +0100
committerMark Brown <broonie@kernel.org>2026-07-06 14:53:28 +0100
commit35e8e9e78770d77b462d3612bb3c9a6abf86dc90 (patch)
treeb6f34e400bf81f1ae55f05a133de02a74b433e28
parentd997703d9c51b7e86a7cce99b3df2f1060a13d56 (diff)
parente64e6b5dc86758c14ed28a6e85bf5d1b78146ed5 (diff)
downloadlinux-next-35e8e9e78770d77b462d3612bb3c9a6abf86dc90.tar.gz
linux-next-35e8e9e78770d77b462d3612bb3c9a6abf86dc90.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/libata/linux
-rw-r--r--drivers/ata/libata-core.c6
-rw-r--r--drivers/ata/libata-scsi.c416
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--include/linux/ata.h13
4 files changed, 334 insertions, 103 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index bdc88cf74709..5121faf9738e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2488,7 +2488,7 @@ static void ata_dev_config_sense_reporting(struct ata_device *dev)
}
}
-static void ata_dev_config_zac(struct ata_device *dev)
+static void ata_dev_config_zoned(struct ata_device *dev)
{
unsigned int err_mask;
u8 *identify_buf = dev->sector_buf;
@@ -2497,7 +2497,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
dev->zac_zones_optimal_nonseq = U32_MAX;
dev->zac_zones_max_open = U32_MAX;
- if (!ata_dev_is_zac(dev))
+ if (!ata_dev_is_zoned(dev))
return;
if (!ata_identify_page_supported(dev, ATA_LOG_ZONED_INFORMATION)) {
@@ -3111,7 +3111,7 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_config_fua(dev);
ata_dev_config_devslp(dev);
ata_dev_config_sense_reporting(dev);
- ata_dev_config_zac(dev);
+ ata_dev_config_zoned(dev);
ata_dev_config_trusted(dev);
ata_dev_config_cpr(dev);
ata_dev_config_cdl(dev);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 5868526301a2..5cddb63a6bc6 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2023,7 +2023,7 @@ static unsigned int ata_scsiop_inq_std(struct ata_device *dev,
if (rbuf[32] == 0 || rbuf[32] == ' ')
memcpy(&rbuf[32], "n/a ", 4);
- if (ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC)
+ if (ata_dev_is_zoned(dev))
memcpy(rbuf + 58, versions_zbc, sizeof(versions_zbc));
else
memcpy(rbuf + 58, versions, sizeof(versions));
@@ -2063,7 +2063,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_device *dev,
};
for (i = 0; i < sizeof(pages); i++) {
- if (pages[i] == 0xb6 && !ata_dev_is_zac(dev))
+ if (pages[i] == 0xb6 && !ata_dev_is_zoned(dev))
continue;
rbuf[num_pages + 4] = pages[i];
num_pages++;
@@ -2202,6 +2202,39 @@ static unsigned int ata_scsiop_inq_89(struct ata_device *dev,
}
/**
+ * ata_dsm_trim_pages - maximum DSM TRIM payload for a device, in 512-byte pages
+ * @dev: ATA device the DATA SET MANAGEMENT TRIM command will be sent to
+ *
+ * A DATA SET MANAGEMENT TRIM payload is a list of 512-byte pages, each holding
+ * up to ATA_MAX_TRIM_RNUM (64) LBA Range Entries; the format is page-based and
+ * unrelated to the logical sector size.
+ *
+ * The logical sector size still bounds it, though: the descriptor is written
+ * directly into the WRITE SAME data-out buffer, which sd sizes to a single
+ * logical block, so it can hold at most sector_size / 512 pages.
+ *
+ * Return: the maximum number of 512-byte pages a single translated WRITE SAME
+ * command may send to @dev (never less than one), that is the smaller of:
+ * - MAX PAGES PER DSM COMMAND (IDENTIFY DEVICE word 105), when the device
+ * reports a non-zero limit; and
+ * - the logical sector size expressed in 512-byte pages (see above).
+ */
+static unsigned int ata_dsm_trim_pages(struct ata_device *dev)
+{
+ unsigned int sector_size = ata_id_logical_sector_size(dev->id);
+ unsigned int max_pages = ata_id_dsm_max_pages(dev->id);
+ unsigned int pages = sector_size / ATA_SECT_SIZE;
+
+ /* If the device does not specify a limit, assume only a single page. */
+ if (!max_pages)
+ max_pages = 1;
+
+ pages = min_not_zero(pages, max_pages);
+
+ return pages;
+}
+
+/**
* ata_scsiop_inq_b0 - Simulate INQUIRY VPD page B0, Block Limits
* @dev: Target device.
* @cmd: SCSI command of interest.
@@ -2240,7 +2273,8 @@ static unsigned int ata_scsiop_inq_b0(struct ata_device *dev,
* with the unmap bit set.
*/
if (ata_id_has_trim(dev->id)) {
- u64 max_blocks = 65535 * ATA_MAX_TRIM_RNUM;
+ unsigned int max_pages = ata_dsm_trim_pages(dev);
+ u64 max_blocks = max_pages * ATA_MAX_TRIM_RNUM * (u64)U16_MAX;
if (dev->quirks & ATA_QUIRK_MAX_TRIM_128M)
max_blocks = 128 << (20 - SECTOR_SHIFT);
@@ -2320,7 +2354,7 @@ static unsigned int ata_scsiop_inq_b2(struct ata_device *dev,
static unsigned int ata_scsiop_inq_b6(struct ata_device *dev,
struct scsi_cmnd *cmd, u8 *rbuf)
{
- if (!ata_dev_is_zac(dev)) {
+ if (!ata_dev_is_zoned(dev)) {
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
return 0;
}
@@ -2851,7 +2885,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_device *dev,
rbuf[10] = sector_size >> (8 * 1);
rbuf[11] = sector_size;
- if (ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC)
+ if (ata_dev_is_zoned(dev))
rbuf[12] = (1 << 4); /* RC_BASIS */
rbuf[13] = log2_per_phys;
rbuf[14] = (lowest_aligned >> 8) & 0x3f;
@@ -3429,14 +3463,14 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
/**
* ata_format_dsm_trim_descr() - SATL Write Same to DSM Trim
* @cmd: SCSI command being translated
- * @trmax: Maximum number of entries that will fit in sector_size bytes.
+ * @size: DSM TRIM payload size in bytes (a multiple of 512)
* @sector: Starting sector
* @count: Total Range of request in logical sectors
*
* Rewrite the WRITE SAME descriptor to be a DSM TRIM little-endian formatted
* descriptor.
*
- * Upto 64 entries of the format:
+ * The payload is a list of @size / 8 entries of the format:
* 63:48 Range Length
* 47:0 LBA
*
@@ -3445,39 +3479,45 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
*
* NOTE: this is the same format as ADD LBA(S) TO NV CACHE PINNED SET
*
- * Return: Number of bytes copied into sglist.
+ * The descriptor is written straight into the WRITE SAME data-out buffer;
+ * ata_dsm_trim_pages() guarantees @size does not exceed that buffer (one
+ * logical block). An atomic sg_miter mapping is used so this works from the
+ * command submission path and, unlike page_address(), copes with a high
+ * memory payload.
+ *
+ * Return: Number of bytes written into the data-out buffer.
*/
-static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax,
+static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, size_t size,
u64 sector, u32 count)
{
- struct scsi_device *sdp = cmd->device;
- size_t len = sdp->sector_size;
- size_t r;
- __le64 *buf;
- u32 i = 0;
- unsigned long flags;
+ struct sg_mapping_iter miter;
+ size_t offset = 0;
- WARN_ON(len > ATA_SCSI_RBUF_SIZE);
+ sg_miter_start(&miter, scsi_sglist(cmd), scsi_sg_count(cmd),
+ SG_MITER_TO_SG | SG_MITER_ATOMIC);
+ while (offset < size && sg_miter_next(&miter)) {
+ __le64 *buf = miter.addr;
+ size_t chunk = min_t(size_t, miter.length, size - offset);
+ unsigned int n = chunk / sizeof(__le64);
+ unsigned int i;
- if (len > ATA_SCSI_RBUF_SIZE)
- len = ATA_SCSI_RBUF_SIZE;
+ for (i = 0; i < n; i++) {
+ u64 entry = 0;
- spin_lock_irqsave(&ata_scsi_rbuf_lock, flags);
- buf = ((void *)ata_scsi_rbuf);
- memset(buf, 0, len);
- while (i < trmax) {
- u64 entry = sector |
- ((u64)(count > 0xffff ? 0xffff : count) << 48);
- buf[i++] = __cpu_to_le64(entry);
- if (count <= 0xffff)
- break;
- count -= 0xffff;
- sector += 0xffff;
+ if (count) {
+ u32 rlen = min_t(u32, count, 0xffff);
+
+ entry = sector | ((u64)rlen << 48);
+ sector += rlen;
+ count -= rlen;
+ }
+ buf[i] = cpu_to_le64(entry);
+ }
+ offset += n * sizeof(__le64);
}
- r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len);
- spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags);
+ sg_miter_stop(&miter);
- return r;
+ return offset;
}
/**
@@ -3495,14 +3535,13 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
{
struct ata_taskfile *tf = &qc->tf;
struct scsi_cmnd *scmd = qc->scsicmd;
- struct scsi_device *sdp = scmd->device;
- size_t len = sdp->sector_size;
struct ata_device *dev = qc->dev;
const u8 *cdb = scmd->cmnd;
+ unsigned int max_pages = ata_dsm_trim_pages(dev);
+ unsigned int n_pages;
+ size_t size;
u64 block;
u32 n_block;
- const u32 trmax = len >> 3;
- u32 size;
u16 fp;
u8 bp = 0xff;
u8 unmap = cdb[1] & 0x8;
@@ -3532,7 +3571,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
goto invalid_fld;
}
/* If the request is too large the cmd is invalid */
- if (n_block > 0xffff * trmax) {
+ if (n_block > max_pages * ATA_MAX_TRIM_RNUM * (u64)U16_MAX) {
fp = 2;
goto invalid_fld;
}
@@ -3545,31 +3584,39 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
goto invalid_param_len;
/*
- * size must match sector size in bytes
- * For DATA SET MANAGEMENT TRIM in ACS-2 nsect (aka count)
- * is defined as number of 512 byte blocks to be transferred.
+ * The DATA SET MANAGEMENT TRIM payload is a whole number of 512-byte
+ * pages (each holding up to ATA_MAX_TRIM_RNUM LBA Range Entries),
+ * independent of the logical sector size. Only use as many pages as
+ * are needed to describe the request, capped at max_pages.
*/
+ n_pages = DIV_ROUND_UP(DIV_ROUND_UP(n_block, U16_MAX),
+ ATA_MAX_TRIM_RNUM);
+ n_pages = clamp(n_pages, 1U, max_pages);
+ size = (size_t)n_pages * ATA_SECT_SIZE;
- size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block);
- if (size != len)
+ if (ata_format_dsm_trim_descr(scmd, size, block, n_block) != size)
goto invalid_param_len;
+ /*
+ * For DATA SET MANAGEMENT TRIM the COUNT field (aka nsect) is the
+ * number of 512-byte pages to be transferred.
+ */
if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) {
/* Newer devices support queued TRIM commands */
tf->protocol = ATA_PROT_NCQ;
tf->command = ATA_CMD_FPDMA_SEND;
tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f;
tf->nsect = qc->hw_tag << 3;
- tf->hob_feature = (size / 512) >> 8;
- tf->feature = size / 512;
+ tf->hob_feature = n_pages >> 8;
+ tf->feature = n_pages;
tf->auxiliary = 1;
} else {
tf->protocol = ATA_PROT_DMA;
tf->hob_feature = 0;
tf->feature = ATA_DSM_TRIM;
- tf->hob_nsect = (size / 512) >> 8;
- tf->nsect = size / 512;
+ tf->hob_nsect = n_pages >> 8;
+ tf->nsect = n_pages;
tf->command = ATA_CMD_DSM;
}
@@ -3577,6 +3624,12 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
ATA_TFLAG_WRITE;
ata_qc_set_pc_nbytes(qc);
+ /*
+ * The DSM TRIM payload (size) may be smaller than the WRITE SAME
+ * data-out buffer (one logical block); only transfer the pages that
+ * were actually built so the transfer length matches the COUNT field.
+ */
+ qc->nbytes = size;
return 0;
@@ -3593,88 +3646,253 @@ invalid_opcode:
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;
+ bool sa_valid;
+ u16 sa;
+};
+
+/*
+ * Array of commands supported with translation or emulation, sorted in
+ * ascending opcode and service action order. All of these commands are
+ * processed either in ata_xlat_func() or in ata_scsi_simulate();
+ *
+ * Note: commands that are not fully supported may be left out of this array
+ * so that they are not reported as supported for passthrough but still
+ * available through the block layer. For now, this includes the following
+ * commands:
+ * - WRITE_SAME_16: ata_scsi_write_same_xlat() forbids passthrough commands
+ */
+static const struct ata_scsi_cmd ata_supported_cmds[] = {
+ { .op = TEST_UNIT_READY, .cdb_len = 6 },
+ { .op = REZERO_UNIT, .cdb_len = 6 },
+ { .op = REQUEST_SENSE, .cdb_len = 6 },
+ { .op = READ_6, .cdb_len = 6 },
+ { .op = WRITE_6, .cdb_len = 6 },
+ { .op = SEEK_6, .cdb_len = 6 },
+ { .op = INQUIRY, .cdb_len = 6 },
+ { .op = MODE_SELECT, .cdb_len = 6 },
+ { .op = MODE_SENSE, .cdb_len = 6 },
+ { .op = START_STOP, .cdb_len = 6 },
+ { .op = SEND_DIAGNOSTIC, .cdb_len = 6 },
+ { .op = READ_CAPACITY, .cdb_len = 10 },
+ { .op = READ_10, .cdb_len = 10 },
+ { .op = WRITE_10, .cdb_len = 10 },
+ { .op = SEEK_10, .cdb_len = 10 },
+ { .op = VERIFY, .cdb_len = 10 },
+ { .op = SYNCHRONIZE_CACHE, .cdb_len = 10 },
+ { .op = MODE_SELECT_10, .cdb_len = 10 },
+ { .op = MODE_SENSE_10, .cdb_len = 10 },
+ {
+ .op = VARIABLE_LENGTH_CMD, .cdb_len = 32,
+ .sa_valid = true,
+ .sa = ATA_32
+ },
+ { .op = ATA_16, .cdb_len = 16 },
+ { .op = READ_16, .cdb_len = 16 },
+ { .op = WRITE_16, .cdb_len = 16 },
+ { .op = VERIFY_16, .cdb_len = 16 },
+ { .op = SYNCHRONIZE_CACHE_16, .cdb_len = 16 },
+ {
+ .op = ZBC_OUT, .cdb_len = 16,
+ .sa_valid = true,
+ .sa = ZO_CLOSE_ZONE
+ },
+ {
+ .op = ZBC_OUT, .cdb_len = 16,
+ .sa_valid = true,
+ .sa = ZO_FINISH_ZONE
+ },
+ {
+ .op = ZBC_OUT, .cdb_len = 16,
+ .sa_valid = true,
+ .sa = ZO_OPEN_ZONE
+ },
+ {
+ .op = ZBC_OUT, .cdb_len = 16,
+ .sa_valid = true,
+ .sa = ZO_RESET_WRITE_POINTER
+ },
+ {
+ .op = ZBC_IN, .cdb_len = 16,
+ .sa_valid = true,
+ .sa = ZI_REPORT_ZONES
+ },
+ {
+ .op = SERVICE_ACTION_IN_16, .cdb_len = 16,
+ .sa_valid = true,
+ .sa = SAI_READ_CAPACITY_16
+ },
+ { .op = REPORT_LUNS, .cdb_len = 12 },
+ { .op = ATA_12, .cdb_len = 12 },
+ { .op = SECURITY_PROTOCOL_IN, .cdb_len = 12 },
+ {
+ .op = MAINTENANCE_IN, .cdb_len = 12,
+ .sa_valid = true,
+ .sa = MI_REPORT_SUPPORTED_OPERATION_CODES
+ },
+ { .op = SECURITY_PROTOCOL_OUT, .cdb_len = 12 },
+};
+
+static const struct ata_scsi_cmd *ata_scsi_get_supported_cmd(u8 op, u16 sa)
{
- 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 && cmd->sa == sa)
+ 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;
+}
+
+static bool ata_scsi_supported_cmd_use_sa(u8 op)
+{
+ const struct ata_scsi_cmd *cmd;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ata_supported_cmds); i++) {
+ cmd = &ata_supported_cmds[i];
+ if (cmd->op == op)
+ return cmd->sa_valid;
+ }
+
+ return false;
+}
+
+struct ata_scsi_cmd_support {
+ u8 cdlp;
+ u8 rwcdlp;
+};
+
+static bool ata_scsi_cmd_is_supported(struct ata_device *dev, u8 op, u16 sa,
+ 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, sa);
+ 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;
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;
case ZBC_IN:
case ZBC_OUT:
- if (ata_id_zoned_cap(dev->id) ||
- dev->class == ATA_DEV_ZAC)
- supported = 3;
- break;
+ return ata_dev_is_zoned(dev);
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_all_supported_opcodes(struct ata_device *dev, u8 *rbuf)
+{
+ struct ata_scsi_cmd_support sup;
+ const struct ata_scsi_cmd *cmd;
+ unsigned int len = 4;
+ u8 *buf = &rbuf[len];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ata_supported_cmds); i++) {
+ if (len > ATA_SCSI_RBUF_SIZE - 8)
+ break;
+
+ cmd = &ata_supported_cmds[i];
+
+ /* All command format */
+ if (!ata_scsi_cmd_is_supported(dev, cmd->op, cmd->sa, &sup))
+ continue;
+
+ buf[0] = cmd->op;
+ put_unaligned_be16(cmd->sa, &buf[2]);
+ buf[5] = (sup.rwcdlp << 6) | (sup.cdlp << 2);
+ if (cmd->sa_valid)
+ buf[5] |= 0x01;
+ put_unaligned_be16(cmd->cdb_len, &buf[6]);
+
+ /* CTDP == 0 */
+ len += 8;
+ buf += 8;
+ }
+
+ put_unaligned_be32(len - 4, &rbuf[0]);
+
+ return len;
+}
+
+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;
+ u16 sa = 0;
+
+ switch (cdb[2]) {
+ case 0:
+ /* All command format */
+ return ata_scsi_report_all_supported_opcodes(dev, rbuf);
+ case 1:
+ /* One command format with command support data, ignore sa. */
+ if (ata_scsi_supported_cmd_use_sa(cdb[3])) {
+ ata_scsi_set_invalid_field(dev, cmd, 3, 0xff);
+ return 0;
+ }
+ break;
+ case 2:
+ /* One command format, must have sa. */
+ if (!ata_scsi_supported_cmd_use_sa(cdb[3])) {
+ ata_scsi_set_invalid_field(dev, cmd, 3, 0xff);
+ return 0;
+ }
+ fallthrough;
+ case 3:
+ /* One command format */
+ sa = get_unaligned_be16(&cdb[4]);
+ break;
+ default:
+ 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], sa, &sup)) {
+ rbuf[0] = sup.rwcdlp;
+ rbuf[1] = (sup.cdlp << 3) | 0x03;
+ } else {
+ rbuf[1] = 0x01;
+ }
return 4;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 700627596ce1..39494ab206a2 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -44,7 +44,7 @@ static inline bool ata_sstatus_online(u32 sstatus)
return (sstatus & 0xf) == 0x3;
}
-static inline bool ata_dev_is_zac(struct ata_device *dev)
+static inline bool ata_dev_is_zoned(struct ata_device *dev)
{
/* Host managed device or host aware device */
return dev->class == ATA_DEV_ZAC ||
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 8fd48bcb2a46..ac5616a9668b 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -75,6 +75,7 @@ enum {
ATA_ID_HW_CONFIG = 93,
ATA_ID_SPG = 98,
ATA_ID_LBA_CAPACITY_2 = 100,
+ ATA_ID_MAX_PAGES_PER_DSM = 105,
ATA_ID_SECTOR_SIZE = 106,
ATA_ID_WWN = 108,
ATA_ID_LOGICAL_SECTOR_SIZE = 117, /* and 118 */
@@ -928,6 +929,18 @@ static inline bool ata_id_has_trim(const u16 *id)
return false;
}
+static inline u16 ata_id_dsm_max_pages(const u16 *id)
+{
+ /*
+ * IDENTIFY DEVICE word 105: MAX PAGES PER DSM COMMAND. Maximum number
+ * of 512-byte pages of LBA Range Entries the device accepts in a
+ * single DATA SET MANAGEMENT command. Zero means the device does not
+ * specify a limit. The field is reserved unless TRIM is supported, so
+ * callers must gate on ata_id_has_trim().
+ */
+ return id[ATA_ID_MAX_PAGES_PER_DSM];
+}
+
static inline bool ata_id_has_zero_after_trim(const u16 *id)
{
/* DSM supported, deterministic read, and read zero after trim set */