From: John Meneghini <jmeneghi@redhat.com>
To: "Kai Mäkisara" <Kai.Makisara@kolumbus.fi>,
linux-scsi@vger.kernel.org, dgilbert@interlog.com
Subject: Re: [RFC PATCH 2/6] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
Date: Thu, 30 Jan 2025 13:01:02 -0500 [thread overview]
Message-ID: <c4d70fec-fe89-4429-9c2b-08407378000a@redhat.com> (raw)
In-Reply-To: <20250128142250.163901-3-Kai.Makisara@kolumbus.fi>
Another much appreciated improvement for my scsi_debug tests.
Reviewed-by: John Meneghini <jmeneghi@redhat.com>
Tested-by: John Meneghini <jmeneghi@redhat.com>
On 1/28/25 9:22 AM, Kai Mäkisara wrote:
> The changes:
> - add READ BLOCK LIMITS (512 - 1048576 bytes)
> - make LOAD send New Media UA (not correct by the standard, but
> makes possible to test also this UA)
>
> Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
> ---
> drivers/scsi/scsi_debug.c | 130 ++++++++++++++++++++++++++++++++++++--
> 1 file changed, 123 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
> index 00daa77f636c..19929625bd36 100644
> --- a/drivers/scsi/scsi_debug.c
> +++ b/drivers/scsi/scsi_debug.c
> @@ -80,6 +80,7 @@ static const char *sdebug_version_date = "20210520";
> #define INVALID_FIELD_IN_CDB 0x24
> #define INVALID_FIELD_IN_PARAM_LIST 0x26
> #define WRITE_PROTECTED 0x27
> +#define UA_READY_ASC 0x28
> #define UA_RESET_ASC 0x29
> #define UA_CHANGED_ASC 0x2a
> #define TARGET_CHANGED_ASC 0x3f
> @@ -175,7 +176,11 @@ static const char *sdebug_version_date = "20210520";
>
> /* Default parameters for tape drives */
> #define TAPE_DEF_DENSITY 0x0
> +#define TAPE_BAD_DENSITY 0x65
> #define TAPE_DEF_BLKSIZE 0
> +#define TAPE_MIN_BLKSIZE 512
> +#define TAPE_MAX_BLKSIZE 1048576
> +#define TAPE_MAX_PARTITIONS 2
>
> #define SDEBUG_LUN_0_VAL 0
>
> @@ -220,7 +225,8 @@ static const char *sdebug_version_date = "20210520";
> #define SDEBUG_UA_LUNS_CHANGED 5
> #define SDEBUG_UA_MICROCODE_CHANGED 6 /* simulate firmware change */
> #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7
> -#define SDEBUG_NUM_UAS 8
> +#define SDEBUG_UA_NOT_READY_TO_READY 8
> +#define SDEBUG_NUM_UAS 9
>
> /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
> * sector on read commands: */
> @@ -370,6 +376,8 @@ struct sdebug_dev_info {
> /* For tapes */
> unsigned int tape_blksize;
> unsigned int tape_density;
> + unsigned char tape_partition;
> + unsigned int tape_location[TAPE_MAX_PARTITIONS];
>
> struct dentry *debugfs_entry;
> struct spinlock list_lock;
> @@ -491,14 +499,16 @@ enum sdeb_opcode_index {
> SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */
> SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */
> SDEB_I_ATOMIC_WRITE_16 = 32,
> - SDEB_I_LAST_ELEM_P1 = 33, /* keep this last (previous + 1) */
> + SDEB_I_READ_BLOCK_LIMITS = 33,
> + SDEB_I_LOCATE = 34,
> + SDEB_I_LAST_ELEM_P1 = 35, /* keep this last (previous + 1) */
> };
>
>
> static const unsigned char opcode_ind_arr[256] = {
> /* 0x0; 0x0->0x1f: 6 byte cdbs */
> SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
> - 0, 0, 0, 0,
> + 0, SDEB_I_READ_BLOCK_LIMITS, 0, 0,
> SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
> 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
> SDEB_I_RELEASE,
> @@ -506,7 +516,7 @@ static const unsigned char opcode_ind_arr[256] = {
> SDEB_I_ALLOW_REMOVAL, 0,
> /* 0x20; 0x20->0x3f: 10 byte cdbs */
> 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
> - SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
> + SDEB_I_READ, 0, SDEB_I_WRITE, SDEB_I_LOCATE, 0, 0, 0, SDEB_I_VERIFY,
> 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
> 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
> /* 0x40; 0x40->0x5f: 10 byte cdbs */
> @@ -581,6 +591,8 @@ static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
> static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
> static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
> static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
> +static int resp_read_blklimits(struct scsi_cmnd *, struct sdebug_dev_info *);
> +static int resp_locate(struct scsi_cmnd *, struct sdebug_dev_info *);
>
> static int sdebug_do_add_host(bool mk_new_store);
> static int sdebug_add_host_helper(int per_host_idx);
> @@ -808,6 +820,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
> resp_pre_fetch, pre_fetch_iarr,
> {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
> 0, 0, 0, 0} }, /* PRE-FETCH (10) */
> + /* READ POSITION (10) */
>
> /* 30 */
> {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
> @@ -823,6 +836,12 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
> resp_atomic_write, NULL, /* ATOMIC WRITE 16 */
> {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
> 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} },
> + {0, 0x05, 0, F_D_IN, resp_read_blklimits, NULL, /* READ BLOCK LIMITS (6) */
> + {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
> + {0, 0x2b, 0, F_D_UNKN, resp_locate, NULL, /* LOCATE (10) */
> + {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
> + 0, 0, 0, 0} },
> +
> /* sentinel */
> {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
> {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
> @@ -1501,6 +1520,12 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
> if (sdebug_verbose)
> cp = "reported luns data has changed";
> break;
> + case SDEBUG_UA_NOT_READY_TO_READY:
> + mk_sense_buffer(scp, UNIT_ATTENTION, UA_READY_ASC,
> + 0);
> + if (sdebug_verbose)
> + cp = "not ready to ready transition/media change";
> + break;
> default:
> pr_warn("unexpected unit attention code=%d\n", k);
> if (sdebug_verbose)
> @@ -2204,6 +2229,14 @@ static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
> changing = (stopped_state != want_stop);
> if (changing)
> atomic_xchg(&devip->stopped, want_stop);
> + if (sdebug_ptype == TYPE_TAPE && !want_stop) {
> + int i;
> +
> + set_bit(SDEBUG_UA_NOT_READY_TO_READY, devip->uas_bm); /* not legal! */
> + for (i = 0; i < TAPE_MAX_PARTITIONS; i++)
> + devip->tape_location[i] = 0;
> + devip->tape_partition = 0;
> + }
> if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */
> return SDEG_RES_IMMED_MASK;
> else
> @@ -2736,6 +2769,17 @@ static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
> return sizeof(sas_sha_m_pg);
> }
>
> +static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target)
> +{ /* Partition page for mode_sense (tape) */
> + unsigned char partition_pg[] = {0x11, 12, 1, 1, 0x80, 3, 9, 0,
> + 0xff, 0xff, 0x00, 40};
> +
> + memcpy(p, partition_pg, sizeof(partition_pg));
> + if (pcontrol == 1)
> + memset(p + 2, 0, sizeof(partition_pg) - 2);
> + return sizeof(partition_pg);
> +}
> +
> /* PAGE_SIZE is more than necessary but provides room for future expansion. */
> #define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE
>
> @@ -2872,6 +2916,12 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
> }
> offset += len;
> break;
> + case 0x11: /* Partition Mode Page (tape) */
> + if (!is_tape)
> + goto bad_pcode;
> + len += resp_partition_m_pg(ap, pcontrol, target);
> + offset += len;
> + break;
> case 0x19: /* if spc==1 then sas phy, control+discover */
> if (subpcode > 0x2 && subpcode < 0xff)
> goto bad_subpcode;
> @@ -2963,12 +3013,24 @@ static int resp_mode_select(struct scsi_cmnd *scp,
> bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
> off = (mselect6 ? 4 : 8);
> if (sdebug_ptype == TYPE_TAPE) {
> + int blks;
> +
> + if (arr[off] == TAPE_BAD_DENSITY) {
> + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
> + return check_condition_result;
> + }
> + blks = get_unaligned_be16(arr + off + 6);
> + if (blks != 0 &&
> + (blks < TAPE_MIN_BLKSIZE || blks > TAPE_MAX_BLKSIZE)) {
> + mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, -1);
> + return check_condition_result;
> + }
> devip->tape_density = arr[off];
> - devip->tape_blksize = get_unaligned_be16(arr + off + 6);
> + devip->tape_blksize = blks;
> }
> off += bd_len;
> if (res <= off)
> - goto only_bd; /* No page written, just descriptors */
> + return 0; /* No page written, just descriptors */
> if (md_len > 2 || off >= res) {
> mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
> return check_condition_result;
> @@ -3021,7 +3083,6 @@ static int resp_mode_select(struct scsi_cmnd *scp,
> return check_condition_result;
> set_mode_changed_ua:
> set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
> -only_bd:
> return 0;
> }
>
> @@ -3162,6 +3223,36 @@ static int resp_log_sense(struct scsi_cmnd *scp,
> min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
> }
>
> +#define SDEBUG_READ_BLOCK_LIMITS_ARR_SZ 6
> +static int resp_read_blklimits(struct scsi_cmnd *scp,
> + struct sdebug_dev_info *devip)
> +{
> + unsigned char arr[SDEBUG_READ_BLOCK_LIMITS_ARR_SZ];
> +
> + memset(arr, 0, SDEBUG_READ_BLOCK_LIMITS_ARR_SZ);
> + put_unaligned_be24(TAPE_MAX_BLKSIZE, arr + 1);
> + put_unaligned_be16(TAPE_MIN_BLKSIZE, arr + 4);
> + return fill_from_dev_buffer(scp, arr, SDEBUG_READ_BLOCK_LIMITS_ARR_SZ);
> +}
> +
> +static int resp_locate(struct scsi_cmnd *scp,
> + struct sdebug_dev_info *devip)
> +{
> + unsigned char *cmd = scp->cmnd;
> +
> + if ((cmd[1] & 0x02) != 0) {
> + if (cmd[8] >= TAPE_MAX_PARTITIONS) {
> + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1);
> + return check_condition_result;
> + }
> + devip->tape_partition = cmd[8];
> + }
> + devip->tape_location[devip->tape_partition] =
> + get_unaligned_be32(cmd + 3);
> +
> + return 0;
> +}
> +
> static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
> {
> return devip->nr_zones != 0;
> @@ -4942,6 +5033,8 @@ static int resp_sync_cache(struct scsi_cmnd *scp,
> * a GOOD status otherwise. Model a disk with a big cache and yield
> * CONDITION MET. Actually tries to bring range in main memory into the
> * cache associated with the CPU(s).
> + *
> + * The pcode 0x34 is also used for READ POSITION by tape devices.
> */
> static int resp_pre_fetch(struct scsi_cmnd *scp,
> struct sdebug_dev_info *devip)
> @@ -4954,6 +5047,29 @@ static int resp_pre_fetch(struct scsi_cmnd *scp,
> struct sdeb_store_info *sip = devip2sip(devip, true);
> u8 *fsp = sip->storep;
>
> + if (sdebug_ptype == TYPE_TAPE) {
> + if (cmd[0] == PRE_FETCH) { /* READ POSITION (10) */
> + int all_length;
> + unsigned char arr[20];
> + unsigned int pos;
> +
> + all_length = get_unaligned_be16(cmd + 7);
> + if ((cmd[1] & 0xfe) != 0) { /* only short form */
> + mk_sense_invalid_fld(scp, SDEB_IN_CDB,
> + 1, 0);
> + return check_condition_result;
> + }
> + memset(arr, 0, 20);
> + arr[1] = devip->tape_partition;
> + pos = devip->tape_location[devip->tape_partition];
> + put_unaligned_be32(pos, arr + 4);
> + put_unaligned_be32(pos, arr + 8);
> + return fill_from_dev_buffer(scp, arr, 20);
> + }
> + mk_sense_invalid_opcode(scp);
> + return check_condition_result;
> + }
> +
> if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */
> lba = get_unaligned_be32(cmd + 2);
> nblks = get_unaligned_be16(cmd + 7);
next prev parent reply other threads:[~2025-01-30 18:01 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-28 14:22 [RFC PATCH 0/6] scsi: scsi_debug: Add more tape support Kai Mäkisara
2025-01-28 14:22 ` [RFC PATCH 1/6] scsi: scsi_debug: First fixes for tapes Kai Mäkisara
2025-01-30 17:58 ` John Meneghini
2025-01-28 14:22 ` [RFC PATCH 2/6] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD " Kai Mäkisara
2025-01-28 17:32 ` Bart Van Assche
2025-01-30 18:01 ` John Meneghini [this message]
2025-01-28 14:22 ` [RFC PATCH 3/6] scsi: scsi_debug: Add tape write support with block lengths and 4 bytes of data Kai Mäkisara
2025-01-30 21:45 ` John Meneghini
2025-01-28 14:22 ` [RFC PATCH 4/6] scsi: scsi_debug: Add read support and update locate for tapes Kai Mäkisara
2025-01-30 21:46 ` John Meneghini
2025-01-28 14:22 ` [RFC PATCH 5/6] scsi: scsi_debug: Add compression mode page " Kai Mäkisara
2025-01-30 21:49 ` John Meneghini
2025-01-28 14:22 ` [RFC PATCH 6/6] scsi: scsi_debug: Reset tape setting at device reset Kai Mäkisara
2025-01-30 21:58 ` John Meneghini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c4d70fec-fe89-4429-9c2b-08407378000a@redhat.com \
--to=jmeneghi@redhat.com \
--cc=Kai.Makisara@kolumbus.fi \
--cc=dgilbert@interlog.com \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox