Skip to content

Commit 1eb09e6

Browse files
committed
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
2 parents eb98f30 + 14a3cc7 commit 1eb09e6

File tree

2 files changed

+41
-20
lines changed

2 files changed

+41
-20
lines changed

drivers/ata/libata-scsi.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,8 +2453,8 @@ static unsigned int ata_msense_control_ata_feature(struct ata_device *dev,
24532453
*/
24542454
put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]);
24552455

2456-
if (dev->flags & ATA_DFLAG_CDL)
2457-
buf[4] = 0x02; /* Support T2A and T2B pages */
2456+
if (dev->flags & ATA_DFLAG_CDL_ENABLED)
2457+
buf[4] = 0x02; /* T2A and T2B pages enabled */
24582458
else
24592459
buf[4] = 0;
24602460

@@ -3886,12 +3886,11 @@ static int ata_mselect_control_spg0(struct ata_queued_cmd *qc,
38863886
}
38873887

38883888
/*
3889-
* Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode
3889+
* Translate MODE SELECT control mode page, sub-page f2h (ATA feature mode
38903890
* page) into a SET FEATURES command.
38913891
*/
3892-
static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc,
3893-
const u8 *buf, int len,
3894-
u16 *fp)
3892+
static int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc,
3893+
const u8 *buf, int len, u16 *fp)
38953894
{
38963895
struct ata_device *dev = qc->dev;
38973896
struct ata_taskfile *tf = &qc->tf;
@@ -3909,17 +3908,27 @@ static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc,
39093908
/* Check cdl_ctrl */
39103909
switch (buf[0] & 0x03) {
39113910
case 0:
3912-
/* Disable CDL */
3911+
/* Disable CDL if it is enabled */
3912+
if (!(dev->flags & ATA_DFLAG_CDL_ENABLED))
3913+
return 0;
3914+
ata_dev_dbg(dev, "Disabling CDL\n");
39133915
cdl_action = 0;
39143916
dev->flags &= ~ATA_DFLAG_CDL_ENABLED;
39153917
break;
39163918
case 0x02:
3917-
/* Enable CDL T2A/T2B: NCQ priority must be disabled */
3919+
/*
3920+
* Enable CDL if not already enabled. Since this is mutually
3921+
* exclusive with NCQ priority, allow this only if NCQ priority
3922+
* is disabled.
3923+
*/
3924+
if (dev->flags & ATA_DFLAG_CDL_ENABLED)
3925+
return 0;
39183926
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) {
39193927
ata_dev_err(dev,
39203928
"NCQ priority must be disabled to enable CDL\n");
39213929
return -EINVAL;
39223930
}
3931+
ata_dev_dbg(dev, "Enabling CDL\n");
39233932
cdl_action = 1;
39243933
dev->flags |= ATA_DFLAG_CDL_ENABLED;
39253934
break;

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)