scsi: ata: libata: Detect support for command duration limits
authorDamien Le Moal <dlemoal@kernel.org>
Thu, 11 May 2023 01:13:47 +0000 (03:13 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 22 May 2023 21:05:20 +0000 (17:05 -0400)
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>
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
include/linux/ata.h
include/linux/libata.h

index 8bf612b..83fe037 100644 (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)
index 0727858..3434fec 100644 (file)
@@ -47,15 +47,14 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
 static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
                                        const struct scsi_device *scsidev);
 
-#define RW_RECOVERY_MPAGE 0x1
-#define RW_RECOVERY_MPAGE_LEN 12
-#define CACHE_MPAGE 0x8
-#define CACHE_MPAGE_LEN 20
-#define CONTROL_MPAGE 0xa
-#define CONTROL_MPAGE_LEN 12
-#define ALL_MPAGES 0x3f
-#define ALL_SUB_MPAGES 0xff
-
+#define RW_RECOVERY_MPAGE              0x1
+#define RW_RECOVERY_MPAGE_LEN          12
+#define CACHE_MPAGE                    0x8
+#define CACHE_MPAGE_LEN                        20
+#define CONTROL_MPAGE                  0xa
+#define CONTROL_MPAGE_LEN              12
+#define ALL_MPAGES                     0x3f
+#define ALL_SUB_MPAGES                 0xff
 
 static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
        RW_RECOVERY_MPAGE,
index c224dbd..1eda46b 100644 (file)
@@ -322,15 +322,18 @@ 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,
 
-       /* Identify device SATA settings log:*/
+       /* Identify device SATA settings log: */
        ATA_LOG_DEVSLP_OFFSET     = 0x30,
        ATA_LOG_DEVSLP_SIZE       = 0x08,
        ATA_LOG_DEVSLP_MDAT       = 0x00,
index 311cd93..e8a45f7 100644 (file)
@@ -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 */