scsi: ata: libata: Detect support for command duration limits

Use the supported capabilities identify device data log page to detect if a
device supports the command duration limits feature. For devices supporting
this feature, set the device flag ATA_DFLAG_CDL. To support SCSI-ATA
translation, retrieve the command duration limits log page 18h and cache
this page content using the cdl array added to the ata_device data
structure.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Co-developed-by: Niklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Link: https://lore.kernel.org/r/20230511011356.227789-15-nks@flawful.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Damien Le Moal
2023-05-11 03:13:47 +02:00
committed by Martin K. Petersen
parent 24aeebbf8e
commit 62e4a60e0c
4 changed files with 78 additions and 21 deletions

View File

@@ -2367,6 +2367,54 @@ static void ata_dev_config_trusted(struct ata_device *dev)
dev->flags |= ATA_DFLAG_TRUSTED;
}
static void ata_dev_config_cdl(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
u64 val;
if (ata_id_major_version(dev->id) < 12)
goto not_supported;
if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE) ||
!ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES))
goto not_supported;
err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_SUPPORTED_CAPABILITIES,
ap->sector_buf, 1);
if (err_mask)
goto not_supported;
/* Check Command Duration Limit Supported bits */
val = get_unaligned_le64(&ap->sector_buf[168]);
if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(0)))
goto not_supported;
/* Warn the user if command duration guideline is not supported */
if (!(val & BIT_ULL(1)))
ata_dev_warn(dev,
"Command duration guideline is not supported\n");
/*
* Command duration limits is supported: cache the CDL log page 18h
* (command duration descriptors).
*/
err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_warn(dev, "Read Command Duration Limits log failed\n");
goto not_supported;
}
memcpy(dev->cdl, ap->sector_buf, ATA_LOG_CDL_SIZE);
dev->flags |= ATA_DFLAG_CDL;
return;
not_supported:
dev->flags &= ~ATA_DFLAG_CDL;
}
static int ata_dev_config_lba(struct ata_device *dev)
{
const u16 *id = dev->id;
@@ -2534,13 +2582,14 @@ static void ata_dev_print_features(struct ata_device *dev)
return;
ata_dev_info(dev,
"Features:%s%s%s%s%s%s%s\n",
"Features:%s%s%s%s%s%s%s%s\n",
dev->flags & ATA_DFLAG_FUA ? " FUA" : "",
dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "",
dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "",
dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "",
dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "",
dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "",
dev->flags & ATA_DFLAG_CDL ? " CDL" : "",
dev->cpr_log ? " CPR" : "");
}
@@ -2702,6 +2751,7 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_config_zac(dev);
ata_dev_config_trusted(dev);
ata_dev_config_cpr(dev);
ata_dev_config_cdl(dev);
dev->cdb_len = 32;
if (print_info)