public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/7] scsi: scsi_debug: Add more tape support
@ 2025-02-10 19:12 Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 1/7] scsi: scsi_debug: First fixes for tapes Kai Mäkisara
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

Currently, the scsi_debug driver can create tape devices and the st
driver attaches to those. Nothing much can be done with the tape devices
because scsi_debug does not have support for the tape-specific commands
and features. These patches add some more tape support to the scsi_debug
driver. The end result is simulated drives with a tape having one or two
partitions (one partition is created initially).

The tape is implemented as fixed number (10 000) of 8-byte units.
The first four bytes of a unit contain the type of the unit (data
block, filemark or end-of-data mark). If the units is a data block,
the first four bytes also contain the block length and the remaining
four bytes the first bytes of written data. This allows the user
to use tags to see that the read block is what it was supposed to be.

The following SCSI operations are added or modified:
FORMAT MEDIUM
- added
LOCATE
- added
MODE SELECT
- modified to allow use without page(s) (just header and block descriptor)
  - store density and block size
- partition page added
MODE SENSE
- modified to allow use without page(s) (just header and block descriptor)
  - set density and block size
- partition page added
READ BLOCK LIMITS
- added
READ POSITION
- added
READ
- added tape support for READ (6)
REWIND
- modified to set the tape position
SPACE
- added
START STOP (LOAD)
- modified to return New Medium Unit Attention if tape loaded (not
  according to the standard, but enables testing this UA)
WRITE
- added tape support for WRITE (6)
WRITE FILEMARKS
- added

Changes RFC -> v1:
- rebased to v6.14-rc1
- virtual tape initialization is rewritten and the tape is made shorter
  (10 000 units)
- only one partition is created initially
- tape block allocation is moved to sdev_configure()
- tape blocks are freed in sdev_destroy()
- block size must be multiple of four (SSC standard)
- granularity set to four in READ BLOCK LIMITS
- long LBA not allowed for tapes in MODE SELECT/SENSE
- READ POSITION checks allocation length
- new patch 7 adds support for re-partitioning the tape

Kai Mäkisara (7):
  scsi: scsi_debug: First fixes for tapes
  scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
  scsi: scsi_debug: Add write support with block lengths  and 4 bytes of
    data
  scsi: scsi_debug: Add read support and update locate for tapes
  scsi: scsi_debug: Add compression mode page for tapes
  scsi: scsi_debug: Reset tape setting at device reset
  scsi: scsi_debug: Add support for partitioning the tape

 drivers/scsi/scsi_debug.c | 775 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 761 insertions(+), 14 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v1 1/7] scsi: scsi_debug: First fixes for tapes
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD " Kai Mäkisara
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

Patch includes the following:
- enable MODE SENSE/SELECT without actual page (to read/write only
  the Block Descriptor)
- store the density code and block size in the Block Descriptor
  (only short version for tapes)
- fix REWIND not to use the wrong page filling function

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
 drivers/scsi/scsi_debug.c | 55 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 5ceaa4665e5d..4da0c259390b 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -173,6 +173,10 @@ static const char *sdebug_version_date = "20210520";
 #define DEF_ZBC_MAX_OPEN_ZONES	8
 #define DEF_ZBC_NR_CONV_ZONES	1
 
+/* Default parameters for tape drives */
+#define TAPE_DEF_DENSITY  0x0
+#define TAPE_DEF_BLKSIZE  0
+
 #define SDEBUG_LUN_0_VAL 0
 
 /* bit mask values for sdebug_opts */
@@ -363,6 +367,10 @@ struct sdebug_dev_info {
 	ktime_t create_ts;	/* time since bootup that this device was created */
 	struct sdeb_zone_state *zstate;
 
+	/* For tapes */
+	unsigned int tape_blksize;
+	unsigned int tape_density;
+
 	struct dentry *debugfs_entry;
 	struct spinlock list_lock;
 	struct list_head inject_err_list;
@@ -773,7 +781,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 /* 20 */
 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
+	{0, 0x1, 0, 0, NULL, NULL, /* REWIND ?? */
 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
@@ -2742,7 +2750,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	unsigned char *ap;
 	unsigned char *arr __free(kfree);
 	unsigned char *cmd = scp->cmnd;
-	bool dbd, llbaa, msense_6, is_disk, is_zbc;
+	bool dbd, llbaa, msense_6, is_disk, is_zbc, is_tape;
 
 	arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC);
 	if (!arr)
@@ -2755,7 +2763,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
 	is_disk = (sdebug_ptype == TYPE_DISK);
 	is_zbc = devip->zoned;
-	if ((is_disk || is_zbc) && !dbd)
+	is_tape = (sdebug_ptype == TYPE_TAPE);
+	if ((is_disk || is_zbc || is_tape) && !dbd)
 		bd_len = llbaa ? 16 : 8;
 	else
 		bd_len = 0;
@@ -2793,15 +2802,25 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 			put_unaligned_be32(0xffffffff, ap + 0);
 		else
 			put_unaligned_be32(sdebug_capacity, ap + 0);
-		put_unaligned_be16(sdebug_sector_size, ap + 6);
+		if (is_tape) {
+			ap[0] = devip->tape_density;
+			put_unaligned_be16(devip->tape_blksize, ap + 6);
+		} else
+			put_unaligned_be16(sdebug_sector_size, ap + 6);
 		offset += bd_len;
 		ap = arr + offset;
 	} else if (16 == bd_len) {
+		if (is_tape) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, 4);
+			return check_condition_result;
+		}
 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
 		put_unaligned_be32(sdebug_sector_size, ap + 12);
 		offset += bd_len;
 		ap = arr + offset;
 	}
+	if (cmd[2] == 0)
+		goto only_bd; /* Only block descriptor requested */
 
 	/*
 	 * N.B. If len>0 before resp_*_pg() call, then form of that call should be:
@@ -2902,6 +2921,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	default:
 		goto bad_pcode;
 	}
+only_bd:
 	if (msense_6)
 		arr[0] = offset - 1;
 	else
@@ -2945,8 +2965,27 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 			    __func__, param_len, res);
 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
-	off = bd_len + (mselect6 ? 4 : 8);
-	if (md_len > 2 || off >= res) {
+	off = (mselect6 ? 4 : 8);
+	if (sdebug_ptype == TYPE_TAPE) {
+		int blksize;
+
+		if (bd_len != 8) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA,
+					mselect6 ? 3 : 6, -1);
+			return check_condition_result;
+		}
+		blksize = get_unaligned_be16(arr + off + 6);
+		if ((blksize % 4) != 0) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, off + 6, -1);
+			return check_condition_result;
+		}
+		devip->tape_density = arr[off];
+		devip->tape_blksize = blksize;
+	}
+	off += bd_len;
+	if (off >= res)
+		return 0; /* No page written, just descriptors */
+	if (md_len > 2) {
 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
 		return check_condition_result;
 	}
@@ -5835,6 +5874,10 @@ static struct sdebug_dev_info *sdebug_device_create(
 		} else {
 			devip->zoned = false;
 		}
+		if (sdebug_ptype == TYPE_TAPE) {
+			devip->tape_density = TAPE_DEF_DENSITY;
+			devip->tape_blksize = TAPE_DEF_BLKSIZE;
+		}
 		devip->create_ts = ktime_get_boottime();
 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
 		spin_lock_init(&devip->list_lock);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 1/7] scsi: scsi_debug: First fixes for tapes Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  2025-02-11 10:41   ` kernel test robot
  2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data Kai Mäkisara
                   ` (4 subsequent siblings)
  6 siblings, 2 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

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 | 127 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 121 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 4da0c259390b..5c662f3d97e3 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 unsigned char partition_pg[] = {0x11, 12, 1, 0, 0x24, 3, 9, 0,
+	0xff, 0xff, 0x00, 0x00};
+
+static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target)
+{	/* Partition page for mode_sense (tape) */
+	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
 
@@ -2876,6 +2920,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;
@@ -2974,9 +3024,16 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 					mselect6 ? 3 : 6, -1);
 			return check_condition_result;
 		}
+		if (arr[off] == TAPE_BAD_DENSITY) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
+			return check_condition_result;
+		}
 		blksize = get_unaligned_be16(arr + off + 6);
-		if ((blksize % 4) != 0) {
-			mk_sense_invalid_fld(scp, SDEB_IN_DATA, off + 6, -1);
+		if (blksize != 0 &&
+			(blksize < TAPE_MIN_BLKSIZE ||
+				blksize > TAPE_MAX_BLKSIZE ||
+				(blksize % 4) != 0)) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, -1);
 			return check_condition_result;
 		}
 		devip->tape_density = arr[off];
@@ -3177,6 +3234,36 @@ static int resp_log_sense(struct scsi_cmnd *scp,
 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
 }
 
+enum {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];
+
+	arr[0] = 4;
+	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;
@@ -4957,7 +5044,10 @@ 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.
  */
+enum {SDEBUG_READ_POSITION_ARR_SZ = 20};
 static int resp_pre_fetch(struct scsi_cmnd *scp,
 			  struct sdebug_dev_info *devip)
 {
@@ -4969,6 +5059,31 @@ 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 ||
+				all_length != 0) { /* only short form */
+				mk_sense_invalid_fld(scp, SDEB_IN_CDB,
+						all_length ? 7 : 1, 0);
+				return check_condition_result;
+			}
+			memset(arr, 0, SDEBUG_READ_POSITION_ARR_SZ);
+			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,
+						SDEBUG_READ_POSITION_ARR_SZ);
+		}
+		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);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 1/7] scsi: scsi_debug: First fixes for tapes Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD " Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  2025-02-11 13:08   ` kernel test robot
  2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes Kai Mäkisara
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

The tape is implemented as fixed number (10 000) of 8-byte units.
The first four bytes of a unit contains the type of the unit (data
block, filemark or end-of-data mark). If the units is a data block,
the first four bytes contain the block length and the remaining
four bytes the first bytes of written data. This allows the user
to use tags to see that the read block is what it was supposed to be.

The tape can contain two partitions. Initially it is formatted as one
partition consisting of all 10 000 units.

This patch adds the WRITE(6) command for tapes and the WRITE FILEMARKS (6)
command. The REWIND command is updated.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
 drivers/scsi/scsi_debug.c | 217 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 212 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 5c662f3d97e3..6282f162ed5a 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -71,6 +71,10 @@ static const char *sdebug_version_date = "20210520";
 #define NO_ADDITIONAL_SENSE 0x0
 #define OVERLAP_ATOMIC_COMMAND_ASC 0x0
 #define OVERLAP_ATOMIC_COMMAND_ASCQ 0x23
+#define FILEMARK_DETECTED_ASCQ 0x1
+#define EOP_EOM_DETECTED_ASCQ 0x2
+#define BEGINNING_OF_P_M_DETECTED_ASCQ 0x4
+#define EOD_DETECTED_ASCQ 0x5
 #define LOGICAL_UNIT_NOT_READY 0x4
 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
 #define UNRECOVERED_READ_ERR 0x11
@@ -83,6 +87,7 @@ static const char *sdebug_version_date = "20210520";
 #define UA_READY_ASC 0x28
 #define UA_RESET_ASC 0x29
 #define UA_CHANGED_ASC 0x2a
+#define TOO_MANY_IN_PARTITION_ASC 0x3b
 #define TARGET_CHANGED_ASC 0x3f
 #define LUNS_CHANGED_ASCQ 0x0e
 #define INSUFF_RES_ASC 0x55
@@ -180,7 +185,29 @@ static const char *sdebug_version_date = "20210520";
 #define TAPE_DEF_BLKSIZE  0
 #define TAPE_MIN_BLKSIZE  512
 #define TAPE_MAX_BLKSIZE  1048576
+#define TAPE_EW 20
 #define TAPE_MAX_PARTITIONS 2
