From ac0dd0f33adb804b8301ae415a91f56f97f40bae Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 3 Feb 2024 15:39:02 -0300 Subject: scsi: scsi_debug: Make pseudo_lld_bus const Now that the driver core can properly handle constant struct bus_type, move the pseudo_lld_bus variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Link: https://lore.kernel.org/r/20240203-bus_cleanup-scsi-v1-3-6f552fb24f71@marliere.net Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d03d66f11493..914d9c12e741 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -899,7 +899,7 @@ static int poll_queues; /* iouring iopoll interface.*/ static char sdebug_proc_name[] = MY_NAME; static const char *my_name = MY_NAME; -static struct bus_type pseudo_lld_bus; +static const struct bus_type pseudo_lld_bus; static struct device_driver sdebug_driverfs_driver = { .name = sdebug_proc_name, @@ -8405,7 +8405,7 @@ static void sdebug_driver_remove(struct device *dev) scsi_host_put(sdbg_host->shost); } -static struct bus_type pseudo_lld_bus = { +static const struct bus_type pseudo_lld_bus = { .name = "pseudo", .probe = sdebug_driver_probe, .remove = sdebug_driver_remove, -- cgit v1.2.3 From a5fe98eb8f630f3ad3d1d5c16374621e8c0cd702 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:38 -0800 Subject: scsi: scsi_debug: Reduce code duplication All VPD pages have the page code in byte one. Reduce code duplication by storing the VPD page code once. Reviewed-by: Avri Altman Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-13-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d03d66f11493..994a2b829b94 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1903,7 +1903,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) u32 len; char lu_id_str[6]; int host_no = devip->sdbg_host->shost->host_no; - + + arr[1] = cmd[2]; port_group_id = (((host_no + 1) & 0x7f) << 8) + (devip->channel & 0x7f); if (sdebug_vpd_use_hostno == 0) @@ -1914,7 +1915,6 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) (devip->target * 1000) - 3; len = scnprintf(lu_id_str, 6, "%d", lu_id_num); if (0 == cmd[2]) { /* supported vital product data pages */ - arr[1] = cmd[2]; /*sanity */ n = 4; arr[n++] = 0x0; /* this page */ arr[n++] = 0x80; /* unit serial number */ @@ -1935,23 +1935,18 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ - arr[1] = cmd[2]; /*sanity */ arr[3] = len; memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_83(&arr[4], port_group_id, target_dev_id, lu_id_num, lu_id_str, len, &devip->lu_name); } else if (0x84 == cmd[2]) { /* Software interface ident. */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_84(&arr[4]); } else if (0x85 == cmd[2]) { /* Management network addresses */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_85(&arr[4]); } else if (0x86 == cmd[2]) { /* extended inquiry */ - arr[1] = cmd[2]; /*sanity */ arr[3] = 0x3c; /* number of following entries */ if (sdebug_dif == T10_PI_TYPE3_PROTECTION) arr[4] = 0x4; /* SPT: GRD_CHK:1 */ @@ -1961,30 +1956,23 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[4] = 0x0; /* no protection stuff */ arr[5] = 0x7; /* head of q, ordered + simple q's */ } else if (0x87 == cmd[2]) { /* mode page policy */ - arr[1] = cmd[2]; /*sanity */ arr[3] = 0x8; /* number of following entries */ arr[4] = 0x2; /* disconnect-reconnect mp */ arr[6] = 0x80; /* mlus, shared */ arr[8] = 0x18; /* protocol specific lu */ arr[10] = 0x82; /* mlus, per initiator port */ } else if (0x88 == cmd[2]) { /* SCSI Ports */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ - arr[1] = cmd[2]; /*sanity */ n = inquiry_vpd_89(&arr[4]); put_unaligned_be16(n, arr + 2); } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b0(&arr[4]); } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b1(devip, &arr[4]); } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b2(&arr[4]); } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ - arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b6(devip, &arr[4]); } else { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); -- cgit v1.2.3 From b1e5c0b34db8e7dac04af618e53c64e70c86aac8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:39 -0800 Subject: scsi: scsi_debug: Support the block limits extension VPD page >From SBC-5 r05: "Reduced stream control: a) reduces the maximum number of streams that the device server supports; and b) increases the number of write commands that are able to specify a stream to be written in any write command that contains the GROUP NUMBER field in its CDB. If the RSCS bit (see 6.6.5) is set to one, then the device server shall: a) support per group stream identifier usage as described in 4.32.2; b) support the IO Advice Hints Grouping mode page (see 6.5.7); and c) set the MAXIMUM NUMBER OF STREAMS field (see 6.6.5) to a value that is less than 64. Device servers that set the RSCS bit to one may support other features (e.g., permanent streams (see 4.32.4)). 4.32.4 Permanent streams A permanent stream is a stream for which the device server does not allow closing or otherwise modifying the configuration of that stream. The PERM bit (see 5.9.2.3) indicates whether a stream is a permanent stream. If a STREAM CONTROL command (see 5.32) specifies the closing of a permanent stream, the device server terminates that command with CHECK CONDITION status instead of closing the specified stream. A permanent stream is always an open stream. Device severs should assign the lowest numbered stream identifiers to permanent streams." Report that reduced stream control is supported. Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-14-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 994a2b829b94..8dba838ef983 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1867,6 +1867,19 @@ static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) return 0x3c; } +#define SDEBUG_BLE_LEN_AFTER_B4 28 /* thus vpage 32 bytes long */ + +enum { MAXIMUM_NUMBER_OF_STREAMS = 6, PERMANENT_STREAM_COUNT = 5 }; + +/* Block limits extension VPD page (SBC-4) */ +static int inquiry_vpd_b7(unsigned char *arrb4) +{ + memset(arrb4, 0, SDEBUG_BLE_LEN_AFTER_B4); + arrb4[1] = 1; /* Reduced stream control support (RSCS) */ + put_unaligned_be16(MAXIMUM_NUMBER_OF_STREAMS, &arrb4[2]); + return SDEBUG_BLE_LEN_AFTER_B4; +} + #define SDEBUG_LONG_INQ_SZ 96 #define SDEBUG_MAX_INQ_ARR_SZ 584 @@ -1932,6 +1945,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[n++] = 0xb2; /* LB Provisioning */ if (is_zbc) arr[n++] = 0xb6; /* ZB dev. char. */ + arr[n++] = 0xb7; /* Block limits extension */ } arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ @@ -1974,6 +1988,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[3] = inquiry_vpd_b2(&arr[4]); } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ arr[3] = inquiry_vpd_b6(devip, &arr[4]); + } else if (cmd[2] == 0xb7) { /* block limits extension page */ + arr[3] = inquiry_vpd_b7(&arr[4]); } else { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); kfree(arr); -- cgit v1.2.3 From b2f860903fe9774f755a917edc674ba6e879fa55 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:40 -0800 Subject: scsi: scsi_debug: Rework page code error handling Instead of tracking whether or not the page code is valid in a boolean variable, jump to error handling code if an unsupported page code is encountered. Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-15-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 8dba838ef983..ba0a29e6a86d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2644,7 +2644,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, unsigned char *ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = scp->cmnd; - bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; + bool dbd, llbaa, msense_6, is_disk, is_zbc; dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ pcontrol = (cmd[2] & 0xc0) >> 6; @@ -2708,7 +2708,6 @@ static int resp_mode_sense(struct scsi_cmnd *scp, mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); return check_condition_result; } - bad_pcode = false; switch (pcode) { case 0x1: /* Read-Write error recovery page, direct access */ @@ -2723,15 +2722,17 @@ static int resp_mode_sense(struct scsi_cmnd *scp, if (is_disk) { len = resp_format_pg(ap, pcontrol, target); offset += len; - } else - bad_pcode = true; + } else { + goto bad_pcode; + } break; case 0x8: /* Caching page, direct access */ if (is_disk || is_zbc) { len = resp_caching_pg(ap, pcontrol, target); offset += len; - } else - bad_pcode = true; + } else { + goto bad_pcode; + } break; case 0xa: /* Control Mode page, all devices */ len = resp_ctrl_m_pg(ap, pcontrol, target); @@ -2784,18 +2785,17 @@ static int resp_mode_sense(struct scsi_cmnd *scp, } break; default: - bad_pcode = true; - break; - } - if (bad_pcode) { - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); - return check_condition_result; + goto bad_pcode; } if (msense_6) arr[0] = offset - 1; else put_unaligned_be16((offset - 2), arr + 0); return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); + +bad_pcode: + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); + return check_condition_result; } #define SDEBUG_MAX_MSELECT_SZ 512 -- cgit v1.2.3 From f19c3e4fe2542d7b145d294386666958c9fabe17 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:41 -0800 Subject: scsi: scsi_debug: Rework subpage code error handling Move the subpage code checks into the switch statement to make it easier to add support for new page code / subpage code combinations. Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-16-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 70 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index ba0a29e6a86d..67a8e6243e5e 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2703,22 +2703,22 @@ static int resp_mode_sense(struct scsi_cmnd *scp, ap = arr + offset; } - if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { - /* TODO: Control Extension page */ - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); - return check_condition_result; - } - switch (pcode) { case 0x1: /* Read-Write error recovery page, direct access */ + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; len = resp_err_recov_pg(ap, pcontrol, target); offset += len; break; case 0x2: /* Disconnect-Reconnect page, all devices */ + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; len = resp_disconnect_pg(ap, pcontrol, target); offset += len; break; case 0x3: /* Format device page, direct access */ + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; if (is_disk) { len = resp_format_pg(ap, pcontrol, target); offset += len; @@ -2727,6 +2727,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp, } break; case 0x8: /* Caching page, direct access */ + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; if (is_disk || is_zbc) { len = resp_caching_pg(ap, pcontrol, target); offset += len; @@ -2735,14 +2737,14 @@ static int resp_mode_sense(struct scsi_cmnd *scp, } break; case 0xa: /* Control Mode page, all devices */ + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; len = resp_ctrl_m_pg(ap, pcontrol, target); offset += len; break; case 0x19: /* if spc==1 then sas phy, control+discover */ - if ((subpcode > 0x2) && (subpcode < 0xff)) { - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); - return check_condition_result; - } + if (subpcode > 0x2 && subpcode < 0xff) + goto bad_subpcode; len = 0; if ((0x0 == subpcode) || (0xff == subpcode)) len += resp_sas_sf_m_pg(ap + len, pcontrol, target); @@ -2754,35 +2756,31 @@ static int resp_mode_sense(struct scsi_cmnd *scp, offset += len; break; case 0x1c: /* Informational Exceptions Mode page, all devices */ + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; len = resp_iec_m_pg(ap, pcontrol, target); offset += len; break; case 0x3f: /* Read all Mode pages */ - if ((0 == subpcode) || (0xff == subpcode)) { - len = resp_err_recov_pg(ap, pcontrol, target); - len += resp_disconnect_pg(ap + len, pcontrol, target); - if (is_disk) { - len += resp_format_pg(ap + len, pcontrol, - target); - len += resp_caching_pg(ap + len, pcontrol, - target); - } else if (is_zbc) { - len += resp_caching_pg(ap + len, pcontrol, - target); - } - len += resp_ctrl_m_pg(ap + len, pcontrol, target); - len += resp_sas_sf_m_pg(ap + len, pcontrol, target); - if (0xff == subpcode) { - len += resp_sas_pcd_m_spg(ap + len, pcontrol, - target, target_dev_id); - len += resp_sas_sha_m_spg(ap + len, pcontrol); - } - len += resp_iec_m_pg(ap + len, pcontrol, target); - offset += len; - } else { - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); - return check_condition_result; + if (subpcode > 0x0 && subpcode < 0xff) + goto bad_subpcode; + len = resp_err_recov_pg(ap, pcontrol, target); + len += resp_disconnect_pg(ap + len, pcontrol, target); + if (is_disk) { + len += resp_format_pg(ap + len, pcontrol, target); + len += resp_caching_pg(ap + len, pcontrol, target); + } else if (is_zbc) { + len += resp_caching_pg(ap + len, pcontrol, target); + } + len += resp_ctrl_m_pg(ap + len, pcontrol, target); + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if (0xff == subpcode) { + len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, + target_dev_id); + len += resp_sas_sha_m_spg(ap + len, pcontrol); } + len += resp_iec_m_pg(ap + len, pcontrol, target); + offset += len; break; default: goto bad_pcode; @@ -2796,6 +2794,10 @@ static int resp_mode_sense(struct scsi_cmnd *scp, bad_pcode: mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); return check_condition_result; + +bad_subpcode: + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); + return check_condition_result; } #define SDEBUG_MAX_MSELECT_SZ 512 -- cgit v1.2.3 From b952eb270df38bc0d930a1ef965666ecf54a2097 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:42 -0800 Subject: scsi: scsi_debug: Allocate the MODE SENSE response from the heap Make the MODE SENSE response buffer larger and allocate it from the heap. This patch prepares for adding support for the IO Advice Hints Grouping mode page. Suggested-by: Douglas Gilbert Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-17-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 67a8e6243e5e..b544498324f6 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -2631,7 +2632,8 @@ static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) return sizeof(sas_sha_m_pg); } -#define SDEBUG_MAX_MSENSE_SZ 256 +/* PAGE_SIZE is more than necessary but provides room for future expansion. */ +#define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE static int resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) @@ -2642,10 +2644,13 @@ static int resp_mode_sense(struct scsi_cmnd *scp, int target_dev_id; int target = scp->device->id; unsigned char *ap; - unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; + unsigned char *arr __free(kfree); unsigned char *cmd = scp->cmnd; bool dbd, llbaa, msense_6, is_disk, is_zbc; + arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC); + if (!arr) + return -ENOMEM; dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ pcontrol = (cmd[2] & 0xc0) >> 6; pcode = cmd[2] & 0x3f; -- cgit v1.2.3 From f8ab2710177a762ce0f9b8426f9fc292394949df Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:43 -0800 Subject: scsi: scsi_debug: Implement the IO Advice Hints Grouping mode page Implement an IO Advice Hints Grouping mode page with three permanent streams. A permanent stream is a stream for which the device server does not allow closing or otherwise modifying the configuration of that stream. The stream identifier enable (ST_ENBLE) bit specifies whether the stream identifier may be used in the GROUP NUMBER field of SCSI WRITE commands. Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-18-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b544498324f6..ccf59b3e7602 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1969,7 +1969,11 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ else arr[4] = 0x0; /* no protection stuff */ - arr[5] = 0x7; /* head of q, ordered + simple q's */ + /* + * GROUP_SUP=1; HEADSUP=1 (HEAD OF QUEUE); ORDSUP=1 + * (ORDERED queuing); SIMPSUP=1 (SIMPLE queuing). + */ + arr[5] = 0x17; } else if (0x87 == cmd[2]) { /* mode page policy */ arr[3] = 0x8; /* number of following entries */ arr[4] = 0x2; /* disconnect-reconnect mp */ @@ -2559,6 +2563,40 @@ static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) return sizeof(ctrl_m_pg); } +/* IO Advice Hints Grouping mode page */ +static int resp_grouping_m_pg(unsigned char *p, int pcontrol, int target) +{ + /* IO Advice Hints Grouping mode page */ + struct grouping_m_pg { + u8 page_code; /* OR 0x40 when subpage_code > 0 */ + u8 subpage_code; + __be16 page_length; + u8 reserved[12]; + struct scsi_io_group_descriptor descr[MAXIMUM_NUMBER_OF_STREAMS]; + }; + static const struct grouping_m_pg gr_m_pg = { + .page_code = 0xa | 0x40, + .subpage_code = 5, + .page_length = cpu_to_be16(sizeof(gr_m_pg) - 4), + .descr = { + { .st_enble = 1 }, + { .st_enble = 1 }, + { .st_enble = 1 }, + { .st_enble = 1 }, + { .st_enble = 1 }, + { .st_enble = 0 }, + } + }; + + BUILD_BUG_ON(sizeof(struct grouping_m_pg) != + 16 + MAXIMUM_NUMBER_OF_STREAMS * 16); + memcpy(p, &gr_m_pg, sizeof(gr_m_pg)); + if (1 == pcontrol) { + /* There are no changeable values so clear from byte 4 on. */ + memset(p + 4, 0, sizeof(gr_m_pg) - 4); + } + return sizeof(gr_m_pg); +} static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) { /* Informational Exceptions control mode page for mode_sense */ @@ -2708,6 +2746,10 @@ static int resp_mode_sense(struct scsi_cmnd *scp, ap = arr + offset; } + /* + * N.B. If len>0 before resp_*_pg() call, then form of that call should be: + * len += resp_*_pg(ap + len, pcontrol, target); + */ switch (pcode) { case 0x1: /* Read-Write error recovery page, direct access */ if (subpcode > 0x0 && subpcode < 0xff) @@ -2742,9 +2784,20 @@ static int resp_mode_sense(struct scsi_cmnd *scp, } break; case 0xa: /* Control Mode page, all devices */ - if (subpcode > 0x0 && subpcode < 0xff) + switch (subpcode) { + case 0: + len = resp_ctrl_m_pg(ap, pcontrol, target); + break; + case 0x05: + len = resp_grouping_m_pg(ap, pcontrol, target); + break; + case 0xff: + len = resp_ctrl_m_pg(ap, pcontrol, target); + len += resp_grouping_m_pg(ap + len, pcontrol, target); + break; + default: goto bad_subpcode; - len = resp_ctrl_m_pg(ap, pcontrol, target); + } offset += len; break; case 0x19: /* if spc==1 then sas phy, control+discover */ @@ -2778,6 +2831,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp, len += resp_caching_pg(ap + len, pcontrol, target); } len += resp_ctrl_m_pg(ap + len, pcontrol, target); + if (0xff == subpcode) + len += resp_grouping_m_pg(ap + len, pcontrol, target); len += resp_sas_sf_m_pg(ap + len, pcontrol, target); if (0xff == subpcode) { len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, -- cgit v1.2.3 From ad620becda436fc02e50e5f6fe01de1d1f3794c9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:44 -0800 Subject: scsi: scsi_debug: Implement GET STREAM STATUS Implement the GET STREAM STATUS SCSI command. Report that the first five stream indexes correspond to permanent streams. Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-19-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index ccf59b3e7602..497045e54300 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -533,6 +533,8 @@ static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_get_stream_status(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip); static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); @@ -607,6 +609,9 @@ static const struct opcode_info_t sa_in_16_iarr[] = { {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ + {0, 0x9e, 0x16, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL, + {16, 0x16, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, + 0, 0} }, /* GET STREAM STATUS */ }; static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ @@ -4573,6 +4578,51 @@ static int resp_get_lba_status(struct scsi_cmnd *scp, return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); } +static int resp_get_stream_status(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + u16 starting_stream_id, stream_id; + const u8 *cmd = scp->cmnd; + u32 alloc_len, offset; + u8 arr[256] = {}; + struct scsi_stream_status_header *h = (void *)arr; + + starting_stream_id = get_unaligned_be16(cmd + 4); + alloc_len = get_unaligned_be32(cmd + 10); + + if (alloc_len < 8) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); + return check_condition_result; + } + + if (starting_stream_id >= MAXIMUM_NUMBER_OF_STREAMS) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); + return check_condition_result; + } + + /* + * The GET STREAM STATUS command only reports status information + * about open streams. Treat the non-permanent stream as open. + */ + put_unaligned_be16(MAXIMUM_NUMBER_OF_STREAMS, + &h->number_of_open_streams); + + for (offset = 8, stream_id = starting_stream_id; + offset + 8 <= min_t(u32, alloc_len, sizeof(arr)) && + stream_id < MAXIMUM_NUMBER_OF_STREAMS; + offset += 8, stream_id++) { + struct scsi_stream_status *stream_status = (void *)arr + offset; + + stream_status->perm = stream_id < PERMANENT_STREAM_COUNT; + put_unaligned_be16(stream_id, + &stream_status->stream_identifier); + stream_status->rel_lifetime = stream_id + 1; + } + put_unaligned_be32(offset - 8, &h->len); /* PARAMETER DATA LENGTH */ + + return fill_from_dev_buffer(scp, arr, min(offset, alloc_len)); +} + static int resp_sync_cache(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { -- cgit v1.2.3 From af180c0880f9df14be31807f0bb0fa6f0d34a943 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 30 Jan 2024 13:48:45 -0800 Subject: scsi: scsi_debug: Maintain write statistics per group number Track per GROUP NUMBER how many write commands have been processed. Make this information available in sysfs. Reset these statistics if any data is written into the sysfs attribute. Note: SCSI devices should only interpret the information in the GROUP NUMBER field as a stream identifier if the ST_ENBLE bit has been set to one. This patch follows a simpler approach: count the number of writes per GROUP NUMBER whether or not the group number represents a stream identifier. Cc: Martin K. Petersen Cc: Douglas Gilbert Tested-by: Douglas Gilbert Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20240130214911.1863909-20-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 49 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/scsi_debug.c') diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 497045e54300..ce52d580d1aa 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -902,6 +902,8 @@ static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ static int poll_queues; /* iouring iopoll interface.*/ +static atomic_long_t writes_by_group_number[64]; + static char sdebug_proc_name[] = MY_NAME; static const char *my_name = MY_NAME; @@ -3377,7 +3379,8 @@ static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, /* Returns number of bytes copied or -1 if error. */ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, - u32 sg_skip, u64 lba, u32 num, bool do_write) + u32 sg_skip, u64 lba, u32 num, bool do_write, + u8 group_number) { int ret; u64 block, rest = 0; @@ -3396,6 +3399,10 @@ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, return 0; if (scp->sc_data_direction != dir) return -1; + + if (do_write && group_number < ARRAY_SIZE(writes_by_group_number)) + atomic_long_inc(&writes_by_group_number[group_number]); + fsp = sip->storep; block = do_div(lba, sdebug_store_sectors); @@ -3769,7 +3776,7 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } } - ret = do_device_access(sip, scp, 0, lba, num, false); + ret = do_device_access(sip, scp, 0, lba, num, false, 0); sdeb_read_unlock(sip); if (unlikely(ret == -1)) return DID_ERROR << 16; @@ -3954,6 +3961,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { bool check_prot; u32 num; + u8 group = 0; u32 ei_lba; int ret; u64 lba; @@ -3965,11 +3973,13 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) ei_lba = 0; lba = get_unaligned_be64(cmd + 2); num = get_unaligned_be32(cmd + 10); + group = cmd[14] & 0x3f; check_prot = true; break; case WRITE_10: ei_lba = 0; lba = get_unaligned_be32(cmd + 2); + group = cmd[6] & 0x3f; num = get_unaligned_be16(cmd + 7); check_prot = true; break; @@ -3984,15 +3994,18 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) ei_lba = 0; lba = get_unaligned_be32(cmd + 2); num = get_unaligned_be32(cmd + 6); + group = cmd[6] & 0x3f; check_prot = true; break; case 0x53: /* XDWRITEREAD(10) */ ei_lba = 0; lba = get_unaligned_be32(cmd + 2); + group = cmd[6] & 0x1f; num = get_unaligned_be16(cmd + 7); check_prot = false; break; default: /* assume WRITE(32) */ + group = cmd[6] & 0x3f; lba = get_unaligned_be64(cmd + 12); ei_lba = get_unaligned_be32(cmd + 20); num = get_unaligned_be32(cmd + 28); @@ -4047,7 +4060,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } } - ret = do_device_access(sip, scp, 0, lba, num, true); + ret = do_device_access(sip, scp, 0, lba, num, true, group); if (unlikely(scsi_debug_lbp())) map_region(sip, lba, num); /* If ZBC zone then bump its write pointer */ @@ -4099,12 +4112,14 @@ static int resp_write_scat(struct scsi_cmnd *scp, u32 lb_size = sdebug_sector_size; u32 ei_lba; u64 lba; + u8 group; int ret, res; bool is_16; static const u32 lrd_size = 32; /* + parameter list header size */ if (cmd[0] == VARIABLE_LENGTH_CMD) { is_16 = false; + group = cmd[6] & 0x3f; wrprotect = (cmd[10] >> 5) & 0x7; lbdof = get_unaligned_be16(cmd + 12); num_lrd = get_unaligned_be16(cmd + 16); @@ -4115,6 +4130,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, lbdof = get_unaligned_be16(cmd + 4); num_lrd = get_unaligned_be16(cmd + 8); bt_len = get_unaligned_be32(cmd + 10); + group = cmd[14] & 0x3f; if (unlikely(have_dif_prot)) { if (sdebug_dif == T10_PI_TYPE2_PROTECTION && wrprotect) { @@ -4203,7 +4219,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, } } - ret = do_device_access(sip, scp, sg_off, lba, num, true); + ret = do_device_access(sip, scp, sg_off, lba, num, true, group); /* If ZBC zone then bump its write pointer */ if (sdebug_dev_is_zoned(devip)) zbc_inc_wp(devip, lba, num); @@ -7298,6 +7314,30 @@ static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) } static DRIVER_ATTR_RO(tur_ms_to_ready); +static ssize_t group_number_stats_show(struct device_driver *ddp, char *buf) +{ + char *p = buf, *end = buf + PAGE_SIZE; + int i; + + for (i = 0; i < ARRAY_SIZE(writes_by_group_number); i++) + p += scnprintf(p, end - p, "%d %ld\n", i, + atomic_long_read(&writes_by_group_number[i])); + + return p - buf; +} + +static ssize_t group_number_stats_store(struct device_driver *ddp, + const char *buf, size_t count) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(writes_by_group_number); i++) + atomic_long_set(&writes_by_group_number[i], 0); + + return count; +} +static DRIVER_ATTR_RW(group_number_stats); + /* Note: The following array creates attribute files in the /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these files (over those found in the /sys/module/scsi_debug/parameters @@ -7344,6 +7384,7 @@ static struct attribute *sdebug_drv_attrs[] = { &driver_attr_cdb_len.attr, &driver_attr_tur_ms_to_ready.attr, &driver_attr_zbc.attr, + &driver_attr_group_number_stats.attr, NULL, }; ATTRIBUTE_GROUPS(sdebug_drv); -- cgit v1.2.3