Skip to content

Commit 6248852

Browse files
damien-lemoalmartinkpetersen
authored andcommitted
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 <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Co-developed-by: Niklas Cassel <[email protected]> Signed-off-by: Niklas Cassel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 152e52f commit 6248852

File tree

5 files changed

+98
-0
lines changed

5 files changed

+98
-0
lines changed

Documentation/ABI/testing/sysfs-block-device

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,12 @@ Description:
9595
This file does not exist if the HBA driver does not implement
9696
support for the SATA NCQ priority feature, regardless of the
9797
device support for this feature.
98+
99+
100+
What: /sys/block/*/device/cdl_supported
101+
Date: May, 2023
102+
KernelVersion: v6.5
103+
104+
Description:
105+
(RO) Indicates if the device supports the command duration
106+
limits feature found in some ATA and SCSI devices.

drivers/scsi/scsi.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,87 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
570570
}
571571
EXPORT_SYMBOL(scsi_report_opcode);
572572

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+
573654
/**
574655
* scsi_device_get - get an additional reference to a scsi_device
575656
* @sdev: device to get a reference to

drivers/scsi/scsi_scan.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,8 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
10871087
if (sdev->scsi_level >= SCSI_3)
10881088
scsi_attach_vpd(sdev);
10891089

1090+
scsi_cdl_check(sdev);
1091+
10901092
sdev->max_queue_depth = sdev->queue_depth;
10911093
WARN_ON_ONCE(sdev->max_queue_depth > sdev->budget_map.depth);
10921094
sdev->sdev_bflags = *bflags;
@@ -1624,6 +1626,7 @@ void scsi_rescan_device(struct device *dev)
16241626
device_lock(dev);
16251627

16261628
scsi_attach_vpd(sdev);
1629+
scsi_cdl_check(sdev);
16271630

16281631
if (sdev->handler && sdev->handler->rescan)
16291632
sdev->handler->rescan(sdev);

drivers/scsi/scsi_sysfs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ sdev_rd_attr (scsi_level, "%d\n");
670670
sdev_rd_attr (vendor, "%.8s\n");
671671
sdev_rd_attr (model, "%.16s\n");
672672
sdev_rd_attr (rev, "%.4s\n");
673+
sdev_rd_attr (cdl_supported, "%d\n");
673674

674675
static ssize_t
675676
sdev_show_device_busy(struct device *dev, struct device_attribute *attr,
@@ -1300,6 +1301,7 @@ static struct attribute *scsi_sdev_attrs[] = {
13001301
&dev_attr_preferred_path.attr,
13011302
#endif
13021303
&dev_attr_queue_ramp_up_period.attr,
1304+
&dev_attr_cdl_supported.attr,
13031305
REF_EVT(media_change),
13041306
REF_EVT(inquiry_change_reported),
13051307
REF_EVT(capacity_change_reported),

include/scsi/scsi_device.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ struct scsi_device {
218218
unsigned silence_suspend:1; /* Do not print runtime PM related messages */
219219
unsigned no_vpd_size:1; /* No VPD size reported in header */
220220

221+
unsigned cdl_supported:1; /* Command duration limits supported */
222+
221223
unsigned int queue_stopped; /* request queue is quiesced */
222224
bool offline_already; /* Device offline message logged */
223225

@@ -364,6 +366,7 @@ extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
364366
extern void scsi_remove_device(struct scsi_device *);
365367
extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
366368
void scsi_attach_vpd(struct scsi_device *sdev);
369+
void scsi_cdl_check(struct scsi_device *sdev);
367370

368371
extern struct scsi_device *scsi_device_from_queue(struct request_queue *q);
369372
extern int __must_check scsi_device_get(struct scsi_device *);

0 commit comments

Comments
 (0)