+#define TAPE_UNITS 10000
+
+/* The tape block data definitions */
+#define TAPE_BLOCK_FM_FLAG   ((u32)0x1 << 30)
+#define TAPE_BLOCK_EOD_FLAG  ((u32)0x2 << 30)
+#define TAPE_BLOCK_MARK_MASK ((u32)0x3 << 30)
+#define TAPE_BLOCK_SIZE_MASK (~TAPE_BLOCK_MARK_MASK)
+#define TAPE_BLOCK_MARK(a) (a & TAPE_BLOCK_MARK_MASK)
+#define TAPE_BLOCK_SIZE(a) (a & TAPE_BLOCK_SIZE_MASK)
+#define IS_TAPE_BLOCK_FM(a)   ((a & TAPE_BLOCK_FM_FLAG) != 0)
+#define IS_TAPE_BLOCK_EOD(a)  ((a & TAPE_BLOCK_EOD_FLAG) != 0)
+
+struct tape_block {
+	u32 fl_size;
+	unsigned char data[4];
+};
+
+/* Flags for sense data */
+#define SENSE_FLAG_FILEMARK  0x80
+#define SENSE_FLAG_EOM 0x40
+#define SENSE_FLAG_ILI 0x20
 
 #define SDEBUG_LUN_0_VAL 0
 
@@ -377,7 +404,10 @@ struct sdebug_dev_info {
 	unsigned int tape_blksize;
 	unsigned int tape_density;
 	unsigned char tape_partition;
+	unsigned char tape_nbr_partitions;
 	unsigned int tape_location[TAPE_MAX_PARTITIONS];
+	unsigned int tape_eop[TAPE_MAX_PARTITIONS];
+	struct tape_block *tape_blocks[TAPE_MAX_PARTITIONS];
 
 	struct dentry *debugfs_entry;
 	struct spinlock list_lock;
@@ -501,7 +531,8 @@ enum sdeb_opcode_index {
 	SDEB_I_ATOMIC_WRITE_16 = 32,
 	SDEB_I_READ_BLOCK_LIMITS = 33,
 	SDEB_I_LOCATE = 34,
-	SDEB_I_LAST_ELEM_P1 = 35,	/* keep this last (previous + 1) */
+	SDEB_I_WRITE_FILEMARKS = 35,
+	SDEB_I_LAST_ELEM_P1 = 36,	/* keep this last (previous + 1) */
 };
 
 
@@ -510,8 +541,8 @@ static const unsigned char opcode_ind_arr[256] = {
 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
 	    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,
+	SDEB_I_WRITE_FILEMARKS, 0, SDEB_I_INQUIRY, 0, 0,
+	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE,
 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
 	    SDEB_I_ALLOW_REMOVAL, 0,
 /* 0x20; 0x20->0x3f: 10 byte cdbs */
@@ -593,6 +624,8 @@ 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 resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_rewind(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);
@@ -793,7 +826,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 /* 20 */
 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-	{0, 0x1, 0, 0, NULL, NULL, /* REWIND ?? */
+	{0, 0x1, 0, 0, resp_rewind, NULL,
 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
@@ -841,6 +874,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 	{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} },
+	{0, 0x10, 0, F_D_IN, resp_write_filemarks, NULL,    /* WRITE FILEMARKS (6) */
+	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 /* sentinel */
 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
@@ -1358,6 +1393,30 @@ static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
 			    my_name, key, asc, asq);
 }
 
+/* Sense data that has information fields for tapes */
+static void mk_sense_info_tape(struct scsi_cmnd *scp, int key, int asc, int asq,
+			unsigned int information, unsigned char tape_flags)
+{
+	if (!scp->sense_buffer) {
+		sdev_printk(KERN_ERR, scp->device,
+			    "%s: sense_buffer is NULL\n", __func__);
+		return;
+	}
+	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+	scsi_build_sense(scp, /*sdebug_dsense*/ 0, key, asc, asq);
+	/* only fixed format so far */
+
+	scp->sense_buffer[0] |= 0x80; /* valid */
+	scp->sense_buffer[2] |= tape_flags;
+	put_unaligned_be32(information, &scp->sense_buffer[3]);
+
+	if (sdebug_verbose)
+		sdev_printk(KERN_INFO, scp->device,
+			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
+			    my_name, key, asc, asq);
+}
+
 static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
 {
 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
@@ -3252,7 +3311,7 @@ static int resp_locate(struct scsi_cmnd *scp,
 	unsigned char *cmd = scp->cmnd;
 
 	if ((cmd[1] & 0x02) != 0) {
-		if (cmd[8] >= TAPE_MAX_PARTITIONS) {
+		if (cmd[8] >= devip->tape_nbr_partitions) {
 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1);
 			return check_condition_result;
 		}
@@ -3264,6 +3323,71 @@ static int resp_locate(struct scsi_cmnd *scp,
 	return 0;
 }
 
+static int resp_write_filemarks(struct scsi_cmnd *scp,
+		struct sdebug_dev_info *devip)
+{
+	unsigned char *cmd = scp->cmnd;
+	unsigned int i, count, pos;
+	u32 data;
+	int partition = devip->tape_partition;
+
+	if ((cmd[1] & 0xfe) != 0) { /* probably write setmarks, not in >= SCSI-3 */
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
+		return check_condition_result;
+	}
+	count = get_unaligned_be24(cmd + 2);
+	data = TAPE_BLOCK_FM_FLAG;
+	for (i = 0, pos = devip->tape_location[partition]; i < count; i++, pos++) {
+		if (pos >= devip->tape_eop[partition] - 1) { /* don't overwrite EOD */
+			devip->tape_location[partition] = devip->tape_eop[partition] - 1;
+			mk_sense_info_tape(scp, VOLUME_OVERFLOW, NO_ADDITIONAL_SENSE,
+					EOP_EOM_DETECTED_ASCQ, count, SENSE_FLAG_EOM);
+			return check_condition_result;
+		}
+		(devip->tape_blocks[partition] + pos)->fl_size = data;
+	}
+	(devip->tape_blocks[partition] + pos)->fl_size =
+		TAPE_BLOCK_EOD_FLAG;
+	devip->tape_location[partition] = pos;
+
+	return 0;
+}
+
+static int resp_rewind(struct scsi_cmnd *scp,
+		struct sdebug_dev_info *devip)
+{
+	devip->tape_location[devip->tape_partition] = 0;
+
+	return 0;
+}
+
+static int partition_tape(struct sdebug_dev_info *devip, int nbr_partitions,
+			int part_0_size, int part_1_size)
+{
+	int i;
+
+	if (part_0_size + part_1_size > TAPE_UNITS)
+		return -1;
+	devip->tape_eop[0] = part_0_size;
+	devip->tape_blocks[0]->fl_size = TAPE_BLOCK_EOD_FLAG;
+	devip->tape_eop[1] = part_1_size;
+	devip->tape_blocks[1] = devip->tape_blocks[0] +
+			devip->tape_eop[0];
+	devip->tape_blocks[1]->fl_size = TAPE_BLOCK_EOD_FLAG;
+
+	for ( ; i < TAPE_MAX_PARTITIONS; i++)
+		devip->tape_location[i] = 0;
+
+	devip->tape_nbr_partitions = nbr_partitions;
+	devip->tape_partition = 0;
+
+	partition_pg[3] = nbr_partitions - 1;
+	put_unaligned_be16(devip->tape_eop[0], partition_pg + 8);
+	put_unaligned_be16(devip->tape_eop[1], partition_pg + 10);
+
+	return nbr_partitions;
+}
+
 static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
 {
 	return devip->nr_zones != 0;
@@ -4304,6 +4428,67 @@ static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
 	}
 }
 
+static int resp_write_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+	u32 i, num, transfer, size, written = 0;
+	u8 *cmd = scp->cmnd;
+	struct scsi_data_buffer *sdb = &scp->sdb;
+	int partition = devip->tape_partition;
+	int pos = devip->tape_location[partition];
+	struct tape_block *blp;
+	bool fixed, ew;
+
+	if (cmd[0] != WRITE_6) { /* Only Write(6) supported */
+		mk_sense_invalid_opcode(scp);
+		return illegal_condition_result;
+	}
+
+	fixed = (cmd[1] & 1) != 0;
+	transfer = get_unaligned_be24(cmd + 2);
+	if (fixed) {
+		num = transfer;
+		size = devip->tape_blksize;
+	} else {
+		if (transfer < TAPE_MIN_BLKSIZE ||
+			transfer > TAPE_MAX_BLKSIZE) {
+			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
+			return check_condition_result;
+		}
+		num = 1;
+		size = transfer;
+	}
+
+	scsi_set_resid(scp, num * transfer);
+	for (i = 0, blp = devip->tape_blocks[partition] + pos, ew = false;
+	     i < num && pos < devip->tape_eop[partition] - 1; i++, pos++, blp++) {
+		blp->fl_size = size;
+		sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
+			&(blp->data), 4, i * size, true);
+		written += size;
+		scsi_set_resid(scp, num * transfer - written);
+		ew |= (pos == devip->tape_eop[partition] - TAPE_EW);
+	}
+
+	devip->tape_location[partition] = pos;
+	blp->fl_size = TAPE_BLOCK_EOD_FLAG;
+	if (pos >= devip->tape_eop[partition] - 1) {
+		mk_sense_info_tape(scp, VOLUME_OVERFLOW,
+				NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ,
+				fixed ? num - i : transfer,
+				SENSE_FLAG_EOM);
+		return check_condition_result;
+	}
+	if (ew) { /* early warning */
+		mk_sense_info_tape(scp, NO_SENSE,
+				NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ,
+				fixed ? num - i : transfer,
+				SENSE_FLAG_EOM);
+		return check_condition_result;
+	}
+
+	return 0;
+}
+
 static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
 	bool check_prot;
@@ -4316,6 +4501,9 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	u8 *cmd = scp->cmnd;
 	bool meta_data_locked = false;
 
+	if (sdebug_ptype == TYPE_TAPE)
+		return resp_write_tape(scp, devip);
+
 	switch (cmd[0]) {
 	case WRITE_16:
 		ei_lba = 0;
@@ -6063,6 +6251,20 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp,
 		if (devip == NULL)
 			return 1;  /* no resources, will be marked offline */
 	}
+	if (sdebug_ptype == TYPE_TAPE) {
+		if (!devip->tape_blocks[0]) {
+			devip->tape_blocks[0] =
+				kcalloc(TAPE_UNITS, sizeof(struct tape_block),
+					GFP_KERNEL);
+			if (!devip->tape_blocks[0])
+				return 1;
+		}
+		if (partition_tape(devip, 1, TAPE_UNITS, 0) < 0) {
+			kfree(devip->tape_blocks[0]);
+			devip->tape_blocks[0] = NULL;
+			return 1;
+		}
+	}
 	sdp->hostdata = devip;
 	if (sdebug_no_uld)
 		sdp->no_uld_attach = 1;
@@ -6108,6 +6310,11 @@ static void scsi_debug_sdev_destroy(struct scsi_device *sdp)
 
 	debugfs_remove(devip->debugfs_entry);
 
+	if (sdebug_ptype == TYPE_TAPE) {
+		kfree(devip->tape_blocks[0]);
+		devip->tape_blocks[0] = NULL;
+	}
+
 	/* make this slot available for re-use */
 	devip->used = false;
 	sdp->hostdata = NULL;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
                   ` (2 preceding siblings ...)
  2025-02-10 19:12 ` [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  2025-02-11 15:50   ` kernel test robot
  2025-02-11 21:26   ` [PATCH v1b " Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 5/7] scsi: scsi_debug: Add compression mode page " Kai Mäkisara
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

Support for the READ (6) and SPACE (6) commands for tapes based on the
previous write patch is added. The LOCATE (10) command is updated to use
the written data.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
 drivers/scsi/scsi_debug.c | 240 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 235 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 6282f162ed5a..691b573b105b 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -532,7 +532,8 @@ enum sdeb_opcode_index {
 	SDEB_I_READ_BLOCK_LIMITS = 33,
 	SDEB_I_LOCATE = 34,
 	SDEB_I_WRITE_FILEMARKS = 35,
-	SDEB_I_LAST_ELEM_P1 = 36,	/* keep this last (previous + 1) */
+	SDEB_I_SPACE = 36,
+	SDEB_I_LAST_ELEM_P1 = 37,	/* keep this last (previous + 1) */
 };
 
 
@@ -541,7 +542,7 @@ static const unsigned char opcode_ind_arr[256] = {
 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
 	    0, SDEB_I_READ_BLOCK_LIMITS, 0, 0,
 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
-	SDEB_I_WRITE_FILEMARKS, 0, SDEB_I_INQUIRY, 0, 0,
+	SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0,
 	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE,
 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
 	    SDEB_I_ALLOW_REMOVAL, 0,
@@ -625,6 +626,7 @@ 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 resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *);
 
 static int sdebug_do_add_host(bool mk_new_store);
@@ -872,10 +874,12 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 	{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,
+	    {10,  0x07, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xc7, 0, 0,
 	     0, 0, 0, 0} },
 	{0, 0x10, 0, F_D_IN, resp_write_filemarks, NULL,    /* WRITE FILEMARKS (6) */
 	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+	{0, 0x11, 0, F_D_IN, resp_space, NULL,    /* SPACE (6) */
+	    {6,  0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 /* sentinel */
 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
@@ -3309,6 +3313,9 @@ static int resp_locate(struct scsi_cmnd *scp,
 		struct sdebug_dev_info *devip)
 {
 	unsigned char *cmd = scp->cmnd;
+	unsigned int i, pos;
+	struct tape_block *blp;
+	int partition;
 
 	if ((cmd[1] & 0x02) != 0) {
 		if (cmd[8] >= devip->tape_nbr_partitions) {
@@ -3317,8 +3324,19 @@ static int resp_locate(struct scsi_cmnd *scp,
 		}
 		devip->tape_partition = cmd[8];
 	}
-	devip->tape_location[devip->tape_partition] =
-		get_unaligned_be32(cmd + 3);
+	pos = get_unaligned_be32(cmd + 3);
+	partition = devip->tape_partition;
+
+	for (i = 0, blp = devip->tape_blocks[partition];
+	     i < pos && i < devip->tape_eop[partition]; i++, blp++)
+		if (IS_TAPE_BLOCK_EOD(blp->fl_size))
+			break;
+	if (i < pos) {
+		devip->tape_location[partition] = i;
+		mk_sense_buffer(scp, BLANK_CHECK, 0x05, 0);
+		return check_condition_result;
+	}
+	devip->tape_location[partition] = pos;
 
 	return 0;
 }
@@ -3353,6 +3371,123 @@ static int resp_write_filemarks(struct scsi_cmnd *scp,
 	return 0;
 }
 
+static int resp_space(struct scsi_cmnd *scp,
+		struct sdebug_dev_info *devip)
+{
+	unsigned char *cmd = scp->cmnd, code;
+	int i, pos, count;
+	struct tape_block *blp;
+	int partition = devip->tape_partition;
+
+	count = get_unaligned_be24(cmd + 2);
+	if ((count & 0x800000) != 0) /* extend negative to 32-bit count */
+		count |= 0xff000000;
+	code = cmd[1] & 0x0f;
+
+	pos = devip->tape_location[partition];
+	if (code == 0) { /* blocks */
+		if (count < 0) {
+			count = (-count);
+			pos -= 1;
+			for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count;
+			     i++) {
+				if (pos < 0)
+					goto is_bop;
+				else if (IS_TAPE_BLOCK_FM(blp->fl_size))
+					goto is_fm;
+				if (i > 0) {
+					pos--;
+					blp--;
+				}
+			}
+		} else if (count > 0) {
+			for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count;
+			     i++, pos++, blp++) {
+				if (IS_TAPE_BLOCK_EOD(blp->fl_size))
+					goto is_eod;
+				if (IS_TAPE_BLOCK_FM(blp->fl_size)) {
+					pos += 1;
+					goto is_fm;
+				}
+				if (pos >= devip->tape_eop[partition])
+					goto is_eop;
+			}
+		}
+	} else if (code == 1) { /* filemarks */
+		if (count < 0) {
+			count = (-count);
+			if (pos == 0)
+				goto is_bop;
+			else {
+				for (i = 0, blp = devip->tape_blocks[partition] + pos;
+				     i < count && pos >= 0; i++, pos--, blp--) {
+					for (pos--, blp-- ; !IS_TAPE_BLOCK_FM(blp->fl_size) &&
+						     pos >= 0; pos--, blp--)
+						; /* empty */
+					if (pos < 0)
+						goto is_bop;
+				}
+			}
+			pos += 1;
+		} else if (count > 0) {
+			for (i = 0, blp = devip->tape_blocks[partition] + pos;
+			     i < count; i++, pos++, blp++) {
+				for ( ; !IS_TAPE_BLOCK_FM(blp->fl_size) &&
+					      !IS_TAPE_BLOCK_EOD(blp->fl_size) &&
+					      pos < devip->tape_eop[partition];
+				      pos++, blp++)
+					; /* empty */
+				if (IS_TAPE_BLOCK_EOD(blp->fl_size))
+					goto is_eod;
+				if (pos >= devip->tape_eop[partition])
+					goto is_eop;
+			}
+		}
+	} else if (code == 3) { /* EOD */
+		for (blp = devip->tape_blocks[partition] + pos;
+		     !IS_TAPE_BLOCK_EOD(blp->fl_size) && pos < devip->tape_eop[partition];
+		     pos++, blp++)
+			; /* empty */
+		if (pos >= devip->tape_eop[partition])
+			goto is_eop;
+	} else {
+		/* sequential filemarks not supported */
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1);
+		return check_condition_result;
+	}
+	devip->tape_location[partition] = pos;
+	return 0;
+
+is_fm:
+	devip->tape_location[partition] = pos;
+	mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+			FILEMARK_DETECTED_ASCQ, count - i,
+			SENSE_FLAG_FILEMARK);
+	return check_condition_result;
+
+is_eod:
+	devip->tape_location[partition] = pos;
+	mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE,
+			EOD_DETECTED_ASCQ, count - i,
+			0);
+	return check_condition_result;
+
+is_bop:
+	devip->tape_location[partition] = 0;
+	mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+			BEGINNING_OF_P_M_DETECTED_ASCQ, count - i,
+			SENSE_FLAG_EOM);
+	devip->tape_location[partition] = 0;
+	return check_condition_result;
+
+is_eop:
+	devip->tape_location[partition] = devip->tape_eop[partition] - 1;
+	mk_sense_info_tape(scp, MEDIUM_ERROR, NO_ADDITIONAL_SENSE,
+			EOP_EOM_DETECTED_ASCQ, (unsigned int)i,
+			SENSE_FLAG_EOM);
+	return check_condition_result;
+}
+
 static int resp_rewind(struct scsi_cmnd *scp,
 		struct sdebug_dev_info *devip)
 {
@@ -4121,6 +4256,98 @@ static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
 	return ret;
 }
 
+static int resp_read_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+	u32 i, num, transfer, size;
+	u8 *cmd = scp->cmnd;
+	struct scsi_data_buffer *sdb = &scp->sdb;
+	int partition = devip->tape_partition;
+	u32 pos = devip->tape_location[partition];
+	struct tape_block *blp;
+	bool fixed, sili;
+
+	if (cmd[0] != READ_6) { /* Only Read(6) supported */
+		mk_sense_invalid_opcode(scp);
+		return illegal_condition_result;
+	}
+	fixed = (cmd[1] & 0x1) != 0;
+	sili = (cmd[1] & 0x2) != 0;
+	if (fixed && sili) {
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
+		return check_condition_result;
+	}
+
+	transfer = get_unaligned_be24(cmd + 2);
+	if (fixed) {
+		num = transfer;
+		size = devip->tape_blksize;
+	} else {
+		if (transfer < TAPE_MIN_BLKSIZE ||
+			transfer > TAPE_MAX_BLKSIZE) {
+			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
+			return check_condition_result;
+		}
+		num = 1;
+		size = transfer;
+	}
+
+	for (i = 0, blp = devip->tape_blocks[partition] + pos;
+	     i < num && pos < devip->tape_eop[partition];
+	     i++, pos++, blp++) {
+		devip->tape_location[partition] = pos + 1;
+		if (IS_TAPE_BLOCK_FM(blp->fl_size)) {
+			mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+					FILEMARK_DETECTED_ASCQ, fixed ? num - i : size,
+					SENSE_FLAG_FILEMARK);
+			scsi_set_resid(scp, (num - i) * size);
+			return check_condition_result;
+		}
+		/* Assume no REW */
+		if (IS_TAPE_BLOCK_EOD(blp->fl_size)) {
+			mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE,
+					EOD_DETECTED_ASCQ, fixed ? num - i : size,
+					0);
+			devip->tape_location[partition] = pos;
+			scsi_set_resid(scp, (num - i) * size);
+			return check_condition_result;
+		}
+		sg_zero_buffer(sdb->table.sgl, sdb->table.nents,
+			size, i * size);
+		sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
+			&(blp->data), 4, i * size, false);
+		if (fixed) {
+			if (blp->fl_size != devip->tape_blksize) {
+				scsi_set_resid(scp, (num - i) * size);
+				mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+						0, num - i,
+						SENSE_FLAG_ILI);
+				return check_condition_result;
+			}
+		} else {
+			if (blp->fl_size != size) {
+				if (blp->fl_size < size)
+					scsi_set_resid(scp, size - blp->fl_size);
+				if (!sili) {
+					mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+							0, size - blp->fl_size,
+							SENSE_FLAG_ILI);
+					return check_condition_result;
+				}
+			}
+		}
+	}
+	if (pos >= devip->tape_eop[partition]) {
+		mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+				EOP_EOM_DETECTED_ASCQ, fixed ? num - i : size,
+				SENSE_FLAG_EOM);
+		devip->tape_location[partition] = pos - 1;
+		return check_condition_result;
+	}
+	devip->tape_location[partition] = pos;
+
+	return 0;
+}
+
 static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
 	bool check_prot;
