* [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