Skip to content

Commit 14a3cc7

Browse files
committed
scsi: Improve CDL control
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: 1b22cfb ("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>
1 parent 17e897a commit 14a3cc7

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

drivers/scsi/scsi.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -707,26 +707,23 @@ void scsi_cdl_check(struct scsi_device *sdev)
707707
*/
708708
int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
709709
{
710-
struct scsi_mode_data data;
711-
struct scsi_sense_hdr sshdr;
712-
struct scsi_vpd *vpd;
713-
bool is_ata = false;
714710
char buf[64];
711+
bool is_ata;
715712
int ret;
716713

717714
if (!sdev->cdl_supported)
718715
return -EOPNOTSUPP;
719716

720717
rcu_read_lock();
721-
vpd = rcu_dereference(sdev->vpd_pg89);
722-
if (vpd)
723-
is_ata = true;
718+
is_ata = rcu_dereference(sdev->vpd_pg89);
724719
rcu_read_unlock();
725720

726721
/*
727722
* For ATA devices, CDL needs to be enabled with a SET FEATURES command.
728723
*/
729724
if (is_ata) {
725+
struct scsi_mode_data data;
726+
struct scsi_sense_hdr sshdr;
730727
char *buf_data;
731728
int len;
732729

@@ -735,16 +732,30 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
735732
if (ret)
736733
return -EINVAL;
737734

738-
/* Enable CDL using the ATA feature page */
735+
/* Enable or disable CDL using the ATA feature page */
739736
len = min_t(size_t, sizeof(buf),
740737
data.length - data.header_length -
741738
data.block_descriptor_length);
742739
buf_data = buf + data.header_length +
743740
data.block_descriptor_length;
744-
if (enable)
745-
buf_data[4] = 0x02;
746-
else
747-
buf_data[4] = 0;
741+
742+
/*
743+
* If we want to enable CDL and CDL is already enabled on the
744+
* device, do nothing. This avoids needlessly resetting the CDL
745+
* statistics on the device as that is implied by the CDL enable
746+
* action. Similar to this, there is no need to do anything if
747+
* we want to disable CDL and CDL is already disabled.
748+
*/
749+
if (enable) {
750+
if ((buf_data[4] & 0x03) == 0x02)
751+
goto out;
752+
buf_data[4] &= ~0x03;
753+
buf_data[4] |= 0x02;
754+
} else {
755+
if ((buf_data[4] & 0x03) == 0x00)
756+
goto out;
757+
buf_data[4] &= ~0x03;
758+
}
748759

749760
ret = scsi_mode_select(sdev, 1, 0, buf_data, len, 5 * HZ, 3,
750761
&data, &sshdr);
@@ -756,6 +767,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
756767
}
757768
}
758769

770+
out:
759771
sdev->cdl_enable = enable;
760772

761773
return 0;

0 commit comments

Comments
 (0)