@@ -4132,6 +4359,9 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	u8 *cmd = scp->cmnd;
 	bool meta_data_locked = false;
 
+	if (sdebug_ptype == TYPE_TAPE)
+		return resp_read_tape(scp, devip);
+
 	switch (cmd[0]) {
 	case READ_16:
 		ei_lba = 0;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1 5/7] scsi: scsi_debug: Add compression mode page for tapes
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
                   ` (3 preceding siblings ...)
  2025-02-10 19:12 ` [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 6/7] scsi: scsi_debug: Reset tape setting at device reset Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 7/7] scsi: scsi_debug: Add support for partitioning the tape Kai Mäkisara
  6 siblings, 0 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

Add support for compression mode page. The compression status
is saved and returned. No UA is generated.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
 drivers/scsi/scsi_debug.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 691b573b105b..7b84acebe0fe 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -405,6 +405,7 @@ struct sdebug_dev_info {
 	unsigned int tape_density;
 	unsigned char tape_partition;
 	unsigned char tape_nbr_partitions;
+	unsigned char tape_dce;
 	unsigned int tape_location[TAPE_MAX_PARTITIONS];
 	unsigned int tape_eop[TAPE_MAX_PARTITIONS];
 	struct tape_block *tape_blocks[TAPE_MAX_PARTITIONS];
@@ -2843,6 +2844,20 @@ static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target)
 	return sizeof(partition_pg);
 }
 
+static int resp_compression_m_pg(unsigned char *p, int pcontrol, int target,
+	unsigned char dce)
+{	/* Compression page for mode_sense (tape) */
+	unsigned char compression_pg[] = {0x0f, 14, 0x40, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 00, 00};
+
+	memcpy(p, compression_pg, sizeof(compression_pg));
+	if (dce)
+		p[2] |= 0x80;
+	if (pcontrol == 1)
+		memset(p + 2, 0, sizeof(compression_pg) - 2);
+	return sizeof(compression_pg);
+}
+
 /* PAGE_SIZE is more than necessary but provides room for future expansion. */
 #define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE
 
@@ -2983,6 +2998,12 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 		}
 		offset += len;
 		break;
+	case 0xf:	/* Compression Mode Page (tape) */
+		if (!is_tape)
+			goto bad_pcode;
+		len += resp_compression_m_pg(ap, pcontrol, target, devip->tape_dce);
+		offset += len;
+		break;
 	case 0x11:	/* Partition Mode Page (tape) */
 		if (!is_tape)
 			goto bad_pcode;
@@ -3143,6 +3164,14 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 			goto set_mode_changed_ua;
 		}
 		break;
+	case 0xf:       /* Compression mode page */
+		if (sdebug_ptype != TYPE_TAPE)
+			goto bad_pcode;
+		if ((arr[off + 2] & 0x40) != 0) {
+			devip->tape_dce = (arr[off + 2] & 0x80) != 0;
+			return 0;
+		}
+		break;
 	case 0x1c:      /* Informational Exceptions Mode page */
 		if (iec_m_pg[1] == arr[off + 1]) {
 			memcpy(iec_m_pg + 2, arr + off + 2,
@@ -3158,6 +3187,10 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 set_mode_changed_ua:
 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
 	return 0;
+
+bad_pcode:
+	mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
+	return check_condition_result;
 }
 
 static int resp_temp_l_pg(unsigned char *arr)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1 6/7] scsi: scsi_debug: Reset tape setting at device reset
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
                   ` (4 preceding siblings ...)
  2025-02-10 19:12 ` [PATCH v1 5/7] scsi: scsi_debug: Add compression mode page " Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  2025-02-10 19:12 ` [PATCH v1 7/7] scsi: scsi_debug: Add support for partitioning the tape Kai Mäkisara
  6 siblings, 0 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

Set tape block size, density and compression to default values when the
device is reset (either directly or via target, bus or host reset).

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
 drivers/scsi/scsi_debug.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 7b84acebe0fe..b40023dd812b 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -6772,6 +6772,20 @@ static int sdebug_fail_lun_reset(struct scsi_cmnd *cmnd)
 	return 0;
 }
 
+static void scsi_tape_reset_clear(struct sdebug_dev_info *devip)
+{
+	if (sdebug_ptype == TYPE_TAPE) {
+		int i;
+
+		devip->tape_blksize = TAPE_DEF_BLKSIZE;
+		devip->tape_density = TAPE_DEF_DENSITY;
+		devip->tape_partition = 0;
+		devip->tape_dce = 0;
+		for (i = 0; i < TAPE_MAX_PARTITIONS; i++)
+			devip->tape_location[i] = 0;
+	}
+}
+
 static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
 {
 	struct scsi_device *sdp = SCpnt->device;
@@ -6785,8 +6799,10 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
 
 	scsi_debug_stop_all_queued(sdp);
-	if (devip)
+	if (devip) {
 		set_bit(SDEBUG_UA_POR, devip->uas_bm);
+		scsi_tape_reset_clear(devip);
+	}
 
 	if (sdebug_fail_lun_reset(SCpnt)) {
 		scmd_printk(KERN_INFO, SCpnt, "fail lun reset 0x%x\n", opcode);
@@ -6824,6 +6840,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
 		if (devip->target == sdp->id) {
 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
+			scsi_tape_reset_clear(devip);
 			++k;
 		}
 	}
@@ -6855,6 +6872,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
 
 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
+		scsi_tape_reset_clear(devip);
 		++k;
 	}
 
@@ -6878,6 +6896,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
 				    dev_list) {
 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
+			scsi_tape_reset_clear(devip);
 			++k;
 		}
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1 7/7] scsi: scsi_debug: Add support for partitioning the tape
  2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
                   ` (5 preceding siblings ...)
  2025-02-10 19:12 ` [PATCH v1 6/7] scsi: scsi_debug: Reset tape setting at device reset Kai Mäkisara
