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

scsi: core: Detect support for command duration limits

Introduce the function scsi_cdl_check() to detect if a device supports
command duration limits (CDL). Support for the READ 16, WRITE 16, READ 32
and WRITE 32 commands are checked using the function scsi_report_opcode()
to probe the rwcdlp and cdlp bits as they indicate the mode page defining
the command duration limits descriptors that apply to the command being
tested.

If any of these commands support CDL, the field cdl_supported of struct
scsi_device is set to 1 to indicate that the device supports CDL.

Support for CDL for a device is advertizes through sysfs using the new
cdl_supported device attribute. This attribute value is 1 for a device
supporting CDL and 0 otherwise.

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-9-nks@flawful.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Damien Le Moal and committed by
Martin K. Petersen
62488520 152e52fb

+98
+9
Documentation/ABI/testing/sysfs-block-device
··· 95 95 This file does not exist if the HBA driver does not implement 96 96 support for the SATA NCQ priority feature, regardless of the 97 97 device support for this feature. 98 + 99 + 100 + What: /sys/block/*/device/cdl_supported 101 + Date: May, 2023 102 + KernelVersion: v6.5 103 + Contact: linux-scsi@vger.kernel.org 104 + Description: 105 + (RO) Indicates if the device supports the command duration 106 + limits feature found in some ATA and SCSI devices.
+81
drivers/scsi/scsi.c
··· 570 570 } 571 571 EXPORT_SYMBOL(scsi_report_opcode); 572 572 573 + #define SCSI_CDL_CHECK_BUF_LEN 64 574 + 575 + static bool scsi_cdl_check_cmd(struct scsi_device *sdev, u8 opcode, u16 sa, 576 + unsigned char *buf) 577 + { 578 + int ret; 579 + u8 cdlp; 580 + 581 + /* Check operation code */ 582 + ret = scsi_report_opcode(sdev, buf, SCSI_CDL_CHECK_BUF_LEN, opcode, sa); 583 + if (ret <= 0) 584 + return false; 585 + 586 + if ((buf[1] & 0x03) != 0x03) 587 + return false; 588 + 589 + /* See SPC-6, one command format of REPORT SUPPORTED OPERATION CODES */ 590 + cdlp = (buf[1] & 0x18) >> 3; 591 + if (buf[0] & 0x01) { 592 + /* rwcdlp == 1 */ 593 + switch (cdlp) { 594 + case 0x01: 595 + /* T2A page */ 596 + return true; 597 + case 0x02: 598 + /* T2B page */ 599 + return true; 600 + } 601 + } else { 602 + /* rwcdlp == 0 */ 603 + switch (cdlp) { 604 + case 0x01: 605 + /* A page */ 606 + return true; 607 + case 0x02: 608 + /* B page */ 609 + return true; 610 + } 611 + } 612 + 613 + return false; 614 + } 615 + 616 + /** 617 + * scsi_cdl_check - Check if a SCSI device supports Command Duration Limits 618 + * @sdev: The device to check 619 + */ 620 + void scsi_cdl_check(struct scsi_device *sdev) 621 + { 622 + bool cdl_supported; 623 + unsigned char *buf; 624 + 625 + buf = kmalloc(SCSI_CDL_CHECK_BUF_LEN, GFP_KERNEL); 626 + if (!buf) { 627 + sdev->cdl_supported = 0; 628 + return; 629 + } 630 + 631 + /* Check support for READ_16, WRITE_16, READ_32 and WRITE_32 commands */ 632 + cdl_supported = 633 + scsi_cdl_check_cmd(sdev, READ_16, 0, buf) || 634 + scsi_cdl_check_cmd(sdev, WRITE_16, 0, buf) || 635 + scsi_cdl_check_cmd(sdev, VARIABLE_LENGTH_CMD, READ_32, buf) || 636 + scsi_cdl_check_cmd(sdev, VARIABLE_LENGTH_CMD, WRITE_32, buf); 637 + if (cdl_supported) { 638 + /* 639 + * We have CDL support: force the use of READ16/WRITE16. 640 + * READ32 and WRITE32 will be used for devices that support 641 + * the T10_PI_TYPE2_PROTECTION protection type. 642 + */ 643 + sdev->use_16_for_rw = 1; 644 + sdev->use_10_for_rw = 0; 645 + 646 + sdev->cdl_supported = 1; 647 + } else { 648 + sdev->cdl_supported = 0; 649 + } 650 + 651 + kfree(buf); 652 + } 653 + 573 654 /** 574 655 * scsi_device_get - get an additional reference to a scsi_device 575 656 * @sdev: device to get a reference to
+3
drivers/scsi/scsi_scan.c
··· 1087 1087 if (sdev->scsi_level >= SCSI_3) 1088 1088 scsi_attach_vpd(sdev); 1089 1089 1090 + scsi_cdl_check(sdev); 1091 + 1090 1092 sdev->max_queue_depth = sdev->queue_depth; 1091 1093 WARN_ON_ONCE(sdev->max_queue_depth > sdev->budget_map.depth); 1092 1094 sdev->sdev_bflags = *bflags; ··· 1626 1624 device_lock(dev); 1627 1625 1628 1626 scsi_attach_vpd(sdev); 1627 + scsi_cdl_check(sdev); 1629 1628 1630 1629 if (sdev->handler && sdev->handler->rescan) 1631 1630 sdev->handler->rescan(sdev);
+2
drivers/scsi/scsi_sysfs.c
··· 670 670 sdev_rd_attr (vendor, "%.8s\n"); 671 671 sdev_rd_attr (model, "%.16s\n"); 672 672 sdev_rd_attr (rev, "%.4s\n"); 673 + sdev_rd_attr (cdl_supported, "%d\n"); 673 674 674 675 static ssize_t 675 676 sdev_show_device_busy(struct device *dev, struct device_attribute *attr, ··· 1301 1300 &dev_attr_preferred_path.attr, 1302 1301 #endif 1303 1302 &dev_attr_queue_ramp_up_period.attr, 1303 + &dev_attr_cdl_supported.attr, 1304 1304 REF_EVT(media_change), 1305 1305 REF_EVT(inquiry_change_reported), 1306 1306 REF_EVT(capacity_change_reported),
+3
include/scsi/scsi_device.h
··· 218 218 unsigned silence_suspend:1; /* Do not print runtime PM related messages */ 219 219 unsigned no_vpd_size:1; /* No VPD size reported in header */ 220 220 221 + unsigned cdl_supported:1; /* Command duration limits supported */ 222 + 221 223 unsigned int queue_stopped; /* request queue is quiesced */ 222 224 bool offline_already; /* Device offline message logged */ 223 225 ··· 366 364 extern void scsi_remove_device(struct scsi_device *); 367 365 extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); 368 366 void scsi_attach_vpd(struct scsi_device *sdev); 367 + void scsi_cdl_check(struct scsi_device *sdev); 369 368 370 369 extern struct scsi_device *scsi_device_from_queue(struct request_queue *q); 371 370 extern int __must_check scsi_device_get(struct scsi_device *);