]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ata: libata-scsi: Improve CDL control
authorDamien Le Moal <dlemoal@kernel.org>
Mon, 14 Apr 2025 01:25:05 +0000 (10:25 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 May 2025 05:50:47 +0000 (07:50 +0200)
commit 17e897a456752ec9c2d7afb3d9baf268b442451b upstream.

With ATA devices supporting the CDL feature, using CDL requires that the
feature be enabled with a SET FEATURES command. This command is issued
as the translated command for the MODE SELECT command issued by
scsi_cdl_enable() when the user enables CDL through the device
cdl_enable sysfs attribute.

Currently, ata_mselect_control_ata_feature() always translates a MODE
SELECT command for the ATA features subpage of the control mode page to
a SET FEATURES command to enable or disable CDL based on the cdl_ctrl
field. However, there is no need to issue the SET FEATURES command if:
1) The MODE SELECT command requests disabling CDL and CDL is already
   disabled.
2) The MODE SELECT command requests enabling CDL and CDL is already
   enabled.

Fix ata_mselect_control_ata_feature() to issue the SET FEATURES command
only when necessary. Since enabling CDL also implies a reset of the CDL
statistics log page, avoiding useless CDL enable operations also avoids
clearing the CDL statistics log.

Also add debug messages to clearly signal when CDL is being enabled or
disabled using a SET FEATURES command.

Fixes: df60f9c64576 ("scsi: ata: libata: Add ATA feature control sub-page translation")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Igor Pylypiv <ipylypiv@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/ata/libata-scsi.c

index 5377d094bf75480655c0939eaee2c37c5152d9af..4c6a20bd9340c8d9214912a6bbb59d2ca5ad26a3 100644 (file)
@@ -3787,17 +3787,27 @@ static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc,
        /* Check cdl_ctrl */
        switch (buf[0] & 0x03) {
        case 0:
-               /* Disable CDL */
+               /* Disable CDL if it is enabled */
+               if (!(dev->flags & ATA_DFLAG_CDL_ENABLED))
+                       return 0;
+               ata_dev_dbg(dev, "Disabling CDL\n");
                cdl_action = 0;
                dev->flags &= ~ATA_DFLAG_CDL_ENABLED;
                break;
        case 0x02:
-               /* Enable CDL T2A/T2B: NCQ priority must be disabled */
+               /*
+                * Enable CDL if not already enabled. Since this is mutually
+                * exclusive with NCQ priority, allow this only if NCQ priority
+                * is disabled.
+                */
+               if (dev->flags & ATA_DFLAG_CDL_ENABLED)
+                       return 0;
                if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) {
                        ata_dev_err(dev,
                                "NCQ priority must be disabled to enable CDL\n");
                        return -EINVAL;
                }
+               ata_dev_dbg(dev, "Enabling CDL\n");
                cdl_action = 1;
                dev->flags |= ATA_DFLAG_CDL_ENABLED;
                break;