diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-04-25 16:31:10 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-04-25 16:31:10 -0700 |
commit | 1eb09e624f69a619947f262259b3eb90f56ff7f1 (patch) | |
tree | 029b8f50d96177eb9d5ed749d2b66b9085106cac /drivers/scsi/scsi.c | |
parent | eb98f304420c95d1169cc8c73d5427ca9ee29833 (diff) | |
parent | 14a3cc755825ef7b34c986aa2786ea815023e9c5 (diff) |
Merge tag 'ata-6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux
Pull ata fixes from Damien Le Moal:
- Fix the incorrect return type of ata_mselect_control_ata_feature()
- Several fixes for the control of the Command Duration Limits feature
to avoid unnecessary enable and disable actions. Avoiding the
unnecessary enable action also avoids unwanted resets of the CDL
statistics log page as that is implied for any enable action.
- Fix the translation for sensing the control mode page to correctly
return the last enable or disable action performed, as defined in
SAT-6. This correct mode sense information is used to fix the
behavior of the scsi layer to avoid unnecessary mode select command
issuing.
* tag 'ata-6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux:
scsi: Improve CDL control
ata: libata-scsi: Improve CDL control
ata: libata-scsi: Fix ata_msense_control_ata_feature()
ata: libata-scsi: Fix ata_mselect_control_ata_feature() return type
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 53daf923ad8ef..518a252eb6aa0 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; |