Commit 62e4a60e authored by Damien Le Moal's avatar Damien Le Moal Committed by Martin K. Petersen
Browse files

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: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Co-developed-by: default avatarNiklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: default avatarNiklas Cassel <niklas.cassel@wdc.com>
Link: https://lore.kernel.org/r/20230511011356.227789-15-nks@flawful.org


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 24aeebbf
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -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)
+8 −9
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
#define ALL_MPAGES			0x3f
#define ALL_SUB_MPAGES			0xff


static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
	RW_RECOVERY_MPAGE,
	RW_RECOVERY_MPAGE_LEN - 2,
+4 −1
Original line number Diff line number Diff line
@@ -322,10 +322,13 @@ enum {
	ATA_LOG_SATA_NCQ	= 0x10,
	ATA_LOG_NCQ_NON_DATA	= 0x12,
	ATA_LOG_NCQ_SEND_RECV	= 0x13,
	ATA_LOG_CDL		= 0x18,
	ATA_LOG_CDL_SIZE	= ATA_SECT_SIZE,
	ATA_LOG_IDENTIFY_DEVICE	= 0x30,
	ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,

	/* Identify device log pages: */
	ATA_LOG_SUPPORTED_CAPABILITIES	= 0x03,
	ATA_LOG_SECURITY	  = 0x06,
	ATA_LOG_SATA_SETTINGS	  = 0x08,
	ATA_LOG_ZONED_INFORMATION = 0x09,
+17 −12
Original line number Diff line number Diff line
@@ -94,17 +94,18 @@ enum {
	ATA_DFLAG_DMADIR	= (1 << 10), /* device requires DMADIR */
	ATA_DFLAG_NCQ_SEND_RECV = (1 << 11), /* device supports NCQ SEND and RECV */
	ATA_DFLAG_NCQ_PRIO	= (1 << 12), /* device supports NCQ priority */
	ATA_DFLAG_CFG_MASK	= (1 << 13) - 1,

	ATA_DFLAG_PIO		= (1 << 13), /* device limited to PIO mode */
	ATA_DFLAG_NCQ_OFF	= (1 << 14), /* device limited to non-NCQ mode */
	ATA_DFLAG_SLEEPING	= (1 << 15), /* device is sleeping */
	ATA_DFLAG_DUBIOUS_XFER	= (1 << 16), /* data transfer not verified */
	ATA_DFLAG_NO_UNLOAD	= (1 << 17), /* device doesn't support unload */
	ATA_DFLAG_UNLOCK_HPA	= (1 << 18), /* unlock HPA */
	ATA_DFLAG_INIT_MASK	= (1 << 19) - 1,

	ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 19), /* Priority cmds sent to dev */
	ATA_DFLAG_CDL		= (1 << 13), /* supports cmd duration limits */
	ATA_DFLAG_CFG_MASK	= (1 << 14) - 1,

	ATA_DFLAG_PIO		= (1 << 14), /* device limited to PIO mode */
	ATA_DFLAG_NCQ_OFF	= (1 << 15), /* device limited to non-NCQ mode */
	ATA_DFLAG_SLEEPING	= (1 << 16), /* device is sleeping */
	ATA_DFLAG_DUBIOUS_XFER	= (1 << 17), /* data transfer not verified */
	ATA_DFLAG_NO_UNLOAD	= (1 << 18), /* device doesn't support unload */
	ATA_DFLAG_UNLOCK_HPA	= (1 << 19), /* unlock HPA */
	ATA_DFLAG_INIT_MASK	= (1 << 20) - 1,

	ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 20), /* Priority cmds sent to dev */
	ATA_DFLAG_DETACH	= (1 << 24),
	ATA_DFLAG_DETACHED	= (1 << 25),
	ATA_DFLAG_DA		= (1 << 26), /* device supports Device Attention */
@@ -115,7 +116,8 @@ enum {

	ATA_DFLAG_FEATURES_MASK	= (ATA_DFLAG_TRUSTED | ATA_DFLAG_DA |	\
				   ATA_DFLAG_DEVSLP | ATA_DFLAG_NCQ_SEND_RECV | \
				   ATA_DFLAG_NCQ_PRIO | ATA_DFLAG_FUA),
				   ATA_DFLAG_NCQ_PRIO | ATA_DFLAG_FUA | \
				   ATA_DFLAG_CDL),

	ATA_DEV_UNKNOWN		= 0,	/* unknown device */
	ATA_DEV_ATA		= 1,	/* ATA device */
@@ -709,6 +711,9 @@ struct ata_device {
	/* Concurrent positioning ranges */
	struct ata_cpr_log	*cpr_log;

	/* Command Duration Limits log support */
	u8			cdl[ATA_LOG_CDL_SIZE];

	/* error history */
	int			spdn_cnt;
	/* ering is CLEAR_END, read comment above CLEAR_END */