From 86dcc5dea79ab7dc2517174aa784a2844096857e Mon Sep 17 00:00:00 2001
From: Lee Duncan <lduncan@suse.com>
Date: Jun 02 2025 19:53:20 +0000
Subject: scsi: Improve CDL control (git-fixes).


---

diff --git a/patches.suse/scsi-Improve-CDL-control.patch b/patches.suse/scsi-Improve-CDL-control.patch
new file mode 100644
index 0000000..1f1b4b4
--- /dev/null
+++ b/patches.suse/scsi-Improve-CDL-control.patch
@@ -0,0 +1,122 @@
+From: Damien Le Moal <dlemoal@kernel.org>
+Date: Sun, 13 Apr 2025 11:24:47 +0900
+Subject: scsi: Improve CDL control
+Git-commit: 14a3cc755825ef7b34c986aa2786ea815023e9c5
+Patch-mainline: v6.15-rc4
+References: git-fixes
+
+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.
+
+However, the implementation of scsi_cdl_enable() always issues a MODE
+SELECT command for ATA devices when the enable argument is true, even if
+CDL is already enabled on the device. While this does not cause any
+issue with using CDL descriptors with read/write commands (the CDL
+feature will be enabled on the drive), issuing the MODE SELECT command
+even when the device CDL feature is already enabled will cause a reset
+of the ATA device CDL statistics log page (as defined in ACS, any CDL
+enable action must reset the device statistics).
+
+Avoid this needless actions (and the implied statistics log page reset)
+by modifying scsi_cdl_enable() to issue the MODE SELECT command to
+enable CDL if and only if CDL is not reported as already enabled on the
+device.
+
+And while at it, simplify the initialization of the is_ata boolean
+variable and move the declaration of the scsi mode data and sense header
+variables to within the scope of ATA device handling.
+
+Fixes: 1b22cfb14142 ("scsi: core: Allow enabling and disabling command duration limits")
+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>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Acked-by: Lee Duncan <lduncan@suse.com>
+---
+ drivers/scsi/scsi.c | 36 ++++++++++++++++++++++++------------
+ 1 file changed, 24 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
+index 53daf923ad8e..518a252eb6aa 100644
+--- a/drivers/scsi/scsi.c
++++ b/drivers/scsi/scsi.c
+@@ -707,26 +707,23 @@ void scsi_cdl_check(struct scsi_device *sdev)
+  */
+ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
+ {
+-	struct scsi_mode_data data;
+-	struct scsi_sense_hdr sshdr;
+-	struct scsi_vpd *vpd;
+-	bool is_ata = false;
+ 	char buf[64];
++	bool is_ata;
+ 	int ret;
+ 
+ 	if (!sdev->cdl_supported)
+ 		return -EOPNOTSUPP;
+ 
+ 	rcu_read_lock();
+-	vpd = rcu_dereference(sdev->vpd_pg89);
+-	if (vpd)
+-		is_ata = true;
++	is_ata = rcu_dereference(sdev->vpd_pg89);
+ 	rcu_read_unlock();
+ 
+ 	/*
+ 	 * For ATA devices, CDL needs to be enabled with a SET FEATURES command.
+ 	 */
+ 	if (is_ata) {
++		struct scsi_mode_data data;
++		struct scsi_sense_hdr sshdr;
+ 		char *buf_data;
+ 		int len;
+ 
+@@ -735,16 +732,30 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
+ 		if (ret)
+ 			return -EINVAL;
+ 
+-		/* Enable CDL using the ATA feature page */
++		/* Enable or disable CDL using the ATA feature page */
+ 		len = min_t(size_t, sizeof(buf),
+ 			    data.length - data.header_length -
+ 			    data.block_descriptor_length);
+ 		buf_data = buf + data.header_length +
+ 			data.block_descriptor_length;
+-		if (enable)
+-			buf_data[4] = 0x02;
+-		else
+-			buf_data[4] = 0;
++
++		/*
++		 * If we want to enable CDL and CDL is already enabled on the
++		 * device, do nothing. This avoids needlessly resetting the CDL
++		 * statistics on the device as that is implied by the CDL enable
++		 * action. Similar to this, there is no need to do anything if
++		 * we want to disable CDL and CDL is already disabled.
++		 */
++		if (enable) {
++			if ((buf_data[4] & 0x03) == 0x02)
++				goto out;
++			buf_data[4] &= ~0x03;
++			buf_data[4] |= 0x02;
++		} else {
++			if ((buf_data[4] & 0x03) == 0x00)
++				goto out;
++			buf_data[4] &= ~0x03;
++		}
+ 
+ 		ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3,
+ 				       &data, &sshdr);
+@@ -756,6 +767,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
+ 		}
+ 	}
+ 
++out:
+ 	sdev->cdl_enable = enable;
+ 
+ 	return 0;
+
diff --git a/series.conf b/series.conf
index 0c6ddac..d62e6b7 100644
--- a/series.conf
+++ b/series.conf
@@ -31720,6 +31720,7 @@
 	patches.suse/ata-libata-scsi-Fix-ata_mselect_control_ata_feature-.patch
 	patches.suse/ata-libata-scsi-Fix-ata_msense_control_ata_feature.patch
 	patches.suse/ata-libata-scsi-Improve-CDL-control.patch
+	patches.suse/scsi-Improve-CDL-control.patch
 	patches.suse/Revert-drm-meson-vclk-fix-calculation-of-59.94-fract.patch
 	patches.suse/drm-amd-display-Fix-gpu-reset-in-multidisplay-config.patch
 	patches.suse/drm-amd-display-Force-full-update-in-gpu-reset.patch