@ 2025-02-10 19:12 ` Kai Mäkisara
  6 siblings, 0 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-10 19:12 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

This patch adds support for MEDIUM PARTITION PAGE in MODE SELECT and the
FORMAT MEDIUM command for tapes. After these additions, the virtual tape
can be partitioned containing either one or two partitions. The POFM
flag in the mode page is set, meaning that the FORMAT MEDIUM command
must be used to create the partitioning defined in the mode page.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
 drivers/scsi/scsi_debug.c | 108 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 104 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index b40023dd812b..277385e9b91c 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -188,6 +188,7 @@ static const char *sdebug_version_date = "20210520";
 #define TAPE_EW 20
 #define TAPE_MAX_PARTITIONS 2
 #define TAPE_UNITS 10000
+#define TAPE_PARTITION_1_UNITS 1000
 
 /* The tape block data definitions */
 #define TAPE_BLOCK_FM_FLAG   ((u32)0x1 << 30)
@@ -405,6 +406,9 @@ struct sdebug_dev_info {
 	unsigned int tape_density;
 	unsigned char tape_partition;
 	unsigned char tape_nbr_partitions;
+	unsigned char tape_pending_nbr_partitions;
+	unsigned int tape_pending_part_0_size;
+	unsigned int tape_pending_part_1_size;
 	unsigned char tape_dce;
 	unsigned int tape_location[TAPE_MAX_PARTITIONS];
 	unsigned int tape_eop[TAPE_MAX_PARTITIONS];
@@ -534,14 +538,15 @@ enum sdeb_opcode_index {
 	SDEB_I_LOCATE = 34,
 	SDEB_I_WRITE_FILEMARKS = 35,
 	SDEB_I_SPACE = 36,
-	SDEB_I_LAST_ELEM_P1 = 37,	/* keep this last (previous + 1) */
+	SDEB_I_FORMAT_MEDIUM = 37,
+	SDEB_I_LAST_ELEM_P1 = 38,	/* 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, SDEB_I_READ_BLOCK_LIMITS, 0, 0,
+	    SDEB_I_FORMAT_MEDIUM, SDEB_I_READ_BLOCK_LIMITS, 0, 0,
 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
 	SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0,
 	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE,
@@ -629,6 +634,7 @@ static int resp_locate(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_format_medium(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);
@@ -867,7 +873,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
-/* 31 */
+/* 32 */
 	{0, 0x0, 0x0, F_D_OUT | FF_MEDIA_IO,
 	    resp_atomic_write, NULL, /* ATOMIC WRITE 16 */
 		{16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -881,7 +887,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 	{0, 0x11, 0, F_D_IN, resp_space, NULL,    /* SPACE (6) */
 	    {6,  0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-
+	{0, 0x4, 0, 0, resp_format_medium, NULL,  /* FORMAT MEDIUM (6) */
+	    {6,  0x3, 0x7, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+/* 38 */
 /* 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} },
@@ -2844,6 +2852,51 @@ static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target)
 	return sizeof(partition_pg);
 }
 
+static int process_medium_part_m_pg(struct sdebug_dev_info *devip,
+				unsigned char *new, int pg_len)
+{
+	int new_nbr, p0_size, p1_size;
+
+	if ((new[4] & 0x80) != 0) { /* FDP */
+		partition_pg[4] |= 0x80;
+		devip->tape_pending_nbr_partitions = TAPE_MAX_PARTITIONS;
+		devip->tape_pending_part_0_size = TAPE_UNITS - TAPE_PARTITION_1_UNITS;
+		devip->tape_pending_part_1_size = TAPE_PARTITION_1_UNITS;
+	} else {
+		new_nbr = new[3] + 1;
+		if (new_nbr > TAPE_MAX_PARTITIONS)
+			return 3;
+		if ((new[4] & 0x40) != 0) { /* SDP */
+			p1_size = TAPE_PARTITION_1_UNITS;
+			p0_size = TAPE_UNITS - p1_size;
+			if (p0_size < 100)
+				return 4;
+		} else if ((new[4] & 0x20) != 0) {
+			if (new_nbr > 1) {
+				p0_size = get_unaligned_be16(new + 8);
+				p1_size = get_unaligned_be16(new + 10);
+				if (p1_size == 0xFFFF)
+					p1_size = TAPE_UNITS - p0_size;
+				else if (p0_size == 0xFFFF)
+					p0_size = TAPE_UNITS - p1_size;
+				if (p0_size < 100 || p1_size < 100)
+					return 8;
+			} else {
+				p0_size = TAPE_UNITS;
+				p1_size = 0;
+			}
+		} else
+			return 6;
+		devip->tape_pending_nbr_partitions = new_nbr;
+		devip->tape_pending_part_0_size = p0_size;
+		devip->tape_pending_part_1_size = p1_size;
+		partition_pg[3] = new_nbr;
+		devip->tape_pending_nbr_partitions = new_nbr;
+	}
+
+	return 0;
+}
+
 static int resp_compression_m_pg(unsigned char *p, int pcontrol, int target,
 	unsigned char dce)
 {	/* Compression page for mode_sense (tape) */
@@ -3172,6 +3225,17 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 			return 0;
 		}
 		break;
+	case 0x11:	/* Medium Partition Mode Page (tape) */
+		if (sdebug_ptype == TYPE_TAPE) {
+			int fld;
+
+			fld = process_medium_part_m_pg(devip, &arr[off], pg_len);
+			if (fld == 0)
+				return 0;
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, fld, -1);
+			return check_condition_result;
+		}
+		break;
 	case 0x1c:      /* Informational Exceptions Mode page */
 		if (iec_m_pg[1] == arr[off + 1]) {
 			memcpy(iec_m_pg + 2, arr + off + 2,
@@ -3556,6 +3620,39 @@ static int partition_tape(struct sdebug_dev_info *devip, int nbr_partitions,
 	return nbr_partitions;
 }
 
+static int resp_format_medium(struct scsi_cmnd *scp,
+			struct sdebug_dev_info *devip)
+{
+	int res = 0;
+	unsigned char *cmd = scp->cmnd;
+
+	if (sdebug_ptype != TYPE_TAPE) {
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 0, -1);
+		return check_condition_result;
+	}
+	if (cmd[2] > 2) {
+		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 2, -1);
+		return check_condition_result;
+	}
+	if (cmd[2] != 0) {
+		if (devip->tape_pending_nbr_partitions > 0) {
+			res = partition_tape(devip,
+					devip->tape_pending_nbr_partitions,
+					devip->tape_pending_part_0_size,
+					devip->tape_pending_part_1_size);
+		} else
+			res = partition_tape(devip, devip->tape_nbr_partitions,
+					devip->tape_eop[0], devip->tape_eop[1]);
+	} else
+		res = partition_tape(devip, 1, TAPE_UNITS, 0);
+	if (res < 0)
+		return -EINVAL;
+
+	devip->tape_pending_nbr_partitions = -1;
+
+	return 0;
+}
+
 static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
 {
 	return devip->nr_zones != 0;
@@ -6522,6 +6619,7 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp,
 			if (!devip->tape_blocks[0])
 				return 1;
 		}
+		devip->tape_pending_nbr_partitions = -1;
 		if (partition_tape(devip, 1, TAPE_UNITS, 0) < 0) {
 			kfree(devip->tape_blocks[0]);
 			devip->tape_blocks[0] = NULL;
@@ -6783,6 +6881,8 @@ static void scsi_tape_reset_clear(struct sdebug_dev_info *devip)
 		devip->tape_dce = 0;
 		for (i = 0; i < TAPE_MAX_PARTITIONS; i++)
 			devip->tape_location[i] = 0;
+		devip->tape_pending_nbr_partitions = -1;
+		/* Don't reset partitioning? */
 	}
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
  2025-02-10 19:12 ` [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD " Kai Mäkisara
@ 2025-02-11 10:41   ` kernel test robot
  2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
  1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-02-11 10:41 UTC (permalink / raw)
  To: Kai Mäkisara, linux-scsi, dgilbert
  Cc: llvm, oe-kbuild-all, martin.petersen, James.Bottomley, jmeneghi,
	Kai Mäkisara

Hi Kai,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jejb-scsi/for-next]
[also build test WARNING on mkp-scsi/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kai-M-kisara/scsi-scsi_debug-First-fixes-for-tapes/20250211-031623
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
patch link:    https://lore.kernel.org/r/20250210191232.185207-3-Kai.Makisara%40kolumbus.fi
patch subject: [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20250211/202502111805.dXd61ARr-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250211/202502111805.dXd61ARr-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502111805.dXd61ARr-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/scsi/scsi_debug.c:31:
   In file included from include/linux/scatterlist.h:8:
   In file included from include/linux/mm.h:2224:
   include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     504 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     505 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     511 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     512 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     524 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     525 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
>> drivers/scsi/scsi_debug.c:2926:3: warning: variable 'len' is uninitialized when used here [-Wuninitialized]
    2926 |                 len += resp_partition_m_pg(ap, pcontrol, target);
         |                 ^~~
   drivers/scsi/scsi_debug.c:2791:28: note: initialize the variable 'len' to silence this warning
    2791 |         u32 alloc_len, offset, len;
         |                                   ^
         |                                    = 0
   4 warnings generated.


vim +/len +2926 drivers/scsi/scsi_debug.c

  2785	
  2786	static int resp_mode_sense(struct scsi_cmnd *scp,
  2787				   struct sdebug_dev_info *devip)
  2788	{
  2789		int pcontrol, pcode, subpcode, bd_len;
  2790		unsigned char dev_spec;
  2791		u32 alloc_len, offset, len;
  2792		int target_dev_id;
  2793		int target = scp->device->id;
  2794		unsigned char *ap;
  2795		unsigned char *arr __free(kfree);
  2796		unsigned char *cmd = scp->cmnd;
  2797		bool dbd, llbaa, msense_6, is_disk, is_zbc, is_tape;
  2798	
  2799		arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC);
  2800		if (!arr)
  2801			return -ENOMEM;
  2802		dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
  2803		pcontrol = (cmd[2] & 0xc0) >> 6;
  2804		pcode = cmd[2] & 0x3f;
  2805		subpcode = cmd[3];
  2806		msense_6 = (MODE_SENSE == cmd[0]);
  2807		llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
  2808		is_disk = (sdebug_ptype == TYPE_DISK);
  2809		is_zbc = devip->zoned;
  2810		is_tape = (sdebug_ptype == TYPE_TAPE);
  2811		if ((is_disk || is_zbc || is_tape) && !dbd)
  2812			bd_len = llbaa ? 16 : 8;
  2813		else
  2814			bd_len = 0;
  2815		alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
  2816		if (0x3 == pcontrol) {  /* Saving values not supported */
  2817			mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
  2818			return check_condition_result;
  2819		}
  2820		target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
  2821				(devip->target * 1000) - 3;
  2822		/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
  2823		if (is_disk || is_zbc) {
  2824			dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
  2825			if (sdebug_wp)
  2826				dev_spec |= 0x80;
  2827		} else
  2828			dev_spec = 0x0;
  2829		if (msense_6) {
  2830			arr[2] = dev_spec;
  2831			arr[3] = bd_len;
  2832			offset = 4;
  2833		} else {
  2834			arr[3] = dev_spec;
  2835			if (16 == bd_len)
  2836				arr[4] = 0x1;	/* set LONGLBA bit */
  2837			arr[7] = bd_len;	/* assume 255 or less */
  2838			offset = 8;
  2839		}
  2840		ap = arr + offset;
  2841		if ((bd_len > 0) && (!sdebug_capacity))
  2842			sdebug_capacity = get_sdebug_capacity();
  2843	
  2844		if (8 == bd_len) {
  2845			if (sdebug_capacity > 0xfffffffe)
  2846				put_unaligned_be32(0xffffffff, ap + 0);
  2847			else
  2848				put_unaligned_be32(sdebug_capacity, ap + 0);
  2849			if (is_tape) {
  2850				ap[0] = devip->tape_density;
  2851				put_unaligned_be16(devip->tape_blksize, ap + 6);
  2852			} else
  2853				put_unaligned_be16(sdebug_sector_size, ap + 6);
  2854			offset += bd_len;
  2855			ap = arr + offset;
  2856		} else if (16 == bd_len) {
  2857			if (is_tape) {
  2858				mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, 4);
  2859				return check_condition_result;
  2860			}
  2861			put_unaligned_be64((u64)sdebug_capacity, ap + 0);
  2862			put_unaligned_be32(sdebug_sector_size, ap + 12);
  2863			offset += bd_len;
  2864			ap = arr + offset;
  2865		}
  2866		if (cmd[2] == 0)
  2867			goto only_bd; /* Only block descriptor requested */
  2868	
  2869		/*
  2870		 * N.B. If len>0 before resp_*_pg() call, then form of that call should be:
  2871		 *        len += resp_*_pg(ap + len, pcontrol, target);
  2872		 */
  2873		switch (pcode) {
  2874		case 0x1:	/* Read-Write error recovery page, direct access */
  2875			if (subpcode > 0x0 && subpcode < 0xff)
  2876				goto bad_subpcode;
  2877			len = resp_err_recov_pg(ap, pcontrol, target);
  2878			offset += len;
  2879			break;
  2880		case 0x2:	/* Disconnect-Reconnect page, all devices */
  2881			if (subpcode > 0x0 && subpcode < 0xff)
  2882				goto bad_subpcode;
  2883			len = resp_disconnect_pg(ap, pcontrol, target);
  2884			offset += len;
  2885			break;
  2886		case 0x3:       /* Format device page, direct access */
  2887			if (subpcode > 0x0 && subpcode < 0xff)
  2888				goto bad_subpcode;
  2889			if (is_disk) {
  2890				len = resp_format_pg(ap, pcontrol, target);
  2891				offset += len;
  2892			} else {
  2893				goto bad_pcode;
  2894			}
  2895			break;
  2896		case 0x8:	/* Caching page, direct access */
  2897			if (subpcode > 0x0 && subpcode < 0xff)
  2898				goto bad_subpcode;
  2899			if (is_disk || is_zbc) {
  2900				len = resp_caching_pg(ap, pcontrol, target);
  2901				offset += len;
  2902			} else {
  2903				goto bad_pcode;
  2904			}
  2905			break;
  2906		case 0xa:	/* Control Mode page, all devices */
  2907			switch (subpcode) {
  2908			case 0:
  2909				len = resp_ctrl_m_pg(ap, pcontrol, target);
  2910				break;
  2911			case 0x05:
  2912				len = resp_grouping_m_pg(ap, pcontrol, target);
  2913				break;
  2914			case 0xff:
  2915				len = resp_ctrl_m_pg(ap, pcontrol, target);
  2916				len += resp_grouping_m_pg(ap + len, pcontrol, target);
  2917				break;
  2918			default:
  2919				goto bad_subpcode;
  2920			}
  2921			offset += len;
  2922			break;
  2923		case 0x11:	/* Partition Mode Page (tape) */
  2924			if (!is_tape)
  2925				goto bad_pcode;
> 2926			len += resp_partition_m_pg(ap, pcontrol, target);
  2927			offset += len;
  2928			break;
  2929		case 0x19:	/* if spc==1 then sas phy, control+discover */
  2930			if (subpcode > 0x2 && subpcode < 0xff)
  2931				goto bad_subpcode;
  2932			len = 0;
  2933			if ((0x0 == subpcode) || (0xff == subpcode))
  2934				len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
  2935			if ((0x1 == subpcode) || (0xff == subpcode))
  2936				len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
  2937							  target_dev_id);
  2938			if ((0x2 == subpcode) || (0xff == subpcode))
  2939				len += resp_sas_sha_m_spg(ap + len, pcontrol);
  2940			offset += len;
  2941			break;
  2942		case 0x1c:	/* Informational Exceptions Mode page, all devices */
  2943			if (subpcode > 0x0 && subpcode < 0xff)
  2944				goto bad_subpcode;
  2945			len = resp_iec_m_pg(ap, pcontrol, target);
  2946			offset += len;
  2947			break;
  2948		case 0x3f:	/* Read all Mode pages */
  2949			if (subpcode > 0x0 && subpcode < 0xff)
  2950				goto bad_subpcode;
  2951			len = resp_err_recov_pg(ap, pcontrol, target);
  2952			len += resp_disconnect_pg(ap + len, pcontrol, target);
  2953			if (is_disk) {
  2954				len += resp_format_pg(ap + len, pcontrol, target);
  2955				len += resp_caching_pg(ap + len, pcontrol, target);
  2956			} else if (is_zbc) {
  2957				len += resp_caching_pg(ap + len, pcontrol, target);
  2958			}
  2959			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
  2960			if (0xff == subpcode)
  2961				len += resp_grouping_m_pg(ap + len, pcontrol, target);
  2962			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
  2963			if (0xff == subpcode) {
  2964				len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
  2965							  target_dev_id);
  2966				len += resp_sas_sha_m_spg(ap + len, pcontrol);
  2967			}
  2968			len += resp_iec_m_pg(ap + len, pcontrol, target);
  2969			offset += len;
  2970			break;
  2971		default:
  2972			goto bad_pcode;
  2973		}
  2974	only_bd:
  2975		if (msense_6)
  2976			arr[0] = offset - 1;
  2977		else
  2978			put_unaligned_be16((offset - 2), arr + 0);
  2979		return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
  2980	
  2981	bad_pcode:
  2982		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
  2983		return check_condition_result;
  2984	
  2985	bad_subpcode:
  2986		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
  2987		return check_condition_result;
  2988	}
  2989	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data
  2025-02-10 19:12 ` [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data Kai Mäkisara
@ 2025-02-11 13:08   ` kernel test robot
  2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
  1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-02-11 13:08 UTC (permalink / raw)
  To: Kai Mäkisara, linux-scsi, dgilbert
  Cc: llvm, oe-kbuild-all, martin.petersen, James.Bottomley, jmeneghi,
	Kai Mäkisara

Hi Kai,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jejb-scsi/for-next]
[also build test WARNING on mkp-scsi/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kai-M-kisara/scsi-scsi_debug-First-fixes-for-tapes/20250211-031623
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
patch link:    https://lore.kernel.org/r/20250210191232.185207-4-Kai.Makisara%40kolumbus.fi
patch subject: [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20250211/202502112016.6zs2FpD6-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250211/202502112016.6zs2FpD6-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502112016.6zs2FpD6-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/scsi/scsi_debug.c:31:
   In file included from include/linux/scatterlist.h:8:
   In file included from include/linux/mm.h:2224:
   include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     504 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     505 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     511 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     512 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     524 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     525 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/scsi_debug.c:2985:3: warning: variable 'len' is uninitialized when used here [-Wuninitialized]
    2985 |                 len += resp_partition_m_pg(ap, pcontrol, target);
         |                 ^~~
   drivers/scsi/scsi_debug.c:2850:28: note: initialize the variable 'len' to silence this warning
    2850 |         u32 alloc_len, offset, len;
         |                                   ^
         |                                    = 0
>> drivers/scsi/scsi_debug.c:3378:10: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
    3378 |         for ( ; i < TAPE_MAX_PARTITIONS; i++)
         |                 ^
   drivers/scsi/scsi_debug.c:3367:7: note: initialize the variable 'i' to silence this warning
    3367 |         int i;
         |              ^
         |               = 0
   5 warnings generated.


vim +/i +3378 drivers/scsi/scsi_debug.c

  3363	
  3364	static int partition_tape(struct sdebug_dev_info *devip, int nbr_partitions,
  3365				int part_0_size, int part_1_size)
  3366	{
  3367		int i;
  3368	
  3369		if (part_0_size + part_1_size > TAPE_UNITS)
  3370			return -1;
  3371		devip->tape_eop[0] = part_0_size;
  3372		devip->tape_blocks[0]->fl_size = TAPE_BLOCK_EOD_FLAG;
  3373		devip->tape_eop[1] = part_1_size;
  3374		devip->tape_blocks[1] = devip->tape_blocks[0] +
  3375				devip->tape_eop[0];
  3376		devip->tape_blocks[1]->fl_size = TAPE_BLOCK_EOD_FLAG;
  3377	
> 3378		for ( ; i < TAPE_MAX_PARTITIONS; i++)
  3379			devip->tape_location[i] = 0;
  3380	
  3381		devip->tape_nbr_partitions = nbr_partitions;
  3382		devip->tape_partition = 0;
  3383	
  3384		partition_pg[3] = nbr_partitions - 1;
  3385		put_unaligned_be16(devip->tape_eop[0], partition_pg + 8);
  3386		put_unaligned_be16(devip->tape_eop[1], partition_pg + 10);
  3387	
  3388		return nbr_partitions;
  3389	}
  3390	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v1b 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
  2025-02-10 19:12 ` [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD " Kai Mäkisara
  2025-02-11 10:41   ` kernel test robot
@ 2025-02-11 14:11   ` Kai Mäkisara
  2025-02-13  3:11     ` Martin K. Petersen
  1 sibling, 1 reply; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-11 14:11 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

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>
---
v1 -> v1b:
- change 'len +=' to 'len =' to fix the bug reported by the Kernel Test Robot

 drivers/scsi/scsi_debug.c | 127 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 121 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 4da0c259390b..21c64f79797a 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 unsigned char partition_pg[] = {0x11, 12, 1, 0, 0x24, 3, 9, 0,
+	0xff, 0xff, 0x00, 0x00};
+
+static int resp_partition_m_pg(unsigned char *p, int pcontrol, int target)
+{	/* Partition page for mode_sense (tape) */
+	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
 
@@ -2876,6 +2920,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;
@@ -2974,9 +3024,16 @@ static int resp_mode_select(struct scsi_cmnd *scp,
 					mselect6 ? 3 : 6, -1);
 			return check_condition_result;
 		}
+		if (arr[off] == TAPE_BAD_DENSITY) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
+			return check_condition_result;
+		}
 		blksize = get_unaligned_be16(arr + off + 6);
-		if ((blksize % 4) != 0) {
-			mk_sense_invalid_fld(scp, SDEB_IN_DATA, off + 6, -1);
+		if (blksize != 0 &&
+			(blksize < TAPE_MIN_BLKSIZE ||
+				blksize > TAPE_MAX_BLKSIZE ||
+				(blksize % 4) != 0)) {
+			mk_sense_invalid_fld(scp, SDEB_IN_DATA, 1, -1);
 			return check_condition_result;
 		}
 		devip->tape_density = arr[off];
@@ -3177,6 +3234,36 @@ static int resp_log_sense(struct scsi_cmnd *scp,
 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
 }
 
+enum {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];
+
+	arr[0] = 4;
+	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;
@@ -4957,7 +5044,10 @@ 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.
  */
+enum {SDEBUG_READ_POSITION_ARR_SZ = 20};
 static int resp_pre_fetch(struct scsi_cmnd *scp,
 			  struct sdebug_dev_info *devip)
 {
@@ -4969,6 +5059,31 @@ 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 ||
+				all_length != 0) { /* only short form */
+				mk_sense_invalid_fld(scp, SDEB_IN_CDB,
+						all_length ? 7 : 1, 0);
+				return check_condition_result;
+			}
+			memset(arr, 0, SDEBUG_READ_POSITION_ARR_SZ);
+			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,
+						SDEBUG_READ_POSITION_ARR_SZ);
+		}
+		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);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v1b 3/7] scsi: scsi_debug: Add write support with block lengths  and 4 bytes of data
  2025-02-10 19:12 ` [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data Kai Mäkisara
  2025-02-11 13:08   ` kernel test robot
@ 2025-02-11 14:11   ` Kai Mäkisara
  1 sibling, 0 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-11 14:11 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

The tape is implemented as fixed number (10 000) of 8-byte units.
The first four bytes of a unit contains the type of the unit (data
block, filemark or end-of-data mark). If the units is a data block,
the first four bytes contain the block length and the remaining
four bytes the first bytes of written data. This allows the user
to use tags to see that the read block is what it was supposed to be.

The tape can contain two partitions. Initially it is formatted as one
partition consisting of all 10 000 units.

This patch adds the WRITE(6) command for tapes and the WRITE FILEMARKS (6)
command. The REWIND command is updated.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---
v1 -> v1b:
- change 'for (;' to 'for (i = 0;' to fix the bug reported by the
  Kernel Test Robot

 drivers/scsi/scsi_debug.c | 217 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 212 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 21c64f79797a..69cae4c1712a 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -71,6 +71,10 @@ static const char *sdebug_version_date = "20210520";
 #define NO_ADDITIONAL_SENSE 0x0
 #define OVERLAP_ATOMIC_COMMAND_ASC 0x0
 #define OVERLAP_ATOMIC_COMMAND_ASCQ 0x23
+#define FILEMARK_DETECTED_ASCQ 0x1
+#define EOP_EOM_DETECTED_ASCQ 0x2
+#define BEGINNING_OF_P_M_DETECTED_ASCQ 0x4
+#define EOD_DETECTED_ASCQ 0x5
 #define LOGICAL_UNIT_NOT_READY 0x4
 #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
 #define UNRECOVERED_READ_ERR 0x11
@@ -83,6 +87,7 @@ static const char *sdebug_version_date = "20210520";
 #define UA_READY_ASC 0x28
 #define UA_RESET_ASC 0x29
 #define UA_CHANGED_ASC 0x2a
+#define TOO_MANY_IN_PARTITION_ASC 0x3b
 #define TARGET_CHANGED_ASC 0x3f
 #define LUNS_CHANGED_ASCQ 0x0e
 #define INSUFF_RES_ASC 0x55
@@ -180,7 +185,29 @@ static const char *sdebug_version_date = "20210520";
 #define TAPE_DEF_BLKSIZE  0
 #define TAPE_MIN_BLKSIZE  512
 #define TAPE_MAX_BLKSIZE  1048576
+#define TAPE_EW 20
 #define TAPE_MAX_PARTITIONS 2
+#define TAPE_UNITS 10000
+
+/* The tape block data definitions */
+#define TAPE_BLOCK_FM_FLAG   ((u32)0x1 << 30)
+#define TAPE_BLOCK_EOD_FLAG  ((u32)0x2 << 30)
+#define TAPE_BLOCK_MARK_MASK ((u32)0x3 << 30)
+#define TAPE_BLOCK_SIZE_MASK (~TAPE_BLOCK_MARK_MASK)
+#define TAPE_BLOCK_MARK(a) (a & TAPE_BLOCK_MARK_MASK)
+#define TAPE_BLOCK_SIZE(a) (a & TAPE_BLOCK_SIZE_MASK)
+#define IS_TAPE_BLOCK_FM(a)   ((a & TAPE_BLOCK_FM_FLAG) != 0)
+#define IS_TAPE_BLOCK_EOD(a)  ((a & TAPE_BLOCK_EOD_FLAG) != 0)
+
+struct tape_block {
+	u32 fl_size;
+	unsigned char data[4];
+};
+
+/* Flags for sense data */
+#define SENSE_FLAG_FILEMARK  0x80
+#define SENSE_FLAG_EOM 0x40
+#define SENSE_FLAG_ILI 0x20
 
 #define SDEBUG_LUN_0_VAL 0
 
@@ -377,7 +404,10 @@ struct sdebug_dev_info {
 	unsigned int tape_blksize;
 	unsigned int tape_density;
 	unsigned char tape_partition;
+	unsigned char tape_nbr_partitions;
 	unsigned int tape_location[TAPE_MAX_PARTITIONS];
+	unsigned int tape_eop[TAPE_MAX_PARTITIONS];
+	struct tape_block *tape_blocks[TAPE_MAX_PARTITIONS];
 
 	struct dentry *debugfs_entry;
 	struct spinlock list_lock;
@@ -501,7 +531,8 @@ enum sdeb_opcode_index {
 	SDEB_I_ATOMIC_WRITE_16 = 32,
 	SDEB_I_READ_BLOCK_LIMITS = 33,
 	SDEB_I_LOCATE = 34,
-	SDEB_I_LAST_ELEM_P1 = 35,	/* keep this last (previous + 1) */
+	SDEB_I_WRITE_FILEMARKS = 35,
+	SDEB_I_LAST_ELEM_P1 = 36,	/* keep this last (previous + 1) */
 };
 
 
@@ -510,8 +541,8 @@ static const unsigned char opcode_ind_arr[256] = {
 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
 	    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,
+	SDEB_I_WRITE_FILEMARKS, 0, SDEB_I_INQUIRY, 0, 0,
+	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE,
 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
 	    SDEB_I_ALLOW_REMOVAL, 0,
 /* 0x20; 0x20->0x3f: 10 byte cdbs */
@@ -593,6 +624,8 @@ 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 resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_rewind(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);
@@ -793,7 +826,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 /* 20 */
 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-	{0, 0x1, 0, 0, NULL, NULL, /* REWIND ?? */
+	{0, 0x1, 0, 0, resp_rewind, NULL,
 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
@@ -841,6 +874,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 	{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} },
+	{0, 0x10, 0, F_D_IN, resp_write_filemarks, NULL,    /* WRITE FILEMARKS (6) */
+	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 /* sentinel */
 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
@@ -1358,6 +1393,30 @@ static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
 			    my_name, key, asc, asq);
 }
 
+/* Sense data that has information fields for tapes */
+static void mk_sense_info_tape(struct scsi_cmnd *scp, int key, int asc, int asq,
+			unsigned int information, unsigned char tape_flags)
+{
+	if (!scp->sense_buffer) {
+		sdev_printk(KERN_ERR, scp->device,
+			    "%s: sense_buffer is NULL\n", __func__);
+		return;
+	}
+	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+
+	scsi_build_sense(scp, /*sdebug_dsense*/ 0, key, asc, asq);
+	/* only fixed format so far */
+
+	scp->sense_buffer[0] |= 0x80; /* valid */
+	scp->sense_buffer[2] |= tape_flags;
+	put_unaligned_be32(information, &scp->sense_buffer[3]);
+
+	if (sdebug_verbose)
+		sdev_printk(KERN_INFO, scp->device,
+			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
+			    my_name, key, asc, asq);
+}
+
 static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
 {
 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
@@ -3252,7 +3311,7 @@ static int resp_locate(struct scsi_cmnd *scp,
 	unsigned char *cmd = scp->cmnd;
 
 	if ((cmd[1] & 0x02) != 0) {
-		if (cmd[8] >= TAPE_MAX_PARTITIONS) {
+		if (cmd[8] >= devip->tape_nbr_partitions) {
 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1);
 			return check_condition_result;
 		}
@@ -3264,6 +3323,71 @@ static int resp_locate(struct scsi_cmnd *scp,
 	return 0;
 }
 
+static int resp_write_filemarks(struct scsi_cmnd *scp,
+		struct sdebug_dev_info *devip)
+{
+	unsigned char *cmd = scp->cmnd;
+	unsigned int i, count, pos;
+	u32 data;
+	int partition = devip->tape_partition;
+
+	if ((cmd[1] & 0xfe) != 0) { /* probably write setmarks, not in >= SCSI-3 */
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
+		return check_condition_result;
+	}
+	count = get_unaligned_be24(cmd + 2);
+	data = TAPE_BLOCK_FM_FLAG;
+	for (i = 0, pos = devip->tape_location[partition]; i < count; i++, pos++) {
+		if (pos >= devip->tape_eop[partition] - 1) { /* don't overwrite EOD */
+			devip->tape_location[partition] = devip->tape_eop[partition] - 1;
+			mk_sense_info_tape(scp, VOLUME_OVERFLOW, NO_ADDITIONAL_SENSE,
+					EOP_EOM_DETECTED_ASCQ, count, SENSE_FLAG_EOM);
+			return check_condition_result;
+		}
+		(devip->tape_blocks[partition] + pos)->fl_size = data;
+	}
+	(devip->tape_blocks[partition] + pos)->fl_size =
+		TAPE_BLOCK_EOD_FLAG;
+	devip->tape_location[partition] = pos;
+
+	return 0;
+}
+
+static int resp_rewind(struct scsi_cmnd *scp,
+		struct sdebug_dev_info *devip)
+{
+	devip->tape_location[devip->tape_partition] = 0;
+
+	return 0;
+}
+
+static int partition_tape(struct sdebug_dev_info *devip, int nbr_partitions,
+			int part_0_size, int part_1_size)
+{
+	int i;
+
+	if (part_0_size + part_1_size > TAPE_UNITS)
+		return -1;
+	devip->tape_eop[0] = part_0_size;
+	devip->tape_blocks[0]->fl_size = TAPE_BLOCK_EOD_FLAG;
+	devip->tape_eop[1] = part_1_size;
+	devip->tape_blocks[1] = devip->tape_blocks[0] +
+			devip->tape_eop[0];
+	devip->tape_blocks[1]->fl_size = TAPE_BLOCK_EOD_FLAG;
+
+	for (i = 0 ; i < TAPE_MAX_PARTITIONS; i++)
+		devip->tape_location[i] = 0;
+
+	devip->tape_nbr_partitions = nbr_partitions;
+	devip->tape_partition = 0;
+
+	partition_pg[3] = nbr_partitions - 1;
+	put_unaligned_be16(devip->tape_eop[0], partition_pg + 8);
+	put_unaligned_be16(devip->tape_eop[1], partition_pg + 10);
+
+	return nbr_partitions;
+}
+
 static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
 {
 	return devip->nr_zones != 0;
@@ -4304,6 +4428,67 @@ static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
 	}
 }
 
+static int resp_write_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+	u32 i, num, transfer, size, written = 0;
+	u8 *cmd = scp->cmnd;
+	struct scsi_data_buffer *sdb = &scp->sdb;
+	int partition = devip->tape_partition;
+	int pos = devip->tape_location[partition];
+	struct tape_block *blp;
+	bool fixed, ew;
+
+	if (cmd[0] != WRITE_6) { /* Only Write(6) supported */
+		mk_sense_invalid_opcode(scp);
+		return illegal_condition_result;
+	}
+
+	fixed = (cmd[1] & 1) != 0;
+	transfer = get_unaligned_be24(cmd + 2);
+	if (fixed) {
+		num = transfer;
+		size = devip->tape_blksize;
+	} else {
+		if (transfer < TAPE_MIN_BLKSIZE ||
+			transfer > TAPE_MAX_BLKSIZE) {
+			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
+			return check_condition_result;
+		}
+		num = 1;
+		size = transfer;
+	}
+
+	scsi_set_resid(scp, num * transfer);
+	for (i = 0, blp = devip->tape_blocks[partition] + pos, ew = false;
+	     i < num && pos < devip->tape_eop[partition] - 1; i++, pos++, blp++) {
+		blp->fl_size = size;
+		sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
+			&(blp->data), 4, i * size, true);
+		written += size;
+		scsi_set_resid(scp, num * transfer - written);
+		ew |= (pos == devip->tape_eop[partition] - TAPE_EW);
+	}
+
+	devip->tape_location[partition] = pos;
+	blp->fl_size = TAPE_BLOCK_EOD_FLAG;
+	if (pos >= devip->tape_eop[partition] - 1) {
+		mk_sense_info_tape(scp, VOLUME_OVERFLOW,
+				NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ,
+				fixed ? num - i : transfer,
+				SENSE_FLAG_EOM);
+		return check_condition_result;
+	}
+	if (ew) { /* early warning */
+		mk_sense_info_tape(scp, NO_SENSE,
+				NO_ADDITIONAL_SENSE, EOP_EOM_DETECTED_ASCQ,
+				fixed ? num - i : transfer,
+				SENSE_FLAG_EOM);
+		return check_condition_result;
+	}
+
+	return 0;
+}
+
 static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
 	bool check_prot;
@@ -4316,6 +4501,9 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	u8 *cmd = scp->cmnd;
 	bool meta_data_locked = false;
 
+	if (sdebug_ptype == TYPE_TAPE)
+		return resp_write_tape(scp, devip);
+
 	switch (cmd[0]) {
 	case WRITE_16:
 		ei_lba = 0;
@@ -6063,6 +6251,20 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp,
 		if (devip == NULL)
 			return 1;  /* no resources, will be marked offline */
 	}
+	if (sdebug_ptype == TYPE_TAPE) {
+		if (!devip->tape_blocks[0]) {
+			devip->tape_blocks[0] =
+				kcalloc(TAPE_UNITS, sizeof(struct tape_block),
+					GFP_KERNEL);
+			if (!devip->tape_blocks[0])
+				return 1;
+		}
+		if (partition_tape(devip, 1, TAPE_UNITS, 0) < 0) {
+			kfree(devip->tape_blocks[0]);
+			devip->tape_blocks[0] = NULL;
+			return 1;
+		}
+	}
 	sdp->hostdata = devip;
 	if (sdebug_no_uld)
 		sdp->no_uld_attach = 1;
@@ -6108,6 +6310,11 @@ static void scsi_debug_sdev_destroy(struct scsi_device *sdp)
 
 	debugfs_remove(devip->debugfs_entry);
 
+	if (sdebug_ptype == TYPE_TAPE) {
+		kfree(devip->tape_blocks[0]);
+		devip->tape_blocks[0] = NULL;
+	}
+
 	/* make this slot available for re-use */
 	devip->used = false;
 	sdp->hostdata = NULL;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes
  2025-02-10 19:12 ` [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes Kai Mäkisara
@ 2025-02-11 15:50   ` kernel test robot
  2025-02-11 21:26   ` [PATCH v1b " Kai Mäkisara
  1 sibling, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-02-11 15:50 UTC (permalink / raw)
  To: Kai Mäkisara, linux-scsi, dgilbert
  Cc: llvm, oe-kbuild-all, martin.petersen, James.Bottomley, jmeneghi,
	Kai Mäkisara

Hi Kai,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jejb-scsi/for-next]
[also build test WARNING on mkp-scsi/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kai-M-kisara/scsi-scsi_debug-First-fixes-for-tapes/20250211-031623
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
patch link:    https://lore.kernel.org/r/20250210191232.185207-5-Kai.Makisara%40kolumbus.fi
patch subject: [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20250211/202502112330.2jlgUZM7-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250211/202502112330.2jlgUZM7-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502112330.2jlgUZM7-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/scsi/scsi_debug.c:31:
   In file included from include/linux/scatterlist.h:8:
   In file included from include/linux/mm.h:2224:
   include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     504 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     505 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     511 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     512 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     524 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     525 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/scsi_debug.c:2989:3: warning: variable 'len' is uninitialized when used here [-Wuninitialized]
    2989 |                 len += resp_partition_m_pg(ap, pcontrol, target);
         |                 ^~~
   drivers/scsi/scsi_debug.c:2854:28: note: initialize the variable 'len' to silence this warning
    2854 |         u32 alloc_len, offset, len;
         |                                   ^
         |                                    = 0
>> drivers/scsi/scsi_debug.c:3419:8: warning: variable 'i' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
    3419 |                         if (pos == 0)
         |                             ^~~~~~~~
   drivers/scsi/scsi_debug.c:3478:44: note: uninitialized use occurs here
    3478 |                         BEGINNING_OF_P_M_DETECTED_ASCQ, count - i,
         |                                                                 ^
   drivers/scsi/scsi_debug.c:3419:4: note: remove the 'if' if its condition is always false
    3419 |                         if (pos == 0)
         |                         ^~~~~~~~~~~~~
    3420 |                                 goto is_bop;
         |                                 ~~~~~~~~~~~~
    3421 |                         else {
         |                         ~~~~
   drivers/scsi/scsi_debug.c:3378:7: note: initialize the variable 'i' to silence this warning
    3378 |         int i, pos, count;
         |              ^
         |               = 0
   drivers/scsi/scsi_debug.c:3513:10: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
    3513 |         for ( ; i < TAPE_MAX_PARTITIONS; i++)
         |                 ^
   drivers/scsi/scsi_debug.c:3502:7: note: initialize the variable 'i' to silence this warning
    3502 |         int i;
         |              ^
         |               = 0
   6 warnings generated.


vim +3419 drivers/scsi/scsi_debug.c

  3373	
  3374	static int resp_space(struct scsi_cmnd *scp,
  3375			struct sdebug_dev_info *devip)
  3376	{
  3377		unsigned char *cmd = scp->cmnd, code;
  3378		int i, pos, count;
  3379		struct tape_block *blp;
  3380		int partition = devip->tape_partition;
  3381	
  3382		count = get_unaligned_be24(cmd + 2);
  3383		if ((count & 0x800000) != 0) /* extend negative to 32-bit count */
  3384			count |= 0xff000000;
  3385		code = cmd[1] & 0x0f;
  3386	
  3387		pos = devip->tape_location[partition];
  3388		if (code == 0) { /* blocks */
  3389			if (count < 0) {
  3390				count = (-count);
  3391				pos -= 1;
  3392				for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count;
  3393				     i++) {
  3394					if (pos < 0)
  3395						goto is_bop;
  3396					else if (IS_TAPE_BLOCK_FM(blp->fl_size))
  3397						goto is_fm;
  3398					if (i > 0) {
  3399						pos--;
  3400						blp--;
  3401					}
  3402				}
  3403			} else if (count > 0) {
  3404				for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count;
  3405				     i++, pos++, blp++) {
  3406					if (IS_TAPE_BLOCK_EOD(blp->fl_size))
  3407						goto is_eod;
  3408					if (IS_TAPE_BLOCK_FM(blp->fl_size)) {
  3409						pos += 1;
  3410						goto is_fm;
  3411					}
  3412					if (pos >= devip->tape_eop[partition])
  3413						goto is_eop;
  3414				}
  3415			}
  3416		} else if (code == 1) { /* filemarks */
  3417			if (count < 0) {
  3418				count = (-count);
> 3419				if (pos == 0)
  3420					goto is_bop;
  3421				else {
  3422					for (i = 0, blp = devip->tape_blocks[partition] + pos;
  3423					     i < count && pos >= 0; i++, pos--, blp--) {
  3424						for (pos--, blp-- ; !IS_TAPE_BLOCK_FM(blp->fl_size) &&
  3425							     pos >= 0; pos--, blp--)
  3426							; /* empty */
  3427						if (pos < 0)
  3428							goto is_bop;
  3429					}
  3430				}
  3431				pos += 1;
  3432			} else if (count > 0) {
  3433				for (i = 0, blp = devip->tape_blocks[partition] + pos;
  3434				     i < count; i++, pos++, blp++) {
  3435					for ( ; !IS_TAPE_BLOCK_FM(blp->fl_size) &&
  3436						      !IS_TAPE_BLOCK_EOD(blp->fl_size) &&
  3437						      pos < devip->tape_eop[partition];
  3438					      pos++, blp++)
  3439						; /* empty */
  3440					if (IS_TAPE_BLOCK_EOD(blp->fl_size))
  3441						goto is_eod;
  3442					if (pos >= devip->tape_eop[partition])
  3443						goto is_eop;
  3444				}
  3445			}
  3446		} else if (code == 3) { /* EOD */
  3447			for (blp = devip->tape_blocks[partition] + pos;
  3448			     !IS_TAPE_BLOCK_EOD(blp->fl_size) && pos < devip->tape_eop[partition];
  3449			     pos++, blp++)
  3450				; /* empty */
  3451			if (pos >= devip->tape_eop[partition])
  3452				goto is_eop;
  3453		} else {
  3454			/* sequential filemarks not supported */
  3455			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1);
  3456			return check_condition_result;
  3457		}
  3458		devip->tape_location[partition] = pos;
  3459		return 0;
  3460	
  3461	is_fm:
  3462		devip->tape_location[partition] = pos;
  3463		mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
  3464				FILEMARK_DETECTED_ASCQ, count - i,
  3465				SENSE_FLAG_FILEMARK);
  3466		return check_condition_result;
  3467	
  3468	is_eod:
  3469		devip->tape_location[partition] = pos;
  3470		mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE,
  3471				EOD_DETECTED_ASCQ, count - i,
  3472				0);
  3473		return check_condition_result;
  3474	
  3475	is_bop:
  3476		devip->tape_location[partition] = 0;
  3477		mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
  3478				BEGINNING_OF_P_M_DETECTED_ASCQ, count - i,
  3479				SENSE_FLAG_EOM);
  3480		devip->tape_location[partition] = 0;
  3481		return check_condition_result;
  3482	
  3483	is_eop:
  3484		devip->tape_location[partition] = devip->tape_eop[partition] - 1;
  3485		mk_sense_info_tape(scp, MEDIUM_ERROR, NO_ADDITIONAL_SENSE,
  3486				EOP_EOM_DETECTED_ASCQ, (unsigned int)i,
  3487				SENSE_FLAG_EOM);
  3488		return check_condition_result;
  3489	}
  3490	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v1b 4/7] scsi: scsi_debug: Add read support and update locate for tapes
  2025-02-10 19:12 ` [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes Kai Mäkisara
  2025-02-11 15:50   ` kernel test robot
@ 2025-02-11 21:26   ` Kai Mäkisara
  1 sibling, 0 replies; 15+ messages in thread
From: Kai Mäkisara @ 2025-02-11 21:26 UTC (permalink / raw)
  To: linux-scsi, dgilbert
  Cc: martin.petersen, James.Bottomley, jmeneghi, Kai Mäkisara

Support for the READ (6) and SPACE (6) commands for tapes based on the
previous write patch is added. The LOCATE (10) command is updated to use
the written data.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
---

v1 -> v1b:
- initialize i to zero in resp_space to fix the bug found by
  The Kernel Test Robot

 drivers/scsi/scsi_debug.c | 240 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 235 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 69cae4c1712a..29a9aea30d22 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -532,7 +532,8 @@ enum sdeb_opcode_index {
 	SDEB_I_READ_BLOCK_LIMITS = 33,
 	SDEB_I_LOCATE = 34,
 	SDEB_I_WRITE_FILEMARKS = 35,
-	SDEB_I_LAST_ELEM_P1 = 36,	/* keep this last (previous + 1) */
+	SDEB_I_SPACE = 36,
+	SDEB_I_LAST_ELEM_P1 = 37,	/* keep this last (previous + 1) */
 };
 
 
@@ -541,7 +542,7 @@ static const unsigned char opcode_ind_arr[256] = {
 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
 	    0, SDEB_I_READ_BLOCK_LIMITS, 0, 0,
 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
-	SDEB_I_WRITE_FILEMARKS, 0, SDEB_I_INQUIRY, 0, 0,
+	SDEB_I_WRITE_FILEMARKS, SDEB_I_SPACE, SDEB_I_INQUIRY, 0, 0,
 	    SDEB_I_MODE_SELECT, SDEB_I_RESERVE, SDEB_I_RELEASE,
 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
 	    SDEB_I_ALLOW_REMOVAL, 0,
@@ -625,6 +626,7 @@ 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 resp_write_filemarks(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_space(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_rewind(struct scsi_cmnd *, struct sdebug_dev_info *);
 
 static int sdebug_do_add_host(bool mk_new_store);
@@ -872,10 +874,12 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
 	{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,
+	    {10,  0x07, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xc7, 0, 0,
 	     0, 0, 0, 0} },
 	{0, 0x10, 0, F_D_IN, resp_write_filemarks, NULL,    /* WRITE FILEMARKS (6) */
 	    {6,  0x01, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+	{0, 0x11, 0, F_D_IN, resp_space, NULL,    /* SPACE (6) */
+	    {6,  0x07, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 
 /* sentinel */
 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
@@ -3309,6 +3313,9 @@ static int resp_locate(struct scsi_cmnd *scp,
 		struct sdebug_dev_info *devip)
 {
 	unsigned char *cmd = scp->cmnd;
+	unsigned int i, pos;
+	struct tape_block *blp;
+	int partition;
 
 	if ((cmd[1] & 0x02) != 0) {
 		if (cmd[8] >= devip->tape_nbr_partitions) {
@@ -3317,8 +3324,19 @@ static int resp_locate(struct scsi_cmnd *scp,
 		}
 		devip->tape_partition = cmd[8];
 	}
-	devip->tape_location[devip->tape_partition] =
-		get_unaligned_be32(cmd + 3);
+	pos = get_unaligned_be32(cmd + 3);
+	partition = devip->tape_partition;
+
+	for (i = 0, blp = devip->tape_blocks[partition];
+	     i < pos && i < devip->tape_eop[partition]; i++, blp++)
+		if (IS_TAPE_BLOCK_EOD(blp->fl_size))
+			break;
+	if (i < pos) {
+		devip->tape_location[partition] = i;
+		mk_sense_buffer(scp, BLANK_CHECK, 0x05, 0);
+		return check_condition_result;
+	}
+	devip->tape_location[partition] = pos;
 
 	return 0;
 }
@@ -3353,6 +3371,123 @@ static int resp_write_filemarks(struct scsi_cmnd *scp,
 	return 0;
 }
 
+static int resp_space(struct scsi_cmnd *scp,
+		struct sdebug_dev_info *devip)
+{
+	unsigned char *cmd = scp->cmnd, code;
+	int i = 0, pos, count;
+	struct tape_block *blp;
+	int partition = devip->tape_partition;
+
+	count = get_unaligned_be24(cmd + 2);
+	if ((count & 0x800000) != 0) /* extend negative to 32-bit count */
+		count |= 0xff000000;
+	code = cmd[1] & 0x0f;
+
+	pos = devip->tape_location[partition];
+	if (code == 0) { /* blocks */
+		if (count < 0) {
+			count = (-count);
+			pos -= 1;
+			for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count;
+			     i++) {
+				if (pos < 0)
+					goto is_bop;
+				else if (IS_TAPE_BLOCK_FM(blp->fl_size))
+					goto is_fm;
+				if (i > 0) {
+					pos--;
+					blp--;
+				}
+			}
+		} else if (count > 0) {
+			for (i = 0, blp = devip->tape_blocks[partition] + pos; i < count;
+			     i++, pos++, blp++) {
+				if (IS_TAPE_BLOCK_EOD(blp->fl_size))
+					goto is_eod;
+				if (IS_TAPE_BLOCK_FM(blp->fl_size)) {
+					pos += 1;
+					goto is_fm;
+				}
+				if (pos >= devip->tape_eop[partition])
+					goto is_eop;
+			}
+		}
+	} else if (code == 1) { /* filemarks */
+		if (count < 0) {
+			count = (-count);
+			if (pos == 0)
+				goto is_bop;
+			else {
+				for (i = 0, blp = devip->tape_blocks[partition] + pos;
+				     i < count && pos >= 0; i++, pos--, blp--) {
+					for (pos--, blp-- ; !IS_TAPE_BLOCK_FM(blp->fl_size) &&
+						     pos >= 0; pos--, blp--)
+						; /* empty */
+					if (pos < 0)
+						goto is_bop;
+				}
+			}
+			pos += 1;
+		} else if (count > 0) {
+			for (i = 0, blp = devip->tape_blocks[partition] + pos;
+			     i < count; i++, pos++, blp++) {
+				for ( ; !IS_TAPE_BLOCK_FM(blp->fl_size) &&
+					      !IS_TAPE_BLOCK_EOD(blp->fl_size) &&
+					      pos < devip->tape_eop[partition];
+				      pos++, blp++)
+					; /* empty */
+				if (IS_TAPE_BLOCK_EOD(blp->fl_size))
+					goto is_eod;
+				if (pos >= devip->tape_eop[partition])
+					goto is_eop;
+			}
+		}
+	} else if (code == 3) { /* EOD */
+		for (blp = devip->tape_blocks[partition] + pos;
+		     !IS_TAPE_BLOCK_EOD(blp->fl_size) && pos < devip->tape_eop[partition];
+		     pos++, blp++)
+			; /* empty */
+		if (pos >= devip->tape_eop[partition])
+			goto is_eop;
+	} else {
+		/* sequential filemarks not supported */
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, -1);
+		return check_condition_result;
+	}
+	devip->tape_location[partition] = pos;
+	return 0;
+
+is_fm:
+	devip->tape_location[partition] = pos;
+	mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+			FILEMARK_DETECTED_ASCQ, count - i,
+			SENSE_FLAG_FILEMARK);
+	return check_condition_result;
+
+is_eod:
+	devip->tape_location[partition] = pos;
+	mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE,
+			EOD_DETECTED_ASCQ, count - i,
+			0);
+	return check_condition_result;
+
+is_bop:
+	devip->tape_location[partition] = 0;
+	mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+			BEGINNING_OF_P_M_DETECTED_ASCQ, count - i,
+			SENSE_FLAG_EOM);
+	devip->tape_location[partition] = 0;
+	return check_condition_result;
+
+is_eop:
+	devip->tape_location[partition] = devip->tape_eop[partition] - 1;
+	mk_sense_info_tape(scp, MEDIUM_ERROR, NO_ADDITIONAL_SENSE,
+			EOP_EOM_DETECTED_ASCQ, (unsigned int)i,
+			SENSE_FLAG_EOM);
+	return check_condition_result;
+}
+
 static int resp_rewind(struct scsi_cmnd *scp,
 		struct sdebug_dev_info *devip)
 {
@@ -4121,6 +4256,98 @@ static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
 	return ret;
 }
 
+static int resp_read_tape(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+	u32 i, num, transfer, size;
+	u8 *cmd = scp->cmnd;
+	struct scsi_data_buffer *sdb = &scp->sdb;
+	int partition = devip->tape_partition;
+	u32 pos = devip->tape_location[partition];
+	struct tape_block *blp;
+	bool fixed, sili;
+
+	if (cmd[0] != READ_6) { /* Only Read(6) supported */
+		mk_sense_invalid_opcode(scp);
+		return illegal_condition_result;
+	}
+	fixed = (cmd[1] & 0x1) != 0;
+	sili = (cmd[1] & 0x2) != 0;
+	if (fixed && sili) {
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
+		return check_condition_result;
+	}
+
+	transfer = get_unaligned_be24(cmd + 2);
+	if (fixed) {
+		num = transfer;
+		size = devip->tape_blksize;
+	} else {
+		if (transfer < TAPE_MIN_BLKSIZE ||
+			transfer > TAPE_MAX_BLKSIZE) {
+			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
+			return check_condition_result;
+		}
+		num = 1;
+		size = transfer;
+	}
+
+	for (i = 0, blp = devip->tape_blocks[partition] + pos;
+	     i < num && pos < devip->tape_eop[partition];
+	     i++, pos++, blp++) {
+		devip->tape_location[partition] = pos + 1;
+		if (IS_TAPE_BLOCK_FM(blp->fl_size)) {
+			mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+					FILEMARK_DETECTED_ASCQ, fixed ? num - i : size,
+					SENSE_FLAG_FILEMARK);
+			scsi_set_resid(scp, (num - i) * size);
+			return check_condition_result;
+		}
+		/* Assume no REW */
+		if (IS_TAPE_BLOCK_EOD(blp->fl_size)) {
+			mk_sense_info_tape(scp, BLANK_CHECK, NO_ADDITIONAL_SENSE,
+					EOD_DETECTED_ASCQ, fixed ? num - i : size,
+					0);
+			devip->tape_location[partition] = pos;
+			scsi_set_resid(scp, (num - i) * size);
+			return check_condition_result;
+		}
+		sg_zero_buffer(sdb->table.sgl, sdb->table.nents,
+			size, i * size);
+		sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
+			&(blp->data), 4, i * size, false);
+		if (fixed) {
+			if (blp->fl_size != devip->tape_blksize) {
+				scsi_set_resid(scp, (num - i) * size);
+				mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+						0, num - i,
+						SENSE_FLAG_ILI);
+				return check_condition_result;
+			}
+		} else {
+			if (blp->fl_size != size) {
+				if (blp->fl_size < size)
+					scsi_set_resid(scp, size - blp->fl_size);
+				if (!sili) {
+					mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+							0, size - blp->fl_size,
+							SENSE_FLAG_ILI);
+					return check_condition_result;
+				}
+			}
+		}
+	}
+	if (pos >= devip->tape_eop[partition]) {
+		mk_sense_info_tape(scp, NO_SENSE, NO_ADDITIONAL_SENSE,
+				EOP_EOM_DETECTED_ASCQ, fixed ? num - i : size,
+				SENSE_FLAG_EOM);
+		devip->tape_location[partition] = pos - 1;
+		return check_condition_result;
+	}
+	devip->tape_location[partition] = pos;
+
+	return 0;
+}
+
 static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
 	bool check_prot;
@@ -4132,6 +4359,9 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	u8 *cmd = scp->cmnd;
 	bool meta_data_locked = false;
 
+	if (sdebug_ptype == TYPE_TAPE)
+		return resp_read_tape(scp, devip);
+
 	switch (cmd[0]) {
 	case READ_16:
 		ei_lba = 0;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v1b 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD for tapes
  2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
@ 2025-02-13  3:11     ` Martin K. Petersen
  0 siblings, 0 replies; 15+ messages in thread
From: Martin K. Petersen @ 2025-02-13  3:11 UTC (permalink / raw)
  To: Kai Mäkisara
  Cc: linux-scsi, dgilbert, martin.petersen, James.Bottomley, jmeneghi


Hi Kai!

> 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)

Please don't do the "v1b" thing, b4 and patchwork both get confused. I
had to manually stitch your previous series together from several
bundles and it took a long time.

Just repost the entire series as v2 with the necessary changes in place.

Thanks!

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2025-02-13  3:12 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-10 19:12 [PATCH v1 0/7] scsi: scsi_debug: Add more tape support Kai Mäkisara
2025-02-10 19:12 ` [PATCH v1 1/7] scsi: scsi_debug: First fixes for tapes Kai Mäkisara
2025-02-10 19:12 ` [PATCH v1 2/7] scsi: scsi_debug: Add READ BLOCK LIMITS and modify LOAD " Kai Mäkisara
2025-02-11 10:41   ` kernel test robot
2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
2025-02-13  3:11     ` Martin K. Petersen
2025-02-10 19:12 ` [PATCH v1 3/7] scsi: scsi_debug: Add write support with block lengths and 4 bytes of data Kai Mäkisara
2025-02-11 13:08   ` kernel test robot
2025-02-11 14:11   ` [PATCH v1b " Kai Mäkisara
2025-02-10 19:12 ` [PATCH v1 4/7] scsi: scsi_debug: Add read support and update locate for tapes Kai Mäkisara
2025-02-11 15:50   ` kernel test robot
2025-02-11 21:26   ` [PATCH v1b " Kai Mäkisara
2025-02-10 19:12 ` [PATCH v1 5/7] scsi: scsi_debug: Add compression mode page " Kai Mäkisara
2025-02-10 19:12 ` [PATCH v1 6/7] scsi: scsi_debug: Reset tape setting at device reset Kai Mäkisara
2025-02-10 19:12 ` [PATCH v1 7/7] scsi: scsi_debug: Add support for partitioning the tape Kai Mäkisara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox