Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: ata: libata: Add ATA feature control sub-page translation

Add support for the ATA feature control sub-page of the control mode page
to enable/disable the command duration limits feature using the cdl_ctrl
field of the ATA feature control sub-page.

Both mode sense and mode select translation are supported. For mode sense,
the ata device flag ATA_DFLAG_CDL_ENABLED is used to cache the status of
the command duration limits feature. Enabling this feature is done using a
SET FEATURES command with a cdl action set to 1 when the page cdl_ctrl
field value is 0x2 (T2A and T2B pages supported). If this field is 0, CDL
is disabled using the SET FEATURES command with a cdl action set to 0.

Since a device CDL and NCQ priority features should not be used
simultaneously, ata_mselect_control_ata_feature() returns an error when
attempting to enable CDL with the device priority feature enabled.
Conversely, the function ata_ncq_prio_enable_store() used to enable the use
of the device NCQ priority feature through sysfs is modified to return an
error if the device CDL feature is enabled.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Co-developed-by: Niklas Cassel <niklas.cassel@wdc.com>
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Link: https://lore.kernel.org/r/20230511011356.227789-18-nks@flawful.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Damien Le Moal and committed by
Martin K. Petersen
df60f9c6 673b2fe6

+193 -29
+38 -2
drivers/ata/libata-core.c
··· 2371 2371 { 2372 2372 struct ata_port *ap = dev->link->ap; 2373 2373 unsigned int err_mask; 2374 + bool cdl_enabled; 2374 2375 u64 val; 2375 2376 2376 2377 if (ata_id_major_version(dev->id) < 12) 2377 2378 goto not_supported; 2378 2379 2379 2380 if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE) || 2380 - !ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES)) 2381 + !ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES) || 2382 + !ata_identify_page_supported(dev, ATA_LOG_CURRENT_SETTINGS)) 2381 2383 goto not_supported; 2382 2384 2383 2385 err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ··· 2399 2397 "Command duration guideline is not supported\n"); 2400 2398 2401 2399 /* 2400 + * If CDL is marked as enabled, make sure the feature is enabled too. 2401 + * Conversely, if CDL is disabled, make sure the feature is turned off. 2402 + */ 2403 + err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 2404 + ATA_LOG_CURRENT_SETTINGS, 2405 + ap->sector_buf, 1); 2406 + if (err_mask) 2407 + goto not_supported; 2408 + 2409 + val = get_unaligned_le64(&ap->sector_buf[8]); 2410 + cdl_enabled = val & BIT_ULL(63) && val & BIT_ULL(21); 2411 + if (dev->flags & ATA_DFLAG_CDL_ENABLED) { 2412 + if (!cdl_enabled) { 2413 + /* Enable CDL on the device */ 2414 + err_mask = ata_dev_set_feature(dev, SETFEATURES_CDL, 1); 2415 + if (err_mask) { 2416 + ata_dev_err(dev, 2417 + "Enable CDL feature failed\n"); 2418 + goto not_supported; 2419 + } 2420 + } 2421 + } else { 2422 + if (cdl_enabled) { 2423 + /* Disable CDL on the device */ 2424 + err_mask = ata_dev_set_feature(dev, SETFEATURES_CDL, 0); 2425 + if (err_mask) { 2426 + ata_dev_err(dev, 2427 + "Disable CDL feature failed\n"); 2428 + goto not_supported; 2429 + } 2430 + } 2431 + } 2432 + 2433 + /* 2402 2434 * Command duration limits is supported: cache the CDL log page 18h 2403 2435 * (command duration descriptors). 2404 2436 */ ··· 2448 2412 return; 2449 2413 2450 2414 not_supported: 2451 - dev->flags &= ~ATA_DFLAG_CDL; 2415 + dev->flags &= ~(ATA_DFLAG_CDL | ATA_DFLAG_CDL_ENABLED); 2452 2416 } 2453 2417 2454 2418 static int ata_dev_config_lba(struct ata_device *dev)
+9 -2
drivers/ata/libata-sata.c
··· 907 907 goto unlock; 908 908 } 909 909 910 - if (input) 910 + if (input) { 911 + if (dev->flags & ATA_DFLAG_CDL_ENABLED) { 912 + ata_dev_err(dev, 913 + "CDL must be disabled to enable NCQ priority\n"); 914 + rc = -EINVAL; 915 + goto unlock; 916 + } 911 917 dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED; 912 - else 918 + } else { 913 919 dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED; 920 + } 914 921 915 922 unlock: 916 923 spin_unlock_irq(ap->lock);
+142 -25
drivers/ata/libata-scsi.c
··· 58 58 #define CDL_T2A_SUB_MPAGE 0x07 59 59 #define CDL_T2B_SUB_MPAGE 0x08 60 60 #define CDL_T2_SUB_MPAGE_LEN 232 61 + #define ATA_FEATURE_SUB_MPAGE 0xf2 62 + #define ATA_FEATURE_SUB_MPAGE_LEN 16 61 63 62 64 static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = { 63 65 RW_RECOVERY_MPAGE, ··· 2288 2286 return CDL_T2_SUB_MPAGE_LEN; 2289 2287 } 2290 2288 2289 + /* 2290 + * Simulate MODE SENSE control mode page, sub-page f2h 2291 + * (ATA feature control mode page). 2292 + */ 2293 + static unsigned int ata_msense_control_ata_feature(struct ata_device *dev, 2294 + u8 *buf) 2295 + { 2296 + /* PS=0, SPF=1 */ 2297 + buf[0] = CONTROL_MPAGE | (1 << 6); 2298 + buf[1] = ATA_FEATURE_SUB_MPAGE; 2299 + 2300 + /* 2301 + * The first four bytes of ATA Feature Control mode page are a header. 2302 + * The PAGE LENGTH field is the size of the page excluding the header. 2303 + */ 2304 + put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]); 2305 + 2306 + if (dev->flags & ATA_DFLAG_CDL) 2307 + buf[4] = 0x02; /* Support T2A and T2B pages */ 2308 + else 2309 + buf[4] = 0; 2310 + 2311 + return ATA_FEATURE_SUB_MPAGE_LEN; 2312 + } 2313 + 2291 2314 /** 2292 2315 * ata_msense_control - Simulate MODE SENSE control mode page 2293 2316 * @dev: ATA device of interest ··· 2336 2309 case CDL_T2A_SUB_MPAGE: 2337 2310 case CDL_T2B_SUB_MPAGE: 2338 2311 return ata_msense_control_spgt2(dev, buf, spg); 2312 + case ATA_FEATURE_SUB_MPAGE: 2313 + return ata_msense_control_ata_feature(dev, buf); 2339 2314 case ALL_SUB_MPAGES: 2340 2315 n = ata_msense_control_spg0(dev, buf, changeable); 2341 2316 n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); 2342 2317 n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE); 2318 + n += ata_msense_control_ata_feature(dev, buf + n); 2343 2319 return n; 2344 2320 default: 2345 2321 return 0; ··· 2421 2391 spg = scsicmd[3]; 2422 2392 2423 2393 /* 2424 - * Supported subpages: all subpages and sub-pages 07h and 08h of 2394 + * Supported subpages: all subpages and sub-pages 07h, 08h and f2h of 2425 2395 * the control page. 2426 2396 */ 2427 2397 if (spg) { ··· 2430 2400 break; 2431 2401 case CDL_T2A_SUB_MPAGE: 2432 2402 case CDL_T2B_SUB_MPAGE: 2403 + case ATA_FEATURE_SUB_MPAGE: 2433 2404 if (dev->flags & ATA_DFLAG_CDL && pg == CONTROL_MPAGE) 2434 2405 break; 2435 2406 fallthrough; ··· 3739 3708 return 0; 3740 3709 } 3741 3710 3742 - /** 3743 - * ata_mselect_control - Simulate MODE SELECT for control page 3744 - * @qc: Storage for translated ATA taskfile 3745 - * @buf: input buffer 3746 - * @len: number of valid bytes in the input buffer 3747 - * @fp: out parameter for the failed field on error 3748 - * 3749 - * Prepare a taskfile to modify caching information for the device. 3750 - * 3751 - * LOCKING: 3752 - * None. 3711 + /* 3712 + * Simulate MODE SELECT control mode page, sub-page 0. 3753 3713 */ 3754 - static int ata_mselect_control(struct ata_queued_cmd *qc, 3755 - const u8 *buf, int len, u16 *fp) 3714 + static int ata_mselect_control_spg0(struct ata_queued_cmd *qc, 3715 + const u8 *buf, int len, u16 *fp) 3756 3716 { 3757 3717 struct ata_device *dev = qc->dev; 3758 3718 u8 mpage[CONTROL_MPAGE_LEN]; ··· 3781 3759 return 0; 3782 3760 } 3783 3761 3762 + /* 3763 + * Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode 3764 + * page) into a SET FEATURES command. 3765 + */ 3766 + static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc, 3767 + const u8 *buf, int len, 3768 + u16 *fp) 3769 + { 3770 + struct ata_device *dev = qc->dev; 3771 + struct ata_taskfile *tf = &qc->tf; 3772 + u8 cdl_action; 3773 + 3774 + /* 3775 + * The first four bytes of ATA Feature Control mode page are a header, 3776 + * so offsets in mpage are off by 4 compared to buf. Same for len. 3777 + */ 3778 + if (len != ATA_FEATURE_SUB_MPAGE_LEN - 4) { 3779 + *fp = min(len, ATA_FEATURE_SUB_MPAGE_LEN - 4); 3780 + return -EINVAL; 3781 + } 3782 + 3783 + /* Check cdl_ctrl */ 3784 + switch (buf[0] & 0x03) { 3785 + case 0: 3786 + /* Disable CDL */ 3787 + cdl_action = 0; 3788 + dev->flags &= ~ATA_DFLAG_CDL_ENABLED; 3789 + break; 3790 + case 0x02: 3791 + /* Enable CDL T2A/T2B: NCQ priority must be disabled */ 3792 + if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) { 3793 + ata_dev_err(dev, 3794 + "NCQ priority must be disabled to enable CDL\n"); 3795 + return -EINVAL; 3796 + } 3797 + cdl_action = 1; 3798 + dev->flags |= ATA_DFLAG_CDL_ENABLED; 3799 + break; 3800 + default: 3801 + *fp = 0; 3802 + return -EINVAL; 3803 + } 3804 + 3805 + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; 3806 + tf->protocol = ATA_PROT_NODATA; 3807 + tf->command = ATA_CMD_SET_FEATURES; 3808 + tf->feature = SETFEATURES_CDL; 3809 + tf->nsect = cdl_action; 3810 + 3811 + return 1; 3812 + } 3813 + 3814 + /** 3815 + * ata_mselect_control - Simulate MODE SELECT for control page 3816 + * @qc: Storage for translated ATA taskfile 3817 + * @buf: input buffer 3818 + * @len: number of valid bytes in the input buffer 3819 + * @fp: out parameter for the failed field on error 3820 + * 3821 + * Prepare a taskfile to modify caching information for the device. 3822 + * 3823 + * LOCKING: 3824 + * None. 3825 + */ 3826 + static int ata_mselect_control(struct ata_queued_cmd *qc, u8 spg, 3827 + const u8 *buf, int len, u16 *fp) 3828 + { 3829 + switch (spg) { 3830 + case 0: 3831 + return ata_mselect_control_spg0(qc, buf, len, fp); 3832 + case ATA_FEATURE_SUB_MPAGE: 3833 + return ata_mselect_control_ata_feature(qc, buf, len, fp); 3834 + default: 3835 + return -EINVAL; 3836 + } 3837 + } 3838 + 3784 3839 /** 3785 3840 * ata_scsi_mode_select_xlat - Simulate MODE SELECT 6, 10 commands 3786 3841 * @qc: Storage for translated ATA taskfile ··· 3875 3776 const u8 *cdb = scmd->cmnd; 3876 3777 u8 pg, spg; 3877 3778 unsigned six_byte, pg_len, hdr_len, bd_len; 3878 - int len; 3779 + int len, ret; 3879 3780 u16 fp = (u16)-1; 3880 3781 u8 bp = 0xff; 3881 3782 u8 buffer[64]; ··· 3960 3861 } 3961 3862 3962 3863 /* 3963 - * No mode subpages supported (yet) but asking for _all_ 3964 - * subpages may be valid 3864 + * Supported subpages: all subpages and ATA feature sub-page f2h of 3865 + * the control page. 3965 3866 */ 3966 - if (spg && (spg != ALL_SUB_MPAGES)) { 3967 - fp = (p[0] & 0x40) ? 1 : 0; 3968 - fp += hdr_len + bd_len; 3969 - goto invalid_param; 3867 + if (spg) { 3868 + switch (spg) { 3869 + case ALL_SUB_MPAGES: 3870 + /* All subpages is not supported for the control page */ 3871 + if (pg == CONTROL_MPAGE) { 3872 + fp = (p[0] & 0x40) ? 1 : 0; 3873 + fp += hdr_len + bd_len; 3874 + goto invalid_param; 3875 + } 3876 + break; 3877 + case ATA_FEATURE_SUB_MPAGE: 3878 + if (qc->dev->flags & ATA_DFLAG_CDL && 3879 + pg == CONTROL_MPAGE) 3880 + break; 3881 + fallthrough; 3882 + default: 3883 + fp = (p[0] & 0x40) ? 1 : 0; 3884 + fp += hdr_len + bd_len; 3885 + goto invalid_param; 3886 + } 3970 3887 } 3971 3888 if (pg_len > len) 3972 3889 goto invalid_param_len; ··· 3995 3880 } 3996 3881 break; 3997 3882 case CONTROL_MPAGE: 3998 - if (ata_mselect_control(qc, p, pg_len, &fp) < 0) { 3883 + ret = ata_mselect_control(qc, spg, p, pg_len, &fp); 3884 + if (ret < 0) { 3999 3885 fp += hdr_len + bd_len; 4000 3886 goto invalid_param; 4001 - } else { 4002 - goto skip; /* No ATA command to send */ 4003 3887 } 3888 + if (!ret) 3889 + goto skip; /* No ATA command to send */ 4004 3890 break; 4005 - default: /* invalid page code */ 3891 + default: 3892 + /* Invalid page code */ 4006 3893 fp = bd_len + hdr_len; 4007 3894 goto invalid_param; 4008 3895 }
+3
include/linux/ata.h
··· 329 329 330 330 /* Identify device log pages: */ 331 331 ATA_LOG_SUPPORTED_CAPABILITIES = 0x03, 332 + ATA_LOG_CURRENT_SETTINGS = 0x04, 332 333 ATA_LOG_SECURITY = 0x06, 333 334 ATA_LOG_SATA_SETTINGS = 0x08, 334 335 ATA_LOG_ZONED_INFORMATION = 0x09, ··· 418 417 419 418 SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */ 420 419 SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */ 420 + 421 + SETFEATURES_CDL = 0x0d, /* Enable/disable cmd duration limits */ 421 422 422 423 /* SETFEATURE Sector counts for SATA features */ 423 424 SATA_FPDMA_OFFSET = 0x01, /* FPDMA non-zero buffer offsets */
+1
include/linux/libata.h
··· 106 106 ATA_DFLAG_INIT_MASK = (1 << 20) - 1, 107 107 108 108 ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 20), /* Priority cmds sent to dev */ 109 + ATA_DFLAG_CDL_ENABLED = (1 << 21), /* cmd duration limits is enabled */ 109 110 ATA_DFLAG_DETACH = (1 << 24), 110 111 ATA_DFLAG_DETACHED = (1 << 25), 111 112 ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */