xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 9c230382)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
51da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
61da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
71da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
81da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91da177e4SLinus Torvalds  *
10500d0d24SDouglas Gilbert  * Copyright (C) 2001 - 2021 Douglas Gilbert
111da177e4SLinus Torvalds  *
1230f67481SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
194a5fc1c6SDamien Le Moal #include <linux/align.h>
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/fs.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/proc_fs.h>
291da177e4SLinus Torvalds #include <linux/vmalloc.h>
301da177e4SLinus Torvalds #include <linux/moduleparam.h>
31852e034dSJens Axboe #include <linux/scatterlist.h>
321da177e4SLinus Torvalds #include <linux/blkdev.h>
33c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
34cbf67842SDouglas Gilbert #include <linux/spinlock.h>
35cbf67842SDouglas Gilbert #include <linux/interrupt.h>
36cbf67842SDouglas Gilbert #include <linux/atomic.h>
37cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3809ba24c1SDouglas Gilbert #include <linux/uuid.h>
396ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
401442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
410c4bc91dSDouglas Gilbert #include <linux/random.h>
4287c715dcSDouglas Gilbert #include <linux/xarray.h>
43ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
44c6a44287SMartin K. Petersen 
45c6a44287SMartin K. Petersen #include <net/checksum.h>
469ff26eefSFUJITA Tomonori 
4744d92694SMartin K. Petersen #include <asm/unaligned.h>
4844d92694SMartin K. Petersen 
499ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
521da177e4SLinus Torvalds #include <scsi/scsi_host.h>
531da177e4SLinus Torvalds #include <scsi/scsicam.h>
54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
62500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191"	/* format to fit INQUIRY revision field */
63500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520";
64cbf67842SDouglas Gilbert 
65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
661da177e4SLinus Torvalds 
676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
779447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
85500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
1014a5fc1c6SDamien Le Moal #define ATTEMPT_ACCESS_GAP 0x9
102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1031da177e4SLinus Torvalds 
1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1066f3cbf55SDouglas Gilbert 
1071da177e4SLinus Torvalds /* Default values for driver parameters */
1081da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1091da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1101da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1121da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1131da177e4SLinus Torvalds  */
1145b94e232SMartin K. Petersen #define DEF_ATO 1
1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
116c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1205b94e232SMartin K. Petersen #define DEF_DIF 0
1215b94e232SMartin K. Petersen #define DEF_DIX 0
12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1235b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1241da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1255b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1265b94e232SMartin K. Petersen #define DEF_GUARD 0
127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1285b94e232SMartin K. Petersen #define DEF_LBPU 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS 0
1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0
131be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
133cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1351da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1361da177e4SLinus Torvalds #define DEF_OPTS   0
13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
140b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false
142d986788bSMartin Pitt #define DEF_REMOVABLE false
143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
152c2248fc9SDouglas Gilbert #define DEF_STRICT 0
153c4837394SDouglas Gilbert #define DEF_STATISTICS false
154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1581da177e4SLinus Torvalds 
159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
163f0d1cf93SDouglas Gilbert 
164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
165b01f6f83SDouglas Gilbert 
166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
1777d5a129bSDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400	/* ignore */
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
179773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
180773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
181773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1827ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1837382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
185773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
186773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
187773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
188773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1897ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1907382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1917382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1923a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1933a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1941da177e4SLinus Torvalds 
195cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
196cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
197cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
198cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
200500d0d24SDouglas Gilbert #define SDEBUG_UA_POOCCUR 1	/* Power on occurred */
201500d0d24SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 2
202500d0d24SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 3
203500d0d24SDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 4
204500d0d24SDouglas Gilbert #define SDEBUG_UA_LUNS_CHANGED 5
205500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED 6	/* simulate firmware change */
206500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7
207500d0d24SDouglas Gilbert #define SDEBUG_NUM_UAS 8
208cbf67842SDouglas Gilbert 
209773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2101da177e4SLinus Torvalds  * sector on read commands: */
2111da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2131da177e4SLinus Torvalds 
214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
216c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
220c4837394SDouglas Gilbert  */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
223fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN  SDEBUG_CANQUEUE
224cbf67842SDouglas Gilbert 
225b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
226b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
227b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
228fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
229fd32119bSDouglas Gilbert #define F_D_UNKN		8
230b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
231b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
232b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
233b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
234b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
235b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
236b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
237b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
238b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
239b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
240fd32119bSDouglas Gilbert 
241b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
242fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24346f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
244fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2454f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
246fd32119bSDouglas Gilbert 
247fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
248fd32119bSDouglas Gilbert 
249b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
250fd32119bSDouglas Gilbert 
25187c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25287c715dcSDouglas Gilbert 
25364e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25464e14eceSDamien Le Moal enum sdebug_z_type {
25535dbe2b9SDamien Le Moal 	ZBC_ZTYPE_CNV	= 0x1,
25635dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWR	= 0x2,
25735dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWP	= 0x3,
2584a5fc1c6SDamien Le Moal 	/* ZBC_ZTYPE_SOBR = 0x4, */
2594a5fc1c6SDamien Le Moal 	ZBC_ZTYPE_GAP	= 0x5,
26064e14eceSDamien Le Moal };
26164e14eceSDamien Le Moal 
262f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
263f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
264f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
265f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
266f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
267f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
268f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
269f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
270f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
271f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
272f0d1cf93SDouglas Gilbert };
273f0d1cf93SDouglas Gilbert 
274f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
27564e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
276f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
27764e14eceSDamien Le Moal 	bool z_non_seq_resource;
278f0d1cf93SDouglas Gilbert 	unsigned int z_size;
279f0d1cf93SDouglas Gilbert 	sector_t z_start;
280f0d1cf93SDouglas Gilbert 	sector_t z_wp;
281f0d1cf93SDouglas Gilbert };
282fd32119bSDouglas Gilbert 
283fd32119bSDouglas Gilbert struct sdebug_dev_info {
284fd32119bSDouglas Gilbert 	struct list_head dev_list;
285fd32119bSDouglas Gilbert 	unsigned int channel;
286fd32119bSDouglas Gilbert 	unsigned int target;
287fd32119bSDouglas Gilbert 	u64 lun;
288bf476433SChristoph Hellwig 	uuid_t lu_name;
289fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
290fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
291fd32119bSDouglas Gilbert 	atomic_t num_in_q;
292fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
293fd32119bSDouglas Gilbert 	bool used;
294f0d1cf93SDouglas Gilbert 
295f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
29664e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
2974a5fc1c6SDamien Le Moal 	unsigned int zcap;
298f0d1cf93SDouglas Gilbert 	unsigned int zsize;
299f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
300f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
301aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
3024a5fc1c6SDamien Le Moal 	unsigned int nr_seq_zones;
303f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
304f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
305f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
306f0d1cf93SDouglas Gilbert 	unsigned int max_open;
307fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
308f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
309fd32119bSDouglas Gilbert };
310fd32119bSDouglas Gilbert 
311fd32119bSDouglas Gilbert struct sdebug_host_info {
312fd32119bSDouglas Gilbert 	struct list_head host_list;
31387c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
314fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
315fd32119bSDouglas Gilbert 	struct device dev;
316fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
317fd32119bSDouglas Gilbert };
318fd32119bSDouglas Gilbert 
31987c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
32087c715dcSDouglas Gilbert struct sdeb_store_info {
32187c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
32287c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
32387c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
32487c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32587c715dcSDouglas Gilbert };
32687c715dcSDouglas Gilbert 
327785d6b7cSJohn Garry #define dev_to_sdebug_host(d)	\
328fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
329fd32119bSDouglas Gilbert 
330785d6b7cSJohn Garry #define shost_to_sdebug_host(shost)	\
331785d6b7cSJohn Garry 	dev_to_sdebug_host(shost->dma_dev)
332785d6b7cSJohn Garry 
33310bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3344a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
33510bde980SDouglas Gilbert 
336fd32119bSDouglas Gilbert struct sdebug_defer {
337fd32119bSDouglas Gilbert 	struct hrtimer hrt;
338fd32119bSDouglas Gilbert 	struct execute_work ew;
3394a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
340c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
341c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
342c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
343c4837394SDouglas Gilbert 	int issuing_cpu;
34410bde980SDouglas Gilbert 	bool init_hrt;
34510bde980SDouglas Gilbert 	bool init_wq;
3464a0c6f43SDouglas Gilbert 	bool init_poll;
3477382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34810bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
349fd32119bSDouglas Gilbert };
350fd32119bSDouglas Gilbert 
351fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
352c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
353c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
354c4837394SDouglas Gilbert 	 */
355fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
356fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
357fd32119bSDouglas Gilbert };
358fd32119bSDouglas Gilbert 
359c4837394SDouglas Gilbert struct sdebug_queue {
360c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
361c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
362c4837394SDouglas Gilbert 	spinlock_t qc_lock;
363c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
364fd32119bSDouglas Gilbert };
365fd32119bSDouglas Gilbert 
366c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
367c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
368c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
369c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3703a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3714a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
372c4837394SDouglas Gilbert 
373fd32119bSDouglas Gilbert struct opcode_info_t {
374b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
375b01f6f83SDouglas Gilbert 				/* for terminating element */
376fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
377fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
378fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
379fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
380fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3819a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3829a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
383fd32119bSDouglas Gilbert };
384fd32119bSDouglas Gilbert 
385fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
386c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
387c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
388c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
389c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
390c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
391c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
392c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
393c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
394c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
395c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
396c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
397c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
398c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39946f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
40046f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
401c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
402c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
403c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
404481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
405c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
406c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
407c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
408c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
409c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
410c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
411c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
412c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
413c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
414c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
415c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
416ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
417f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
418f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
419f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
420c2248fc9SDouglas Gilbert };
421c2248fc9SDouglas Gilbert 
422c4837394SDouglas Gilbert 
423c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
424c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
425c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
426c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
427c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
428c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
429c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
430c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
431c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
432c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
433c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
434c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
435ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
436c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
437c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
438c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
439c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
440c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
441c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
442c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
443fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
444c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
445c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
446c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
447c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
448c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
449c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
450c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
451f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
452f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
45346f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
454c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
455c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
456c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
45746f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
45846f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
459c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
460c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
461c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
462c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
463c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
464c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
465c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
466c2248fc9SDouglas Gilbert };
467c2248fc9SDouglas Gilbert 
46880c49563SDouglas Gilbert /*
46980c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
47080c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
47180c49563SDouglas Gilbert  * command completion, they can mask their return value with
47280c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
47380c49563SDouglas Gilbert  */
47480c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
47580c49563SDouglas Gilbert 
476c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
485481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
488c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
489c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
490c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
49138d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
49238d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
493c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
494c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
495c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
49638d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
497acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
49880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
499ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
500f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
501f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
502f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
503f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
504f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
505c2248fc9SDouglas Gilbert 
50687c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
50787c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
50887c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50987c715dcSDouglas Gilbert static int sdebug_add_store(void);
51087c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
51187c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
51287c715dcSDouglas Gilbert 
51346f64e70SDouglas Gilbert /*
51446f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
51546f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
51646f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
51746f64e70SDouglas Gilbert  */
51846f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
519c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
520c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
521c2248fc9SDouglas Gilbert };
522c2248fc9SDouglas Gilbert 
52346f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
524c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
525c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
526c2248fc9SDouglas Gilbert };
527c2248fc9SDouglas Gilbert 
52846f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52946f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
530b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
531c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
53246f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
533c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53446f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
535b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
536c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
537c2248fc9SDouglas Gilbert };
538c2248fc9SDouglas Gilbert 
53946f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
54046f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
54146f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
54246f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
54346f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
54446f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
54546f64e70SDouglas Gilbert 		   0, 0, 0} },
54646f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
54746f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54846f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
549c2248fc9SDouglas Gilbert };
550c2248fc9SDouglas Gilbert 
551c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
552c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
553c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
554c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
555c3e2fe92SDouglas Gilbert };
556c3e2fe92SDouglas Gilbert 
55746f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
558c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
559c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56046f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
561c2248fc9SDouglas Gilbert };
562c2248fc9SDouglas Gilbert 
56346f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
56446f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
565b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
566c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
567481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
568481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
569481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
570c2248fc9SDouglas Gilbert };
571c2248fc9SDouglas Gilbert 
57246f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
57338d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
574c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
57546f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
57638d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
577c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
57846f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
579c2248fc9SDouglas Gilbert };
580c2248fc9SDouglas Gilbert 
58146f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
58246f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
583c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58446f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
585c2248fc9SDouglas Gilbert };
586c2248fc9SDouglas Gilbert 
58746f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
588c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
589c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
590c2248fc9SDouglas Gilbert };
591c2248fc9SDouglas Gilbert 
59246f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
593c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
594c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
595c2248fc9SDouglas Gilbert };
596c2248fc9SDouglas Gilbert 
59780c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5984f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59980c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60080c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
60180c49563SDouglas Gilbert };
60280c49563SDouglas Gilbert 
603ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
604b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
605ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
607ed9f3e25SDouglas Gilbert };
608ed9f3e25SDouglas Gilbert 
609f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
610b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
611f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
613b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
614f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
615f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
616b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
617f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
618f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
619f0d1cf93SDouglas Gilbert };
620f0d1cf93SDouglas Gilbert 
621f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
622b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
623f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
624f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
625f0d1cf93SDouglas Gilbert };
626f0d1cf93SDouglas Gilbert 
627c2248fc9SDouglas Gilbert 
628c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
629c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
630c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
631ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
632c2248fc9SDouglas Gilbert /* 0 */
63346f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
634c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63546f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
636c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
637c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
638c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63946f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
640c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
641c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
642c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
643c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64446f64e70SDouglas Gilbert /* 5 */
64546f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
64646f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
64746f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64846f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64946f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
65046f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65146f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
652c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
653c2248fc9SDouglas Gilbert 	     0, 0, 0} },
65446f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
655c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
656c2248fc9SDouglas Gilbert 	     0, 0} },
65746f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
65846f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65946f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
660c2248fc9SDouglas Gilbert /* 10 */
66146f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
66246f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
66346f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66480c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6654f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
666c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
66746f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
66846f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66946f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67046f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
671481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
672481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
673481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
67446f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
67546f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
67646f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
67746f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
67846f64e70SDouglas Gilbert /* 15 */
679c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
680c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
681c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
682c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
683c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
684c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
68546f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
68646f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
68746f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
68846f64e70SDouglas Gilbert 	     0xff, 0xff} },
68946f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
69046f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
691c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
692c2248fc9SDouglas Gilbert 	     0} },
69346f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
69446f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
695c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
696c2248fc9SDouglas Gilbert 	     0} },
697c2248fc9SDouglas Gilbert /* 20 */
698f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
699f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
700c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
701c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
702c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
703c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
704c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
705c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
70646f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
707b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
70846f64e70SDouglas Gilbert /* 25 */
709acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
710acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
711acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
71246f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
71346f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
71446f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
71546f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7164f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
71780c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
718b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71980c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
72046f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
721c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
722b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
723b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
724ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
725ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
726ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
727c2248fc9SDouglas Gilbert 
728ed9f3e25SDouglas Gilbert /* 30 */
729b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
730f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
731f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
732f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
733b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
734f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
735f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
736f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
737f0d1cf93SDouglas Gilbert /* sentinel */
738c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
739c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
740c2248fc9SDouglas Gilbert };
741c2248fc9SDouglas Gilbert 
742f19fe8f3SBart Van Assche static int sdebug_num_hosts;
74387c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
744773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7459b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
746c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7479267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
748773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
749773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
750773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
751773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
752773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
753773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
754c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
755773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
756773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
757c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
758d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
759d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
760cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
761c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
762773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
763773642d9SDouglas Gilbert static int sdebug_no_uld;
764773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
765773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
766773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
767773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
768773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76986e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
770b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
771773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
772773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
773fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
774773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
775773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
776773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
777773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
778773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
779773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
780773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
781773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
782773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
783773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
784773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
78509ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7860c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
78787c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
788773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
789773642d9SDouglas Gilbert static bool sdebug_clustering;
790773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
791773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
792817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
7937109f370SDouglas Gilbert static bool sdebug_no_rwlock;
794773642d9SDouglas Gilbert static bool sdebug_verbose;
795f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7964f2c8bf6SDouglas Gilbert static bool write_since_sync;
797c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7989447b6ceSMartin K. Petersen static bool sdebug_wp;
7999267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
8009267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
8019267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
8021da177e4SLinus Torvalds 
803ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
804ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
805ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
806ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
807ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
808ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
809ad0c7775SDouglas Gilbert 
810c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8111da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8141da177e4SLinus Torvalds    may still need them */
8151da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8161da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8171da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8201da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8211da177e4SLinus Torvalds 
82287c715dcSDouglas Gilbert static struct xarray per_store_arr;
82387c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
82487c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
82587c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
82687c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8271da177e4SLinus Torvalds 
82844d92694SMartin K. Petersen static unsigned long map_size;
829cbf67842SDouglas Gilbert static int num_aborts;
830cbf67842SDouglas Gilbert static int num_dev_resets;
831cbf67842SDouglas Gilbert static int num_target_resets;
832cbf67842SDouglas Gilbert static int num_bus_resets;
833cbf67842SDouglas Gilbert static int num_host_resets;
834c6a44287SMartin K. Petersen static int dix_writes;
835c6a44287SMartin K. Petersen static int dix_reads;
836c6a44287SMartin K. Petersen static int dif_errors;
8371da177e4SLinus Torvalds 
838f0d1cf93SDouglas Gilbert /* ZBC global data */
83964e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
8404a5fc1c6SDamien Le Moal static int sdeb_zbc_zone_cap_mb;
84198e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
842380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
843aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
844f0d1cf93SDouglas Gilbert 
845c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
846c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
847c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
848fd32119bSDouglas Gilbert 
8491da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
85087c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
85187c715dcSDouglas Gilbert 
85287c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8531da177e4SLinus Torvalds 
854cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
855cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8601da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8611da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8621da177e4SLinus Torvalds };
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds static const int check_condition_result =
865464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8661da177e4SLinus Torvalds 
867c6a44287SMartin K. Petersen static const int illegal_condition_result =
868464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
869c6a44287SMartin K. Petersen 
870cbf67842SDouglas Gilbert static const int device_qfull_result =
8717d5a129bSDouglas Gilbert 	(DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
872cbf67842SDouglas Gilbert 
873ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
874ed9f3e25SDouglas Gilbert 
875fd32119bSDouglas Gilbert 
876760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
877760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
878760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
879760f3b03SDouglas Gilbert  */
880760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
881fd32119bSDouglas Gilbert {
882fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
883fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
884fd32119bSDouglas Gilbert }
885c65b1445SDouglas Gilbert 
88687c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
88787c715dcSDouglas Gilbert 			    unsigned long long lba)
88814faa944SAkinobu Mita {
88987c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
89014faa944SAkinobu Mita 
89187c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
89287c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
89387c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
89487c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
89587c715dcSDouglas Gilbert 	}
89687c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
89714faa944SAkinobu Mita }
89814faa944SAkinobu Mita 
89987c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
90087c715dcSDouglas Gilbert 				      sector_t sector)
90114faa944SAkinobu Mita {
90249413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
90314faa944SAkinobu Mita 
90487c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
90514faa944SAkinobu Mita }
90614faa944SAkinobu Mita 
9078dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9088dea0d02SFUJITA Tomonori {
9098dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9108dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9118dea0d02SFUJITA Tomonori 
9128dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9138dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9148dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9158dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
916773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
917773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9188dea0d02SFUJITA Tomonori 		else
919773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
920773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
921f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9228dea0d02SFUJITA Tomonori 	}
9238dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9248dea0d02SFUJITA Tomonori }
9258dea0d02SFUJITA Tomonori 
92622017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
92722017ed2SDouglas Gilbert 
92822017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
929fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
930fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
93122017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
93222017ed2SDouglas Gilbert {
93322017ed2SDouglas Gilbert 	unsigned char *sbuff;
93422017ed2SDouglas Gilbert 	u8 sks[4];
93522017ed2SDouglas Gilbert 	int sl, asc;
93622017ed2SDouglas Gilbert 
93722017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
93822017ed2SDouglas Gilbert 	if (!sbuff) {
93922017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
94022017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
94122017ed2SDouglas Gilbert 		return;
94222017ed2SDouglas Gilbert 	}
94322017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
94422017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
945f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
94622017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
94722017ed2SDouglas Gilbert 	sks[0] = 0x80;
94822017ed2SDouglas Gilbert 	if (c_d)
94922017ed2SDouglas Gilbert 		sks[0] |= 0x40;
95022017ed2SDouglas Gilbert 	if (in_bit >= 0) {
95122017ed2SDouglas Gilbert 		sks[0] |= 0x8;
95222017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
95322017ed2SDouglas Gilbert 	}
95422017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
955773642d9SDouglas Gilbert 	if (sdebug_dsense) {
95622017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
95722017ed2SDouglas Gilbert 		sbuff[7] = sl;
95822017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
95922017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
96022017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
96122017ed2SDouglas Gilbert 	} else
96222017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
963773642d9SDouglas Gilbert 	if (sdebug_verbose)
96422017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
96522017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
96622017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
96722017ed2SDouglas Gilbert }
96822017ed2SDouglas Gilbert 
969cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9708dea0d02SFUJITA Tomonori {
971f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
972cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
973cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
974cbf67842SDouglas Gilbert 		return;
975cbf67842SDouglas Gilbert 	}
976f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9778dea0d02SFUJITA Tomonori 
978f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9798dea0d02SFUJITA Tomonori 
980773642d9SDouglas Gilbert 	if (sdebug_verbose)
981cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
982cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
983cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9848dea0d02SFUJITA Tomonori }
9851da177e4SLinus Torvalds 
986fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
98722017ed2SDouglas Gilbert {
98822017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98922017ed2SDouglas Gilbert }
99022017ed2SDouglas Gilbert 
9916f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9926f4e626fSNathan Chancellor 			    void __user *arg)
9931da177e4SLinus Torvalds {
994773642d9SDouglas Gilbert 	if (sdebug_verbose) {
995cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
996cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
997cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
998cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
999cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
1000cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
1001cbf67842SDouglas Gilbert 				    __func__);
1002cbf67842SDouglas Gilbert 		else
1003cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
1004cbf67842SDouglas Gilbert 				    __func__, cmd);
10051da177e4SLinus Torvalds 	}
10061da177e4SLinus Torvalds 	return -EINVAL;
10071da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10081da177e4SLinus Torvalds }
10091da177e4SLinus Torvalds 
10109b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10119b760fd8SDouglas Gilbert {
10129b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10139b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10149b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10159b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10179b760fd8SDouglas Gilbert 		break;
10189b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10199b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10209b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10229b760fd8SDouglas Gilbert 		break;
10239b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10249b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10259b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10279b760fd8SDouglas Gilbert 		break;
10289b760fd8SDouglas Gilbert 	case 16:
10299b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10309b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10329b760fd8SDouglas Gilbert 		break;
10339b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10349b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10359b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10369b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10379b760fd8SDouglas Gilbert 		break;
10389b760fd8SDouglas Gilbert 	default:
10399b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10409b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10419b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10429b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10439b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10449b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10459b760fd8SDouglas Gilbert 		break;
10469b760fd8SDouglas Gilbert 	}
10479b760fd8SDouglas Gilbert }
10489b760fd8SDouglas Gilbert 
10499b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10509b760fd8SDouglas Gilbert {
10519b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10529b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10539b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10549b760fd8SDouglas Gilbert 
10559b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10569b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10579b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10589b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10599b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10609b760fd8SDouglas Gilbert 		}
10619b760fd8SDouglas Gilbert 	}
10629b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10639b760fd8SDouglas Gilbert }
10649b760fd8SDouglas Gilbert 
106519c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
106619c8ead7SEwan D. Milne {
106719c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106819c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106919c8ead7SEwan D. Milne 
107019c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
107119c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
107219c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
107319c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
107419c8ead7SEwan D. Milne 			    (devip->target == dp->target))
107519c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
107619c8ead7SEwan D. Milne 		}
107719c8ead7SEwan D. Milne 	}
107819c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107919c8ead7SEwan D. Milne }
108019c8ead7SEwan D. Milne 
1081f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10821da177e4SLinus Torvalds {
1083cbf67842SDouglas Gilbert 	int k;
1084cbf67842SDouglas Gilbert 
1085cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1086cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1087cbf67842SDouglas Gilbert 		const char *cp = NULL;
1088cbf67842SDouglas Gilbert 
1089cbf67842SDouglas Gilbert 		switch (k) {
1090cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1091f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1092f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1093773642d9SDouglas Gilbert 			if (sdebug_verbose)
1094cbf67842SDouglas Gilbert 				cp = "power on reset";
1095cbf67842SDouglas Gilbert 			break;
1096500d0d24SDouglas Gilbert 		case SDEBUG_UA_POOCCUR:
1097500d0d24SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1098500d0d24SDouglas Gilbert 					POWER_ON_OCCURRED_ASCQ);
1099500d0d24SDouglas Gilbert 			if (sdebug_verbose)
1100500d0d24SDouglas Gilbert 				cp = "power on occurred";
1101500d0d24SDouglas Gilbert 			break;
1102cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1103f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1104f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1105773642d9SDouglas Gilbert 			if (sdebug_verbose)
1106cbf67842SDouglas Gilbert 				cp = "bus reset";
1107cbf67842SDouglas Gilbert 			break;
1108cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1109f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1110f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1111773642d9SDouglas Gilbert 			if (sdebug_verbose)
1112cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1113cbf67842SDouglas Gilbert 			break;
11140d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1115f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1116f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1117773642d9SDouglas Gilbert 			if (sdebug_verbose)
11180d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1119f49accf1SEwan D. Milne 			break;
1120acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1121f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1122b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1123b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1124773642d9SDouglas Gilbert 			if (sdebug_verbose)
1125acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1126acafd0b9SEwan D. Milne 			break;
1127acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1128f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1129acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1130acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1131773642d9SDouglas Gilbert 			if (sdebug_verbose)
1132acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1133acafd0b9SEwan D. Milne 			break;
113419c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
113519c8ead7SEwan D. Milne 			/*
113619c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
113719c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
113819c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
113919c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1140773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
114119c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
114219c8ead7SEwan D. Milne 			 */
1143773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
114419c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1145f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
114619c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
114719c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1148773642d9SDouglas Gilbert 			if (sdebug_verbose)
114919c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
115019c8ead7SEwan D. Milne 			break;
1151cbf67842SDouglas Gilbert 		default:
1152773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1153773642d9SDouglas Gilbert 			if (sdebug_verbose)
1154cbf67842SDouglas Gilbert 				cp = "unknown";
1155cbf67842SDouglas Gilbert 			break;
1156cbf67842SDouglas Gilbert 		}
1157cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1158773642d9SDouglas Gilbert 		if (sdebug_verbose)
1159f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1160cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1161cbf67842SDouglas Gilbert 				   my_name, cp);
11621da177e4SLinus Torvalds 		return check_condition_result;
11631da177e4SLinus Torvalds 	}
11641da177e4SLinus Torvalds 	return 0;
11651da177e4SLinus Torvalds }
11661da177e4SLinus Torvalds 
1167fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11681da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11691da177e4SLinus Torvalds 				int arr_len)
11701da177e4SLinus Torvalds {
117121a61829SFUJITA Tomonori 	int act_len;
1172ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11731da177e4SLinus Torvalds 
1174072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11751da177e4SLinus Torvalds 		return 0;
1176ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1177773642d9SDouglas Gilbert 		return DID_ERROR << 16;
117821a61829SFUJITA Tomonori 
117921a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
118021a61829SFUJITA Tomonori 				      arr, arr_len);
118142d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
118221a61829SFUJITA Tomonori 
11831da177e4SLinus Torvalds 	return 0;
11841da177e4SLinus Torvalds }
11851da177e4SLinus Torvalds 
1186fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1187fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1188fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1189fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1190fb0cc8d1SDouglas Gilbert  */
1191fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1192fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1193fb0cc8d1SDouglas Gilbert {
11949237f04eSDamien Le Moal 	unsigned int act_len, n;
1195ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1196fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1197fb0cc8d1SDouglas Gilbert 
1198fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1199fb0cc8d1SDouglas Gilbert 		return 0;
1200ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1201fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1202fb0cc8d1SDouglas Gilbert 
1203fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1204fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1205fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
120642d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
120742d387beSBart Van Assche 		 scsi_get_resid(scp));
12089237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
120936e07d7eSGeorge Kennedy 	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
1210fb0cc8d1SDouglas Gilbert 	return 0;
1211fb0cc8d1SDouglas Gilbert }
1212fb0cc8d1SDouglas Gilbert 
1213fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1214fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1215fb0cc8d1SDouglas Gilbert  */
12161da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
121721a61829SFUJITA Tomonori 			       int arr_len)
12181da177e4SLinus Torvalds {
121921a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12201da177e4SLinus Torvalds 		return 0;
1221ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12221da177e4SLinus Torvalds 		return -1;
122321a61829SFUJITA Tomonori 
122421a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12251da177e4SLinus Torvalds }
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 
1228e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1229e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12309b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12311b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12321b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12331b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12341b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12351da177e4SLinus Torvalds 
1236cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1237760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12385a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
123909ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1240bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12411da177e4SLinus Torvalds {
1242c65b1445SDouglas Gilbert 	int num, port_a;
1243c65b1445SDouglas Gilbert 	char b[32];
12441da177e4SLinus Torvalds 
1245c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12461da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12471da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12481da177e4SLinus Torvalds 	arr[1] = 0x1;
12491da177e4SLinus Torvalds 	arr[2] = 0x0;
1250e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1251e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12521da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12531da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12541da177e4SLinus Torvalds 	arr[3] = num;
12551da177e4SLinus Torvalds 	num += 4;
1256c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
125709ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
125809ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
125909ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
126009ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
126109ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
126209ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
126309ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
126409ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
126509ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
126609ba24c1SDouglas Gilbert 			num += 16;
126709ba24c1SDouglas Gilbert 		} else {
12681b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1269c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1270c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1271c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1272c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12731b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1274773642d9SDouglas Gilbert 			num += 8;
127509ba24c1SDouglas Gilbert 		}
1276c65b1445SDouglas Gilbert 		/* Target relative port number */
1277c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1278c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1279c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1280c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1281c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1282c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1283c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1284c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1285c65b1445SDouglas Gilbert 	}
12861b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1287c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1288c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1289c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1290c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12911b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1292773642d9SDouglas Gilbert 	num += 8;
12931b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12945a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12955a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12965a09e398SHannes Reinecke 	arr[num++] = 0x0;
12975a09e398SHannes Reinecke 	arr[num++] = 0x4;
12985a09e398SHannes Reinecke 	arr[num++] = 0;
12995a09e398SHannes Reinecke 	arr[num++] = 0;
1300773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1301773642d9SDouglas Gilbert 	num += 2;
13021b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1303c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1304c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1305c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1306c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
13071b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1308773642d9SDouglas Gilbert 	num += 8;
1309c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1310c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1311c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1312c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1313c65b1445SDouglas Gilbert 	arr[num++] = 24;
13141b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1315c65b1445SDouglas Gilbert 	num += 12;
1316c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1317c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1318c65b1445SDouglas Gilbert 	num += 8;
1319c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1320c65b1445SDouglas Gilbert 	num += 4;
1321c65b1445SDouglas Gilbert 	return num;
1322c65b1445SDouglas Gilbert }
1323c65b1445SDouglas Gilbert 
1324c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1325c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1326c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1327c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1328c65b1445SDouglas Gilbert };
1329c65b1445SDouglas Gilbert 
1330cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1331760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1332c65b1445SDouglas Gilbert {
1333c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1334c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1335c65b1445SDouglas Gilbert }
1336c65b1445SDouglas Gilbert 
1337cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1338760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1339c65b1445SDouglas Gilbert {
1340c65b1445SDouglas Gilbert 	int num = 0;
1341c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1342c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1343c65b1445SDouglas Gilbert 	int plen, olen;
1344c65b1445SDouglas Gilbert 
1345c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1346c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1347c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1348c65b1445SDouglas Gilbert 	olen = strlen(na1);
1349c65b1445SDouglas Gilbert 	plen = olen + 1;
1350c65b1445SDouglas Gilbert 	if (plen % 4)
1351c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1352c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1353c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1354c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1355c65b1445SDouglas Gilbert 	num += plen;
1356c65b1445SDouglas Gilbert 
1357c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1358c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1359c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1360c65b1445SDouglas Gilbert 	olen = strlen(na2);
1361c65b1445SDouglas Gilbert 	plen = olen + 1;
1362c65b1445SDouglas Gilbert 	if (plen % 4)
1363c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1364c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1365c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1366c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1367c65b1445SDouglas Gilbert 	num += plen;
1368c65b1445SDouglas Gilbert 
1369c65b1445SDouglas Gilbert 	return num;
1370c65b1445SDouglas Gilbert }
1371c65b1445SDouglas Gilbert 
1372c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1373760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1374c65b1445SDouglas Gilbert {
1375c65b1445SDouglas Gilbert 	int num = 0;
1376c65b1445SDouglas Gilbert 	int port_a, port_b;
1377c65b1445SDouglas Gilbert 
1378c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1379c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1380c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1381c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1384c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1385c65b1445SDouglas Gilbert 	num += 6;
1386c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1387c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1388c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1389c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1390c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13931b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1394773642d9SDouglas Gilbert 	num += 8;
1395c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1396c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1397c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1398c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1399c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1400c65b1445SDouglas Gilbert 	num += 6;
1401c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1402c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1403c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1404c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1405c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1406c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1407c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
14081b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1409773642d9SDouglas Gilbert 	num += 8;
1410c65b1445SDouglas Gilbert 
1411c65b1445SDouglas Gilbert 	return num;
1412c65b1445SDouglas Gilbert }
1413c65b1445SDouglas Gilbert 
1414c65b1445SDouglas Gilbert 
1415c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1416c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1417c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1418c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1419c65b1445SDouglas Gilbert '1','2','3','4',
1420c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1421c65b1445SDouglas Gilbert 0xec,0,0,0,
1422c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1423c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1424c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1425c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1426c65b1445SDouglas Gilbert 0x53,0x41,
1427c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1428c65b1445SDouglas Gilbert 0x20,0x20,
1429c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1430c65b1445SDouglas Gilbert 0x10,0x80,
1431c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1432c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1433c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1435c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1436c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1438c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1441c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1442c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1443c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1444c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1445c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1446c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1448c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1449c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1450c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1451c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1452c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1453c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1454c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1455c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1456c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1457c65b1445SDouglas Gilbert };
1458c65b1445SDouglas Gilbert 
1459cbf67842SDouglas Gilbert /* ATA Information VPD page */
1460760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1461c65b1445SDouglas Gilbert {
1462c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1463c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1464c65b1445SDouglas Gilbert }
1465c65b1445SDouglas Gilbert 
1466c65b1445SDouglas Gilbert 
1467c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14681e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14691e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14701e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14711e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1472c65b1445SDouglas Gilbert };
1473c65b1445SDouglas Gilbert 
1474cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1475760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1476c65b1445SDouglas Gilbert {
1477ea61fca5SMartin K. Petersen 	unsigned int gran;
1478ea61fca5SMartin K. Petersen 
1479c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1480e308b3d1SMartin K. Petersen 
1481e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
148286e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
148386e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
148486e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
148586e6828aSLukas Herbolt 	else
1486773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1487773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1488e308b3d1SMartin K. Petersen 
1489e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1490773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1491773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
149244d92694SMartin K. Petersen 
1493e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1494773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1495e308b3d1SMartin K. Petersen 
1496773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1497e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1498773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1499e308b3d1SMartin K. Petersen 
1500e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1501773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
150244d92694SMartin K. Petersen 	}
150344d92694SMartin K. Petersen 
1504e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1505773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1506773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
150744d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
150844d92694SMartin K. Petersen 	}
150944d92694SMartin K. Petersen 
1510e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1511773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
15126014759cSMartin K. Petersen 
15135b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1514773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15155b94e232SMartin K. Petersen 
15165b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
15171da177e4SLinus Torvalds }
15181da177e4SLinus Torvalds 
15191e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
152064e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1521eac6e8e4SMatthew Wilcox {
1522eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1523eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15241e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15251e49f785SDouglas Gilbert 	arr[2] = 0;
15261e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
152764e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
152864e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1529eac6e8e4SMatthew Wilcox 
1530eac6e8e4SMatthew Wilcox 	return 0x3c;
1531eac6e8e4SMatthew Wilcox }
15321da177e4SLinus Torvalds 
1533760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1534760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15356014759cSMartin K. Petersen {
15363f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15376014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1538773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15396014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1540773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15416014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1542773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15435b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1544760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1545760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1546760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1547760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1548760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15493f0bc3b3SMartin K. Petersen 	return 0x4;
15506014759cSMartin K. Petersen }
15516014759cSMartin K. Petersen 
1552d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1553f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1554d36da305SDouglas Gilbert {
1555d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1556d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1557d36da305SDouglas Gilbert 	/*
1558d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1559d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1560f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1561f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1562d36da305SDouglas Gilbert 	 */
1563d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1564d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
156564e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1566f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1567f0d1cf93SDouglas Gilbert 	else
1568d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
15694a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize) {
15704a5fc1c6SDamien Le Moal 		arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET;
15714a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, &arr[20]);
15724a5fc1c6SDamien Le Moal 	} else {
15734a5fc1c6SDamien Le Moal 		arr[19] = 0;
15744a5fc1c6SDamien Le Moal 	}
1575d36da305SDouglas Gilbert 	return 0x3c;
1576d36da305SDouglas Gilbert }
1577d36da305SDouglas Gilbert 
15781da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1579c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15801da177e4SLinus Torvalds 
1581c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15821da177e4SLinus Torvalds {
15831da177e4SLinus Torvalds 	unsigned char pq_pdt;
15845a09e398SHannes Reinecke 	unsigned char *arr;
158501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
158636e07d7eSGeorge Kennedy 	u32 alloc_len, n;
158736e07d7eSGeorge Kennedy 	int ret;
1588d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15891da177e4SLinus Torvalds 
1590773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15916f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15926f3cbf55SDouglas Gilbert 	if (! arr)
15936f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1594760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
159564e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1596d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1597b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1598c2248fc9SDouglas Gilbert 	if (have_wlun)
1599b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1600b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1601b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1602c65b1445SDouglas Gilbert 	else
1603773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
16041da177e4SLinus Torvalds 	arr[0] = pq_pdt;
16051da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
160622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
16075a09e398SHannes Reinecke 		kfree(arr);
16081da177e4SLinus Torvalds 		return check_condition_result;
16091da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
161036e07d7eSGeorge Kennedy 		int lu_id_num, port_group_id, target_dev_id;
161136e07d7eSGeorge Kennedy 		u32 len;
1612c65b1445SDouglas Gilbert 		char lu_id_str[6];
1613c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
16141da177e4SLinus Torvalds 
16155a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16165a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1617b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
161823183910SDouglas Gilbert 			host_no = 0;
1619c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1620c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1621c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1622c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1623c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16241da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1625c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1626c65b1445SDouglas Gilbert 			n = 4;
1627c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1628c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1629c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1630c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1631c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1632c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1633c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1634c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1635d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1636c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1637760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1638760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1639d36da305SDouglas Gilbert 				if (is_disk)
1640d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
164164e14eceSDamien Le Moal 				if (is_zbc)
1642d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1643760f3b03SDouglas Gilbert 			}
1644c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16451da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1646c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16471da177e4SLinus Torvalds 			arr[3] = len;
1648c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16491da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1650c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1651760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16525a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
165309ba24c1SDouglas Gilbert 						lu_id_str, len,
165409ba24c1SDouglas Gilbert 						&devip->lu_name);
1655c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1656c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1657760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1658c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1659c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1660760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1661c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1662c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1663c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16648475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1665c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1666760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1667c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1668c6a44287SMartin K. Petersen 			else
1669c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1670c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1671c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1672c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1673c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1674c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1675c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1676c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1677c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1678c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1679c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1680760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1681d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1682c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1683760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1684773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1685d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1686c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1687760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1688d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1689eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
169064e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1691760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16926014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1693760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1694d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1695d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1696f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16971da177e4SLinus Torvalds 		} else {
169822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16995a09e398SHannes Reinecke 			kfree(arr);
17001da177e4SLinus Torvalds 			return check_condition_result;
17011da177e4SLinus Torvalds 		}
170236e07d7eSGeorge Kennedy 		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
17035a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
170436e07d7eSGeorge Kennedy 			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
17055a09e398SHannes Reinecke 		kfree(arr);
17065a09e398SHannes Reinecke 		return ret;
17071da177e4SLinus Torvalds 	}
17081da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1709773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1710773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
17111da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
17121da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1713f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1714b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
171570bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1716c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17171da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1718c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1719e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1720e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1721e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17229b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17239b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17241da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1725760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1726760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1727c65b1445SDouglas Gilbert 	n = 62;
1728760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1729760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1730760f3b03SDouglas Gilbert 		n += 2;
1731760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1732760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1733760f3b03SDouglas Gilbert 		n += 2;
1734d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1735d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1736d36da305SDouglas Gilbert 		n += 2;
17371da177e4SLinus Torvalds 	}
1738760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17395a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
174036e07d7eSGeorge Kennedy 			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17415a09e398SHannes Reinecke 	kfree(arr);
17425a09e398SHannes Reinecke 	return ret;
17431da177e4SLinus Torvalds }
17441da177e4SLinus Torvalds 
174584905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1746fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1747fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1748fd32119bSDouglas Gilbert 
17491da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17501da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17511da177e4SLinus Torvalds {
175201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
175384905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
175484905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
175536e07d7eSGeorge Kennedy 	u32 alloc_len = cmd[4];
175636e07d7eSGeorge Kennedy 	u32 len = 18;
175784905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17581da177e4SLinus Torvalds 
1759c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
176084905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
176184905d34SDouglas Gilbert 		if (dsense) {
176284905d34SDouglas Gilbert 			arr[0] = 0x72;
176384905d34SDouglas Gilbert 			arr[1] = NOT_READY;
176484905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
176584905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
176684905d34SDouglas Gilbert 			len = 8;
176784905d34SDouglas Gilbert 		} else {
176884905d34SDouglas Gilbert 			arr[0] = 0x70;
176984905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
177084905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
177184905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
177284905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
177384905d34SDouglas Gilbert 		}
177484905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
177584905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1776c2248fc9SDouglas Gilbert 		if (dsense) {
1777c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1778c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1779c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
178084905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1781c2248fc9SDouglas Gilbert 			len = 8;
1782c65b1445SDouglas Gilbert 		} else {
1783c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1784c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1785c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1786c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
178784905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1788c65b1445SDouglas Gilbert 		}
178984905d34SDouglas Gilbert 	} else {	/* nothing to report */
1790c2248fc9SDouglas Gilbert 		if (dsense) {
1791c2248fc9SDouglas Gilbert 			len = 8;
179284905d34SDouglas Gilbert 			memset(arr, 0, len);
179384905d34SDouglas Gilbert 			arr[0] = 0x72;
1794c2248fc9SDouglas Gilbert 		} else {
179584905d34SDouglas Gilbert 			memset(arr, 0, len);
1796c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1797c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1798c2248fc9SDouglas Gilbert 		}
1799c65b1445SDouglas Gilbert 	}
180036e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
18011da177e4SLinus Torvalds }
18021da177e4SLinus Torvalds 
1803fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1804c65b1445SDouglas Gilbert {
180501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1806fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
18074f2c8bf6SDouglas Gilbert 	bool changing;
1808c65b1445SDouglas Gilbert 
1809c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1810c65b1445SDouglas Gilbert 	if (power_cond) {
181122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1812c65b1445SDouglas Gilbert 		return check_condition_result;
1813c65b1445SDouglas Gilbert 	}
1814fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1815fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1816fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1817fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1818fc13638aSDouglas Gilbert 
1819fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1820fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1821fc13638aSDouglas Gilbert 
1822fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1823fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1824fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1825fc13638aSDouglas Gilbert 				stopped_state = 0;
1826fc13638aSDouglas Gilbert 			}
1827fc13638aSDouglas Gilbert 		}
1828fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1829fc13638aSDouglas Gilbert 			if (want_stop) {
1830fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1831fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1832fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1833fc13638aSDouglas Gilbert 				return check_condition_result;
1834fc13638aSDouglas Gilbert 			}
1835fc13638aSDouglas Gilbert 		}
1836fc13638aSDouglas Gilbert 	}
1837fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1838fc13638aSDouglas Gilbert 	if (changing)
1839fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1840fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18414f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18424f2c8bf6SDouglas Gilbert 	else
18434f2c8bf6SDouglas Gilbert 		return 0;
1844c65b1445SDouglas Gilbert }
1845c65b1445SDouglas Gilbert 
184628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
184728898873SFUJITA Tomonori {
1848773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1849773642d9SDouglas Gilbert 
1850773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1851773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1852773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
185328898873SFUJITA Tomonori 	else
185428898873SFUJITA Tomonori 		return sdebug_store_sectors;
185528898873SFUJITA Tomonori }
185628898873SFUJITA Tomonori 
18571da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18581da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18591da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18601da177e4SLinus Torvalds {
18611da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1862c65b1445SDouglas Gilbert 	unsigned int capac;
18631da177e4SLinus Torvalds 
1864c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18661da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1867c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1868c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1869773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1870773642d9SDouglas Gilbert 	} else
1871773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1872773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18731da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18741da177e4SLinus Torvalds }
18751da177e4SLinus Torvalds 
1876c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1877c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1878c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1879c65b1445SDouglas Gilbert {
188001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1881c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18824e3ace00SYe Bin 	u32 alloc_len;
1883c65b1445SDouglas Gilbert 
1884773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1885c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
188628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1887c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1888773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1889773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1890773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1891773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
189244d92694SMartin K. Petersen 
1893be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18945b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1895760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1896760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1897760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1898760f3b03SDouglas Gilbert 		 */
1899760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1900760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1901be1dd78dSEric Sandeen 	}
190244d92694SMartin K. Petersen 
1903ecb8c258SBart Van Assche 	/*
1904ecb8c258SBart Van Assche 	 * Since the scsi_debug READ CAPACITY implementation always reports the
1905ecb8c258SBart Van Assche 	 * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices.
1906ecb8c258SBart Van Assche 	 */
1907ecb8c258SBart Van Assche 	if (devip->zmodel == BLK_ZONED_HM)
1908ecb8c258SBart Van Assche 		arr[12] |= 1 << 4;
1909ecb8c258SBart Van Assche 
1910773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1911c6a44287SMartin K. Petersen 
1912760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1913773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1914c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1915c6a44287SMartin K. Petersen 	}
1916c6a44287SMartin K. Petersen 
1917c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
19184e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1919c65b1445SDouglas Gilbert }
1920c65b1445SDouglas Gilbert 
19215a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19225a09e398SHannes Reinecke 
19235a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19245a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19255a09e398SHannes Reinecke {
192601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19275a09e398SHannes Reinecke 	unsigned char *arr;
19285a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19295a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1930f347c268SYe Bin 	u32 alen, n, rlen;
1931f347c268SYe Bin 	int ret;
19325a09e398SHannes Reinecke 
1933773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19346f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19356f3cbf55SDouglas Gilbert 	if (! arr)
19366f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19375a09e398SHannes Reinecke 	/*
19385a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19395a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19405a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19415a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19425a09e398SHannes Reinecke 	 */
19435a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19445a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19455a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19465a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19475a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19485a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19495a09e398SHannes Reinecke 
19505a09e398SHannes Reinecke 	/*
19515a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19525a09e398SHannes Reinecke 	 */
19535a09e398SHannes Reinecke 	n = 4;
1954b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19555a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19565a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19575a09e398SHannes Reinecke 	} else {
19585a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1959773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19605a09e398SHannes Reinecke 	}
1961773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1962773642d9SDouglas Gilbert 	n += 2;
19635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19645a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19655a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19665a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19685a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1969773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1970773642d9SDouglas Gilbert 	n += 2;
19715a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19725a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1973773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1974773642d9SDouglas Gilbert 	n += 2;
19755a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19765a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19775a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19785a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19795a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19805a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1981773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1982773642d9SDouglas Gilbert 	n += 2;
19835a09e398SHannes Reinecke 
19845a09e398SHannes Reinecke 	rlen = n - 4;
1985773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19865a09e398SHannes Reinecke 
19875a09e398SHannes Reinecke 	/*
19885a09e398SHannes Reinecke 	 * Return the smallest value of either
19895a09e398SHannes Reinecke 	 * - The allocated length
19905a09e398SHannes Reinecke 	 * - The constructed command length
19915a09e398SHannes Reinecke 	 * - The maximum array size
19925a09e398SHannes Reinecke 	 */
1993f347c268SYe Bin 	rlen = min(alen, n);
19945a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1995f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19965a09e398SHannes Reinecke 	kfree(arr);
19975a09e398SHannes Reinecke 	return ret;
19985a09e398SHannes Reinecke }
19995a09e398SHannes Reinecke 
2000fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
2001fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
200238d5c833SDouglas Gilbert {
200338d5c833SDouglas Gilbert 	bool rctd;
200438d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
200538d5c833SDouglas Gilbert 	u16 req_sa, u;
200638d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
200738d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
200838d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
200938d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
201038d5c833SDouglas Gilbert 	u8 *arr;
201138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
201238d5c833SDouglas Gilbert 
201338d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
201438d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
201538d5c833SDouglas Gilbert 	req_opcode = cmd[3];
201638d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
201738d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
20186d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
201938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
202038d5c833SDouglas Gilbert 		return check_condition_result;
202138d5c833SDouglas Gilbert 	}
202238d5c833SDouglas Gilbert 	if (alloc_len > 8192)
202338d5c833SDouglas Gilbert 		a_len = 8192;
202438d5c833SDouglas Gilbert 	else
202538d5c833SDouglas Gilbert 		a_len = alloc_len;
202699531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
202738d5c833SDouglas Gilbert 	if (NULL == arr) {
202838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
202938d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
203038d5c833SDouglas Gilbert 		return check_condition_result;
203138d5c833SDouglas Gilbert 	}
203238d5c833SDouglas Gilbert 	switch (reporting_opts) {
203338d5c833SDouglas Gilbert 	case 0:	/* all commands */
203438d5c833SDouglas Gilbert 		/* count number of commands */
203538d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
203638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
203738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
203838d5c833SDouglas Gilbert 				continue;
203938d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
204038d5c833SDouglas Gilbert 		}
204138d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
204238d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
204338d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
204438d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
204538d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
204638d5c833SDouglas Gilbert 				continue;
204738d5c833SDouglas Gilbert 			na = oip->num_attached;
204838d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
204938d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
205038d5c833SDouglas Gilbert 			if (rctd)
205138d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
205238d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
205338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
205438d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
205538d5c833SDouglas Gilbert 			if (rctd)
205638d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
205738d5c833SDouglas Gilbert 			r_oip = oip;
205838d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
205938d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
206038d5c833SDouglas Gilbert 					continue;
206138d5c833SDouglas Gilbert 				offset += bump;
206238d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
206338d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
206438d5c833SDouglas Gilbert 				if (rctd)
206538d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
206638d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
206738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
206838d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
206938d5c833SDouglas Gilbert 						   arr + offset + 6);
207038d5c833SDouglas Gilbert 				if (rctd)
207138d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
207238d5c833SDouglas Gilbert 							   arr + offset + 8);
207338d5c833SDouglas Gilbert 			}
207438d5c833SDouglas Gilbert 			oip = r_oip;
207538d5c833SDouglas Gilbert 			offset += bump;
207638d5c833SDouglas Gilbert 		}
207738d5c833SDouglas Gilbert 		break;
207838d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
207938d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
208038d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
208138d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
208238d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
208338d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
208438d5c833SDouglas Gilbert 			supp = 1;
208538d5c833SDouglas Gilbert 			offset = 4;
208638d5c833SDouglas Gilbert 		} else {
208738d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
208838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
208938d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
209038d5c833SDouglas Gilbert 							     2, 2);
209138d5c833SDouglas Gilbert 					kfree(arr);
209238d5c833SDouglas Gilbert 					return check_condition_result;
209338d5c833SDouglas Gilbert 				}
209438d5c833SDouglas Gilbert 				req_sa = 0;
209538d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
209638d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
209738d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
209838d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
209938d5c833SDouglas Gilbert 				return check_condition_result;
210038d5c833SDouglas Gilbert 			}
210138d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
210238d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
210338d5c833SDouglas Gilbert 				supp = 3;
210438d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
210538d5c833SDouglas Gilbert 				na = oip->num_attached;
210638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
210738d5c833SDouglas Gilbert 				     ++k, ++oip) {
210838d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
210938d5c833SDouglas Gilbert 						break;
211038d5c833SDouglas Gilbert 				}
211138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
211238d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
211338d5c833SDouglas Gilbert 				na = oip->num_attached;
211438d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
211538d5c833SDouglas Gilbert 				     ++k, ++oip) {
211638d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
211738d5c833SDouglas Gilbert 						break;
211838d5c833SDouglas Gilbert 				}
211938d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
212038d5c833SDouglas Gilbert 			} else
212138d5c833SDouglas Gilbert 				supp = 3;
212238d5c833SDouglas Gilbert 			if (3 == supp) {
212338d5c833SDouglas Gilbert 				u = oip->len_mask[0];
212438d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
212538d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
212638d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
212738d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
212838d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
212938d5c833SDouglas Gilbert 				offset = 4 + u;
213038d5c833SDouglas Gilbert 			} else
213138d5c833SDouglas Gilbert 				offset = 4;
213238d5c833SDouglas Gilbert 		}
213338d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
213438d5c833SDouglas Gilbert 		if (rctd) {
213538d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
213638d5c833SDouglas Gilbert 			offset += 12;
213738d5c833SDouglas Gilbert 		}
213838d5c833SDouglas Gilbert 		break;
213938d5c833SDouglas Gilbert 	default:
214038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
214138d5c833SDouglas Gilbert 		kfree(arr);
214238d5c833SDouglas Gilbert 		return check_condition_result;
214338d5c833SDouglas Gilbert 	}
214438d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
214538d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
214638d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
214738d5c833SDouglas Gilbert 	kfree(arr);
214838d5c833SDouglas Gilbert 	return errsts;
214938d5c833SDouglas Gilbert }
215038d5c833SDouglas Gilbert 
2151fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2152fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
215338d5c833SDouglas Gilbert {
215438d5c833SDouglas Gilbert 	bool repd;
215538d5c833SDouglas Gilbert 	u32 alloc_len, len;
215638d5c833SDouglas Gilbert 	u8 arr[16];
215738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
215838d5c833SDouglas Gilbert 
215938d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
216038d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
216138d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
216238d5c833SDouglas Gilbert 	if (alloc_len < 4) {
216338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
216438d5c833SDouglas Gilbert 		return check_condition_result;
216538d5c833SDouglas Gilbert 	}
216638d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
216738d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
216838d5c833SDouglas Gilbert 	if (repd) {
216938d5c833SDouglas Gilbert 		arr[3] = 0xc;
217038d5c833SDouglas Gilbert 		len = 16;
217138d5c833SDouglas Gilbert 	} else
217238d5c833SDouglas Gilbert 		len = 4;
217338d5c833SDouglas Gilbert 
217438d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
217538d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
217638d5c833SDouglas Gilbert }
217738d5c833SDouglas Gilbert 
21781da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21791da177e4SLinus Torvalds 
21801da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21811da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21821da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21831da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21841da177e4SLinus Torvalds 
21851da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21861da177e4SLinus Torvalds 	if (1 == pcontrol)
21871da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21881da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21891da177e4SLinus Torvalds }
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21921da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21931da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21941da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21951da177e4SLinus Torvalds 
21961da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21971da177e4SLinus Torvalds 	if (1 == pcontrol)
21981da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21991da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
22001da177e4SLinus Torvalds }
22011da177e4SLinus Torvalds 
22021da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
22031da177e4SLinus Torvalds {       /* Format device page for mode_sense */
22041da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
22051da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
22061da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2209773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2210773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2211773642d9SDouglas Gilbert 	if (sdebug_removable)
22121da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
22131da177e4SLinus Torvalds 	if (1 == pcontrol)
22141da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
22151da177e4SLinus Torvalds 	return sizeof(format_pg);
22161da177e4SLinus Torvalds }
22171da177e4SLinus Torvalds 
2218fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2219fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2220fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2221fd32119bSDouglas Gilbert 
22221da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22231da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2224cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2225cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2226cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22271da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22281da177e4SLinus Torvalds 
2229773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2230cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22311da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22321da177e4SLinus Torvalds 	if (1 == pcontrol)
2233cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2234cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2235cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22361da177e4SLinus Torvalds 	return sizeof(caching_pg);
22371da177e4SLinus Torvalds }
22381da177e4SLinus Torvalds 
2239fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2240fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2241fd32119bSDouglas Gilbert 
22421da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22431da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2244c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2245c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2246c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22471da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22481da177e4SLinus Torvalds 
2249773642d9SDouglas Gilbert 	if (sdebug_dsense)
22501da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2251c65b1445SDouglas Gilbert 	else
2252c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2253c6a44287SMartin K. Petersen 
2254773642d9SDouglas Gilbert 	if (sdebug_ato)
2255c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2256c6a44287SMartin K. Petersen 
22571da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22581da177e4SLinus Torvalds 	if (1 == pcontrol)
2259c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2260c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2261c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22621da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22631da177e4SLinus Torvalds }
22641da177e4SLinus Torvalds 
2265c65b1445SDouglas Gilbert 
22661da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22671da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2268c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22691da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2270c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2271c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2272c65b1445SDouglas Gilbert 
22731da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22741da177e4SLinus Torvalds 	if (1 == pcontrol)
2275c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2276c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2277c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22781da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22791da177e4SLinus Torvalds }
22801da177e4SLinus Torvalds 
2281c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2282c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2283c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2284c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2285c65b1445SDouglas Gilbert 
2286c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2287c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2288c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2289c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2290c65b1445SDouglas Gilbert }
2291c65b1445SDouglas Gilbert 
2292c65b1445SDouglas Gilbert 
2293c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2294c65b1445SDouglas Gilbert 			      int target_dev_id)
2295c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2296c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2297c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2298773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2299773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2300c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2301c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2302c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2303c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2304773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2305773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2306c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2307c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2308c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2309c65b1445SDouglas Gilbert 		};
2310c65b1445SDouglas Gilbert 	int port_a, port_b;
2311c65b1445SDouglas Gilbert 
23121b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
23131b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
23141b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
23151b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2316c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2317c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2318c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2319773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2320773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2321c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2322c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2323c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2324c65b1445SDouglas Gilbert }
2325c65b1445SDouglas Gilbert 
2326c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2327c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2328c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2329c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2330c65b1445SDouglas Gilbert 		};
2331c65b1445SDouglas Gilbert 
2332c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2333c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2334c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2335c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2336c65b1445SDouglas Gilbert }
2337c65b1445SDouglas Gilbert 
23381da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23391da177e4SLinus Torvalds 
2340fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2341fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23421da177e4SLinus Torvalds {
234323183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23441da177e4SLinus Torvalds 	unsigned char dev_spec;
234536e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
234636e07d7eSGeorge Kennedy 	int target_dev_id;
2347c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23481da177e4SLinus Torvalds 	unsigned char *ap;
23491da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
235001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2351d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23521da177e4SLinus Torvalds 
2353760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23541da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23551da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23561da177e4SLinus Torvalds 	subpcode = cmd[3];
23571da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2358760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2359760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
236064e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2361d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
236223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
236323183910SDouglas Gilbert 	else
236423183910SDouglas Gilbert 		bd_len = 0;
2365773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23661da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23671da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2368cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23691da177e4SLinus Torvalds 		return check_condition_result;
23701da177e4SLinus Torvalds 	}
2371c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2372c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2373d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2374d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2375b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23769447b6ceSMartin K. Petersen 		if (sdebug_wp)
23779447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23789447b6ceSMartin K. Petersen 	} else
237923183910SDouglas Gilbert 		dev_spec = 0x0;
23801da177e4SLinus Torvalds 	if (msense_6) {
23811da177e4SLinus Torvalds 		arr[2] = dev_spec;
238223183910SDouglas Gilbert 		arr[3] = bd_len;
23831da177e4SLinus Torvalds 		offset = 4;
23841da177e4SLinus Torvalds 	} else {
23851da177e4SLinus Torvalds 		arr[3] = dev_spec;
238623183910SDouglas Gilbert 		if (16 == bd_len)
238723183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
238823183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23891da177e4SLinus Torvalds 		offset = 8;
23901da177e4SLinus Torvalds 	}
23911da177e4SLinus Torvalds 	ap = arr + offset;
239228898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
239328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
239428898873SFUJITA Tomonori 
239523183910SDouglas Gilbert 	if (8 == bd_len) {
2396773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2397773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2398773642d9SDouglas Gilbert 		else
2399773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2400773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
240123183910SDouglas Gilbert 		offset += bd_len;
240223183910SDouglas Gilbert 		ap = arr + offset;
240323183910SDouglas Gilbert 	} else if (16 == bd_len) {
2404773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2405773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
240623183910SDouglas Gilbert 		offset += bd_len;
240723183910SDouglas Gilbert 		ap = arr + offset;
240823183910SDouglas Gilbert 	}
24091da177e4SLinus Torvalds 
2410c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2411c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
241222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24131da177e4SLinus Torvalds 		return check_condition_result;
24141da177e4SLinus Torvalds 	}
2415760f3b03SDouglas Gilbert 	bad_pcode = false;
2416760f3b03SDouglas Gilbert 
24171da177e4SLinus Torvalds 	switch (pcode) {
24181da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
24191da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
24201da177e4SLinus Torvalds 		offset += len;
24211da177e4SLinus Torvalds 		break;
24221da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
24231da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24241da177e4SLinus Torvalds 		offset += len;
24251da177e4SLinus Torvalds 		break;
24261da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2427760f3b03SDouglas Gilbert 		if (is_disk) {
24281da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24291da177e4SLinus Torvalds 			offset += len;
2430760f3b03SDouglas Gilbert 		} else
2431760f3b03SDouglas Gilbert 			bad_pcode = true;
24321da177e4SLinus Torvalds 		break;
24331da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2434d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24351da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24361da177e4SLinus Torvalds 			offset += len;
2437760f3b03SDouglas Gilbert 		} else
2438760f3b03SDouglas Gilbert 			bad_pcode = true;
24391da177e4SLinus Torvalds 		break;
24401da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24411da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24421da177e4SLinus Torvalds 		offset += len;
24431da177e4SLinus Torvalds 		break;
2444c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2445c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
244622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2447c65b1445SDouglas Gilbert 			return check_condition_result;
2448c65b1445SDouglas Gilbert 		}
2449c65b1445SDouglas Gilbert 		len = 0;
2450c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2451c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2452c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2453c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2454c65b1445SDouglas Gilbert 						  target_dev_id);
2455c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2456c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2457c65b1445SDouglas Gilbert 		offset += len;
2458c65b1445SDouglas Gilbert 		break;
24591da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24601da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24611da177e4SLinus Torvalds 		offset += len;
24621da177e4SLinus Torvalds 		break;
24631da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2464c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24651da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24661da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2467760f3b03SDouglas Gilbert 			if (is_disk) {
2468760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2469760f3b03SDouglas Gilbert 						      target);
2470760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2471760f3b03SDouglas Gilbert 						       target);
2472d36da305SDouglas Gilbert 			} else if (is_zbc) {
2473d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2474d36da305SDouglas Gilbert 						       target);
2475760f3b03SDouglas Gilbert 			}
24761da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2477c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2478c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2479c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2480c65b1445SDouglas Gilbert 						  target, target_dev_id);
2481c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2482c65b1445SDouglas Gilbert 			}
24831da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2484760f3b03SDouglas Gilbert 			offset += len;
2485c65b1445SDouglas Gilbert 		} else {
248622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2487c65b1445SDouglas Gilbert 			return check_condition_result;
2488c65b1445SDouglas Gilbert 		}
24891da177e4SLinus Torvalds 		break;
24901da177e4SLinus Torvalds 	default:
2491760f3b03SDouglas Gilbert 		bad_pcode = true;
2492760f3b03SDouglas Gilbert 		break;
2493760f3b03SDouglas Gilbert 	}
2494760f3b03SDouglas Gilbert 	if (bad_pcode) {
249522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24961da177e4SLinus Torvalds 		return check_condition_result;
24971da177e4SLinus Torvalds 	}
24981da177e4SLinus Torvalds 	if (msense_6)
24991da177e4SLinus Torvalds 		arr[0] = offset - 1;
2500773642d9SDouglas Gilbert 	else
2501773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
250236e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
25031da177e4SLinus Torvalds }
25041da177e4SLinus Torvalds 
2505c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2506c65b1445SDouglas Gilbert 
2507fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2508fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2509c65b1445SDouglas Gilbert {
2510c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2511c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2512c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
251301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2514c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2515c65b1445SDouglas Gilbert 
2516c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2517c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2518c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2519773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2520c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
252122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2522c65b1445SDouglas Gilbert 		return check_condition_result;
2523c65b1445SDouglas Gilbert 	}
2524c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2525c65b1445SDouglas Gilbert 	if (-1 == res)
2526773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2527773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2528cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2529cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2530cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2531773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2532773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2533e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2534e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
253522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2536c65b1445SDouglas Gilbert 		return check_condition_result;
2537c65b1445SDouglas Gilbert 	}
2538c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2539c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2540c65b1445SDouglas Gilbert 	if (ps) {
254122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2542c65b1445SDouglas Gilbert 		return check_condition_result;
2543c65b1445SDouglas Gilbert 	}
2544c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2545773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2546c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2547c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2548cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2549c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2550c65b1445SDouglas Gilbert 		return check_condition_result;
2551c65b1445SDouglas Gilbert 	}
2552c65b1445SDouglas Gilbert 	switch (mpage) {
2553cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2554cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2555cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2556cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2557cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2558cbf67842SDouglas Gilbert 		}
2559cbf67842SDouglas Gilbert 		break;
2560c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2561c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2562c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2563c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25649447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25659447b6ceSMartin K. Petersen 				sdebug_wp = true;
25669447b6ceSMartin K. Petersen 			else
25679447b6ceSMartin K. Petersen 				sdebug_wp = false;
2568773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2569cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2570c65b1445SDouglas Gilbert 		}
2571c65b1445SDouglas Gilbert 		break;
2572c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2573c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2574c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2575c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2576cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2577c65b1445SDouglas Gilbert 		}
2578c65b1445SDouglas Gilbert 		break;
2579c65b1445SDouglas Gilbert 	default:
2580c65b1445SDouglas Gilbert 		break;
2581c65b1445SDouglas Gilbert 	}
258222017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2583c65b1445SDouglas Gilbert 	return check_condition_result;
2584cbf67842SDouglas Gilbert set_mode_changed_ua:
2585cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2586cbf67842SDouglas Gilbert 	return 0;
2587c65b1445SDouglas Gilbert }
2588c65b1445SDouglas Gilbert 
2589c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2590c65b1445SDouglas Gilbert {
2591c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2592c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2593c65b1445SDouglas Gilbert 		};
2594c65b1445SDouglas Gilbert 
2595c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2596c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2597c65b1445SDouglas Gilbert }
2598c65b1445SDouglas Gilbert 
2599c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2600c65b1445SDouglas Gilbert {
2601c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2602c65b1445SDouglas Gilbert 		};
2603c65b1445SDouglas Gilbert 
2604c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2605c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2606c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2607c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2608c65b1445SDouglas Gilbert 	}
2609c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2610c65b1445SDouglas Gilbert }
2611c65b1445SDouglas Gilbert 
26120790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr)
26130790797aSDouglas Gilbert {
26140790797aSDouglas Gilbert 	unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
26150790797aSDouglas Gilbert 					 0x0, 40, 72, 0xff, 45, 18, 0, 0,
26160790797aSDouglas Gilbert 					 0x1, 0x0, 0x23, 0x8,
26170790797aSDouglas Gilbert 					 0x0, 55, 72, 35, 55, 45, 0, 0,
26180790797aSDouglas Gilbert 		};
26190790797aSDouglas Gilbert 
26200790797aSDouglas Gilbert 	memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
26210790797aSDouglas Gilbert 	return sizeof(env_rep_l_spg);
26220790797aSDouglas Gilbert }
26230790797aSDouglas Gilbert 
2624c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2625c65b1445SDouglas Gilbert 
2626c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2627c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2628c65b1445SDouglas Gilbert {
262936e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
263036e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2631c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
263201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2633c65b1445SDouglas Gilbert 
2634c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2635c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2636c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2637c65b1445SDouglas Gilbert 	if (ppc || sp) {
263822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2639c65b1445SDouglas Gilbert 		return check_condition_result;
2640c65b1445SDouglas Gilbert 	}
2641c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
264223183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2643773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2644c65b1445SDouglas Gilbert 	arr[0] = pcode;
264523183910SDouglas Gilbert 	if (0 == subpcode) {
2646c65b1445SDouglas Gilbert 		switch (pcode) {
2647c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2648c65b1445SDouglas Gilbert 			n = 4;
2649c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2650c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2651c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2652c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2653c65b1445SDouglas Gilbert 			break;
2654c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2655c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2656c65b1445SDouglas Gilbert 			break;
2657c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2658c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2659c65b1445SDouglas Gilbert 			break;
2660c65b1445SDouglas Gilbert 		default:
266122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2662c65b1445SDouglas Gilbert 			return check_condition_result;
2663c65b1445SDouglas Gilbert 		}
266423183910SDouglas Gilbert 	} else if (0xff == subpcode) {
266523183910SDouglas Gilbert 		arr[0] |= 0x40;
266623183910SDouglas Gilbert 		arr[1] = subpcode;
266723183910SDouglas Gilbert 		switch (pcode) {
266823183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
266923183910SDouglas Gilbert 			n = 4;
267023183910SDouglas Gilbert 			arr[n++] = 0x0;
267123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
267223183910SDouglas Gilbert 			arr[n++] = 0x0;
267323183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
267423183910SDouglas Gilbert 			arr[n++] = 0xd;
267523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26760790797aSDouglas Gilbert 			arr[n++] = 0xd;
26770790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26780790797aSDouglas Gilbert 			arr[n++] = 0xd;
26790790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0xd subpages */
268023183910SDouglas Gilbert 			arr[n++] = 0x2f;
268123183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
26820790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26830790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0x2f subpages */
268423183910SDouglas Gilbert 			arr[3] = n - 4;
268523183910SDouglas Gilbert 			break;
268623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
268723183910SDouglas Gilbert 			n = 4;
268823183910SDouglas Gilbert 			arr[n++] = 0xd;
268923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26900790797aSDouglas Gilbert 			arr[n++] = 0xd;
26910790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26920790797aSDouglas Gilbert 			arr[n++] = 0xd;
26930790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
269423183910SDouglas Gilbert 			arr[3] = n - 4;
269523183910SDouglas Gilbert 			break;
269623183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
269723183910SDouglas Gilbert 			n = 4;
269823183910SDouglas Gilbert 			arr[n++] = 0x2f;
269923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
27000790797aSDouglas Gilbert 			arr[n++] = 0x2f;
27010790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
270223183910SDouglas Gilbert 			arr[3] = n - 4;
270323183910SDouglas Gilbert 			break;
270423183910SDouglas Gilbert 		default:
270522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
270623183910SDouglas Gilbert 			return check_condition_result;
270723183910SDouglas Gilbert 		}
27080790797aSDouglas Gilbert 	} else if (subpcode > 0) {
27090790797aSDouglas Gilbert 		arr[0] |= 0x40;
27100790797aSDouglas Gilbert 		arr[1] = subpcode;
27110790797aSDouglas Gilbert 		if (pcode == 0xd && subpcode == 1)
27120790797aSDouglas Gilbert 			arr[3] = resp_env_rep_l_spg(arr + 4);
27130790797aSDouglas Gilbert 		else {
27140790797aSDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
27150790797aSDouglas Gilbert 			return check_condition_result;
27160790797aSDouglas Gilbert 		}
271723183910SDouglas Gilbert 	} else {
271822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
271923183910SDouglas Gilbert 		return check_condition_result;
272023183910SDouglas Gilbert 	}
272136e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2722c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
272336e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2724c65b1445SDouglas Gilbert }
2725c65b1445SDouglas Gilbert 
2726f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2727f0d1cf93SDouglas Gilbert {
2728f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2729f0d1cf93SDouglas Gilbert }
2730f0d1cf93SDouglas Gilbert 
2731f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2732f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2733f0d1cf93SDouglas Gilbert {
27344a5fc1c6SDamien Le Moal 	u32 zno = lba >> devip->zsize_shift;
27354a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp;
27364a5fc1c6SDamien Le Moal 
27374a5fc1c6SDamien Le Moal 	if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones)
27384a5fc1c6SDamien Le Moal 		return &devip->zstate[zno];
27394a5fc1c6SDamien Le Moal 
27404a5fc1c6SDamien Le Moal 	/*
27414a5fc1c6SDamien Le Moal 	 * If the zone capacity is less than the zone size, adjust for gap
27424a5fc1c6SDamien Le Moal 	 * zones.
27434a5fc1c6SDamien Le Moal 	 */
27444a5fc1c6SDamien Le Moal 	zno = 2 * zno - devip->nr_conv_zones;
27454a5fc1c6SDamien Le Moal 	WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones);
27464a5fc1c6SDamien Le Moal 	zsp = &devip->zstate[zno];
27474a5fc1c6SDamien Le Moal 	if (lba >= zsp->z_start + zsp->z_size)
27484a5fc1c6SDamien Le Moal 		zsp++;
27494a5fc1c6SDamien Le Moal 	WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size);
27504a5fc1c6SDamien Le Moal 	return zsp;
2751f0d1cf93SDouglas Gilbert }
2752f0d1cf93SDouglas Gilbert 
2753f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2754f0d1cf93SDouglas Gilbert {
275535dbe2b9SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_CNV;
2756f0d1cf93SDouglas Gilbert }
2757f0d1cf93SDouglas Gilbert 
27584a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp)
27594a5fc1c6SDamien Le Moal {
27604a5fc1c6SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_GAP;
27614a5fc1c6SDamien Le Moal }
27624a5fc1c6SDamien Le Moal 
27634a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp)
27644a5fc1c6SDamien Le Moal {
27654a5fc1c6SDamien Le Moal 	return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp);
27664a5fc1c6SDamien Le Moal }
27674a5fc1c6SDamien Le Moal 
2768f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2769f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2770f0d1cf93SDouglas Gilbert {
2771f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2772f0d1cf93SDouglas Gilbert 
27734a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2774f0d1cf93SDouglas Gilbert 		return;
2775f0d1cf93SDouglas Gilbert 
2776f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2777f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2778f0d1cf93SDouglas Gilbert 		return;
2779f0d1cf93SDouglas Gilbert 
2780f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2781f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2782f0d1cf93SDouglas Gilbert 	else
2783f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2784f0d1cf93SDouglas Gilbert 
2785f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2786f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2787f0d1cf93SDouglas Gilbert 	} else {
2788f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2789f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2790f0d1cf93SDouglas Gilbert 	}
2791f0d1cf93SDouglas Gilbert }
2792f0d1cf93SDouglas Gilbert 
2793f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2794f0d1cf93SDouglas Gilbert {
2795f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2796f0d1cf93SDouglas Gilbert 	unsigned int i;
2797f0d1cf93SDouglas Gilbert 
2798f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2799f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2800f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2801f0d1cf93SDouglas Gilbert 			return;
2802f0d1cf93SDouglas Gilbert 		}
2803f0d1cf93SDouglas Gilbert 	}
2804f0d1cf93SDouglas Gilbert }
2805f0d1cf93SDouglas Gilbert 
2806f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2807f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2808f0d1cf93SDouglas Gilbert {
2809f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2810f0d1cf93SDouglas Gilbert 
28114a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2812f0d1cf93SDouglas Gilbert 		return;
2813f0d1cf93SDouglas Gilbert 
2814f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2815f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2816f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2817f0d1cf93SDouglas Gilbert 		return;
2818f0d1cf93SDouglas Gilbert 
2819f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2820f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2821f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2822f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2823f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2824f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2825f0d1cf93SDouglas Gilbert 
2826f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2827f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2828f0d1cf93SDouglas Gilbert 	if (explicit) {
2829f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2830f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2831f0d1cf93SDouglas Gilbert 	} else {
2832f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2833f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2834f0d1cf93SDouglas Gilbert 	}
2835f0d1cf93SDouglas Gilbert }
2836f0d1cf93SDouglas Gilbert 
2837566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip,
2838566d3c57SDamien Le Moal 				     struct sdeb_zone_state *zsp)
2839566d3c57SDamien Le Moal {
2840566d3c57SDamien Le Moal 	switch (zsp->z_cond) {
2841566d3c57SDamien Le Moal 	case ZC2_IMPLICIT_OPEN:
2842566d3c57SDamien Le Moal 		devip->nr_imp_open--;
2843566d3c57SDamien Le Moal 		break;
2844566d3c57SDamien Le Moal 	case ZC3_EXPLICIT_OPEN:
2845566d3c57SDamien Le Moal 		devip->nr_exp_open--;
2846566d3c57SDamien Le Moal 		break;
2847566d3c57SDamien Le Moal 	default:
2848566d3c57SDamien Le Moal 		WARN_ONCE(true, "Invalid zone %llu condition %x\n",
2849566d3c57SDamien Le Moal 			  zsp->z_start, zsp->z_cond);
2850566d3c57SDamien Le Moal 		break;
2851566d3c57SDamien Le Moal 	}
2852566d3c57SDamien Le Moal 	zsp->z_cond = ZC5_FULL;
2853566d3c57SDamien Le Moal }
2854566d3c57SDamien Le Moal 
2855f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2856f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2857f0d1cf93SDouglas Gilbert {
2858f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
285964e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2860f0d1cf93SDouglas Gilbert 
28614a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2862f0d1cf93SDouglas Gilbert 		return;
2863f0d1cf93SDouglas Gilbert 
286435dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2865f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
286664e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2867566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
286864e14eceSDamien Le Moal 		return;
286964e14eceSDamien Le Moal 	}
287064e14eceSDamien Le Moal 
287164e14eceSDamien Le Moal 	while (num) {
287264e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
287364e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
287464e14eceSDamien Le Moal 
287564e14eceSDamien Le Moal 		end = lba + num;
287664e14eceSDamien Le Moal 		if (end >= zend) {
287764e14eceSDamien Le Moal 			n = zend - lba;
287864e14eceSDamien Le Moal 			zsp->z_wp = zend;
287964e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
288064e14eceSDamien Le Moal 			n = num;
288164e14eceSDamien Le Moal 			zsp->z_wp = end;
288264e14eceSDamien Le Moal 		} else {
288364e14eceSDamien Le Moal 			n = num;
288464e14eceSDamien Le Moal 		}
288564e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2886566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
288764e14eceSDamien Le Moal 
288864e14eceSDamien Le Moal 		num -= n;
288964e14eceSDamien Le Moal 		lba += n;
289064e14eceSDamien Le Moal 		if (num) {
289164e14eceSDamien Le Moal 			zsp++;
289264e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
289364e14eceSDamien Le Moal 		}
289464e14eceSDamien Le Moal 	}
2895f0d1cf93SDouglas Gilbert }
2896f0d1cf93SDouglas Gilbert 
2897f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
28989447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
28991da177e4SLinus Torvalds {
2900f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2901f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2902f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2903f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2904f0d1cf93SDouglas Gilbert 
2905f0d1cf93SDouglas Gilbert 	if (!write) {
290664e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
290764e14eceSDamien Le Moal 			return 0;
290864e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
29094a5fc1c6SDamien Le Moal 		if (zsp->z_type != zsp_end->z_type) {
2910f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2911f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2912f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2913f0d1cf93SDouglas Gilbert 			return check_condition_result;
2914f0d1cf93SDouglas Gilbert 		}
2915f0d1cf93SDouglas Gilbert 		return 0;
2916f0d1cf93SDouglas Gilbert 	}
2917f0d1cf93SDouglas Gilbert 
29184a5fc1c6SDamien Le Moal 	/* Writing into a gap zone is not allowed */
29194a5fc1c6SDamien Le Moal 	if (zbc_zone_is_gap(zsp)) {
29204a5fc1c6SDamien Le Moal 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE,
29214a5fc1c6SDamien Le Moal 				ATTEMPT_ACCESS_GAP);
29224a5fc1c6SDamien Le Moal 		return check_condition_result;
29234a5fc1c6SDamien Le Moal 	}
29244a5fc1c6SDamien Le Moal 
2925f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2926f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2927f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2928f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2929f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2930f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2931f0d1cf93SDouglas Gilbert 			return check_condition_result;
2932f0d1cf93SDouglas Gilbert 		}
2933f0d1cf93SDouglas Gilbert 		return 0;
2934f0d1cf93SDouglas Gilbert 	}
2935f0d1cf93SDouglas Gilbert 
293635dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2937f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2938f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2939f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2940f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2941f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2942f0d1cf93SDouglas Gilbert 			return check_condition_result;
2943f0d1cf93SDouglas Gilbert 		}
2944f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2945f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2946f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2947f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2948f0d1cf93SDouglas Gilbert 			return check_condition_result;
2949f0d1cf93SDouglas Gilbert 		}
2950f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2951f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2952f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2953f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2954f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2955f0d1cf93SDouglas Gilbert 			return check_condition_result;
2956f0d1cf93SDouglas Gilbert 		}
295764e14eceSDamien Le Moal 	}
2958f0d1cf93SDouglas Gilbert 
2959f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2960f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2961f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2962f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2963f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2964f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2965f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2966f0d1cf93SDouglas Gilbert 			return check_condition_result;
2967f0d1cf93SDouglas Gilbert 		}
2968f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2969f0d1cf93SDouglas Gilbert 	}
2970f0d1cf93SDouglas Gilbert 
2971f0d1cf93SDouglas Gilbert 	return 0;
2972f0d1cf93SDouglas Gilbert }
2973f0d1cf93SDouglas Gilbert 
2974f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2975f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2976f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2977f0d1cf93SDouglas Gilbert {
2978f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2979f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2980f0d1cf93SDouglas Gilbert 
2981c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
298222017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
29831da177e4SLinus Torvalds 		return check_condition_result;
29841da177e4SLinus Torvalds 	}
2985c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2986c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
298722017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2988cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2989c65b1445SDouglas Gilbert 		return check_condition_result;
2990c65b1445SDouglas Gilbert 	}
29919447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
29929447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29939447b6ceSMartin K. Petersen 		return check_condition_result;
29949447b6ceSMartin K. Petersen 	}
2995f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2996f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2997f0d1cf93SDouglas Gilbert 
299819789100SFUJITA Tomonori 	return 0;
299919789100SFUJITA Tomonori }
300019789100SFUJITA Tomonori 
3001b6ff8ca7SDouglas Gilbert /*
3002b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
3003b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
3004b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
3005b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
3006b6ff8ca7SDouglas Gilbert  */
3007b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
3008b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
300987c715dcSDouglas Gilbert {
3010b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
3011b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
3012b6ff8ca7SDouglas Gilbert 		return NULL;
3013b6ff8ca7SDouglas Gilbert 	}
3014b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
301587c715dcSDouglas Gilbert }
301687c715dcSDouglas Gilbert 
3017a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
301887c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
301987c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
302019789100SFUJITA Tomonori {
302119789100SFUJITA Tomonori 	int ret;
3022c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
3023a4517511SAkinobu Mita 	enum dma_data_direction dir;
302487c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
302587c715dcSDouglas Gilbert 	u8 *fsp;
302619789100SFUJITA Tomonori 
3027c2248fc9SDouglas Gilbert 	if (do_write) {
3028a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
30294f2c8bf6SDouglas Gilbert 		write_since_sync = true;
3030a4517511SAkinobu Mita 	} else {
3031a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
3032a4517511SAkinobu Mita 	}
3033a4517511SAkinobu Mita 
303487c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
3035a4517511SAkinobu Mita 		return 0;
303687c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
3037a4517511SAkinobu Mita 		return -1;
303887c715dcSDouglas Gilbert 	fsp = sip->storep;
303919789100SFUJITA Tomonori 
304019789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
304119789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
304219789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
304319789100SFUJITA Tomonori 
3044386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
304587c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
30460a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
3047773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
3048a4517511SAkinobu Mita 		return ret;
3049a4517511SAkinobu Mita 
3050a4517511SAkinobu Mita 	if (rest) {
3051386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
305287c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
30530a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
30540a7e69c7SDouglas Gilbert 			    do_write);
3055a4517511SAkinobu Mita 	}
305619789100SFUJITA Tomonori 
305719789100SFUJITA Tomonori 	return ret;
305819789100SFUJITA Tomonori }
305919789100SFUJITA Tomonori 
306087c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
306187c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
306287c715dcSDouglas Gilbert {
306387c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
306487c715dcSDouglas Gilbert 
306587c715dcSDouglas Gilbert 	if (!sdb->length)
306687c715dcSDouglas Gilbert 		return 0;
306787c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
306887c715dcSDouglas Gilbert 		return -1;
306987c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
307087c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
307187c715dcSDouglas Gilbert }
307287c715dcSDouglas Gilbert 
307387c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
307487c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
307538d5c833SDouglas Gilbert  * return false. */
307687c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
3077c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
307838d5c833SDouglas Gilbert {
307938d5c833SDouglas Gilbert 	bool res;
308038d5c833SDouglas Gilbert 	u64 block, rest = 0;
308138d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
3082773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
308387c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
308438d5c833SDouglas Gilbert 
308538d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
308638d5c833SDouglas Gilbert 	if (block + num > store_blks)
308738d5c833SDouglas Gilbert 		rest = block + num - store_blks;
308838d5c833SDouglas Gilbert 
308987c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
309038d5c833SDouglas Gilbert 	if (!res)
309138d5c833SDouglas Gilbert 		return res;
309238d5c833SDouglas Gilbert 	if (rest)
309387c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
309438d5c833SDouglas Gilbert 			     rest * lb_size);
309538d5c833SDouglas Gilbert 	if (!res)
309638d5c833SDouglas Gilbert 		return res;
3097c3e2fe92SDouglas Gilbert 	if (compare_only)
3098c3e2fe92SDouglas Gilbert 		return true;
309938d5c833SDouglas Gilbert 	arr += num * lb_size;
310087c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
310138d5c833SDouglas Gilbert 	if (rest)
310287c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
310338d5c833SDouglas Gilbert 	return res;
310438d5c833SDouglas Gilbert }
310538d5c833SDouglas Gilbert 
310651d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3107beb40ea4SAkinobu Mita {
310851d648afSAkinobu Mita 	__be16 csum;
3109beb40ea4SAkinobu Mita 
3110773642d9SDouglas Gilbert 	if (sdebug_guard)
311151d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
311251d648afSAkinobu Mita 	else
3113beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
311451d648afSAkinobu Mita 
3115beb40ea4SAkinobu Mita 	return csum;
3116beb40ea4SAkinobu Mita }
3117beb40ea4SAkinobu Mita 
31186ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3119beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3120beb40ea4SAkinobu Mita {
3121773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3122beb40ea4SAkinobu Mita 
3123beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3124c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3125beb40ea4SAkinobu Mita 			(unsigned long)sector,
3126beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3127beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3128beb40ea4SAkinobu Mita 		return 0x01;
3129beb40ea4SAkinobu Mita 	}
31308475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3131beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3132c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3133c1287970STomas Winkler 			(unsigned long)sector);
3134beb40ea4SAkinobu Mita 		return 0x03;
3135beb40ea4SAkinobu Mita 	}
31368475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3137beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3138c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3139c1287970STomas Winkler 			(unsigned long)sector);
3140beb40ea4SAkinobu Mita 		return 0x03;
3141beb40ea4SAkinobu Mita 	}
3142beb40ea4SAkinobu Mita 	return 0;
3143beb40ea4SAkinobu Mita }
3144beb40ea4SAkinobu Mita 
314587c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
314665f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3147c6a44287SMartin K. Petersen {
3148be4e11beSAkinobu Mita 	size_t resid;
3149c6a44287SMartin K. Petersen 	void *paddr;
315087c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3151b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
315287c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
315314faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3154be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3155c6a44287SMartin K. Petersen 
3156e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3157e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3158c6a44287SMartin K. Petersen 
315987c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
316087c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3161be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3162be4e11beSAkinobu Mita 
3163be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
316487c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
316587c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3166be4e11beSAkinobu Mita 		size_t rest = 0;
316714faa944SAkinobu Mita 
316814faa944SAkinobu Mita 		if (dif_store_end < start + len)
316914faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3170c6a44287SMartin K. Petersen 
3171be4e11beSAkinobu Mita 		paddr = miter.addr;
317214faa944SAkinobu Mita 
317365f72f2aSAkinobu Mita 		if (read)
317465f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
317565f72f2aSAkinobu Mita 		else
317665f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
317765f72f2aSAkinobu Mita 
317865f72f2aSAkinobu Mita 		if (rest) {
317965f72f2aSAkinobu Mita 			if (read)
318014faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
318165f72f2aSAkinobu Mita 			else
318265f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
318365f72f2aSAkinobu Mita 		}
3184c6a44287SMartin K. Petersen 
3185e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3186c6a44287SMartin K. Petersen 		resid -= len;
3187c6a44287SMartin K. Petersen 	}
3188be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3189bb8c063cSAkinobu Mita }
3190c6a44287SMartin K. Petersen 
319187c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3192bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3193bb8c063cSAkinobu Mita {
3194f7be6772SMartin K. Petersen 	int ret = 0;
3195bb8c063cSAkinobu Mita 	unsigned int i;
3196bb8c063cSAkinobu Mita 	sector_t sector;
319787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3198b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
319987c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3200bb8c063cSAkinobu Mita 
3201c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3202bb8c063cSAkinobu Mita 		sector = start_sec + i;
320387c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3204bb8c063cSAkinobu Mita 
320551d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3206bb8c063cSAkinobu Mita 			continue;
3207bb8c063cSAkinobu Mita 
3208f7be6772SMartin K. Petersen 		/*
3209f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3210f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3211f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3212f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3213f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3214f7be6772SMartin K. Petersen 		 */
3215f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3216f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3217f7be6772SMartin K. Petersen 					 sector, ei_lba);
3218bb8c063cSAkinobu Mita 			if (ret) {
3219bb8c063cSAkinobu Mita 				dif_errors++;
3220f7be6772SMartin K. Petersen 				break;
3221f7be6772SMartin K. Petersen 			}
3222bb8c063cSAkinobu Mita 		}
3223bb8c063cSAkinobu Mita 	}
3224bb8c063cSAkinobu Mita 
322587c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3226c6a44287SMartin K. Petersen 	dix_reads++;
3227c6a44287SMartin K. Petersen 
3228f7be6772SMartin K. Petersen 	return ret;
3229c6a44287SMartin K. Petersen }
3230c6a44287SMartin K. Petersen 
32317109f370SDouglas Gilbert static inline void
32327109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip)
32337109f370SDouglas Gilbert {
3234e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3235e9c47801SDamien Le Moal 		if (sip)
3236e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3237e9c47801SDamien Le Moal 		else
3238e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3239e9c47801SDamien Le Moal 	} else {
32407109f370SDouglas Gilbert 		if (sip)
32417109f370SDouglas Gilbert 			read_lock(&sip->macc_lck);
32427109f370SDouglas Gilbert 		else
32437109f370SDouglas Gilbert 			read_lock(&sdeb_fake_rw_lck);
32447109f370SDouglas Gilbert 	}
3245e9c47801SDamien Le Moal }
32467109f370SDouglas Gilbert 
32477109f370SDouglas Gilbert static inline void
32487109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip)
32497109f370SDouglas Gilbert {
3250e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3251e9c47801SDamien Le Moal 		if (sip)
3252e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3253e9c47801SDamien Le Moal 		else
3254e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3255e9c47801SDamien Le Moal 	} else {
32567109f370SDouglas Gilbert 		if (sip)
32577109f370SDouglas Gilbert 			read_unlock(&sip->macc_lck);
32587109f370SDouglas Gilbert 		else
32597109f370SDouglas Gilbert 			read_unlock(&sdeb_fake_rw_lck);
32607109f370SDouglas Gilbert 	}
3261e9c47801SDamien Le Moal }
32627109f370SDouglas Gilbert 
32637109f370SDouglas Gilbert static inline void
32647109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip)
32657109f370SDouglas Gilbert {
3266e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3267e9c47801SDamien Le Moal 		if (sip)
3268e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3269e9c47801SDamien Le Moal 		else
3270e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3271e9c47801SDamien Le Moal 	} else {
32727109f370SDouglas Gilbert 		if (sip)
32737109f370SDouglas Gilbert 			write_lock(&sip->macc_lck);
32747109f370SDouglas Gilbert 		else
32757109f370SDouglas Gilbert 			write_lock(&sdeb_fake_rw_lck);
32767109f370SDouglas Gilbert 	}
3277e9c47801SDamien Le Moal }
32787109f370SDouglas Gilbert 
32797109f370SDouglas Gilbert static inline void
32807109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip)
32817109f370SDouglas Gilbert {
3282e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3283e9c47801SDamien Le Moal 		if (sip)
3284e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3285e9c47801SDamien Le Moal 		else
3286e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3287e9c47801SDamien Le Moal 	} else {
32887109f370SDouglas Gilbert 		if (sip)
32897109f370SDouglas Gilbert 			write_unlock(&sip->macc_lck);
32907109f370SDouglas Gilbert 		else
32917109f370SDouglas Gilbert 			write_unlock(&sdeb_fake_rw_lck);
32927109f370SDouglas Gilbert 	}
3293e9c47801SDamien Le Moal }
32947109f370SDouglas Gilbert 
3295fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
329619789100SFUJITA Tomonori {
329787c715dcSDouglas Gilbert 	bool check_prot;
3298c2248fc9SDouglas Gilbert 	u32 num;
3299c2248fc9SDouglas Gilbert 	u32 ei_lba;
330019789100SFUJITA Tomonori 	int ret;
330187c715dcSDouglas Gilbert 	u64 lba;
3302b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
330387c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
330419789100SFUJITA Tomonori 
3305c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3306c2248fc9SDouglas Gilbert 	case READ_16:
3307c2248fc9SDouglas Gilbert 		ei_lba = 0;
3308c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3309c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3310c2248fc9SDouglas Gilbert 		check_prot = true;
3311c2248fc9SDouglas Gilbert 		break;
3312c2248fc9SDouglas Gilbert 	case READ_10:
3313c2248fc9SDouglas Gilbert 		ei_lba = 0;
3314c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3315c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3316c2248fc9SDouglas Gilbert 		check_prot = true;
3317c2248fc9SDouglas Gilbert 		break;
3318c2248fc9SDouglas Gilbert 	case READ_6:
3319c2248fc9SDouglas Gilbert 		ei_lba = 0;
3320c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3321c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3322c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3323c2248fc9SDouglas Gilbert 		check_prot = true;
3324c2248fc9SDouglas Gilbert 		break;
3325c2248fc9SDouglas Gilbert 	case READ_12:
3326c2248fc9SDouglas Gilbert 		ei_lba = 0;
3327c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3328c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3329c2248fc9SDouglas Gilbert 		check_prot = true;
3330c2248fc9SDouglas Gilbert 		break;
3331c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3332c2248fc9SDouglas Gilbert 		ei_lba = 0;
3333c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3334c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3335c2248fc9SDouglas Gilbert 		check_prot = false;
3336c2248fc9SDouglas Gilbert 		break;
3337c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3338c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3339c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3340c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3341c2248fc9SDouglas Gilbert 		check_prot = false;
3342c2248fc9SDouglas Gilbert 		break;
3343c2248fc9SDouglas Gilbert 	}
3344f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
33458475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3346c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3347c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3348c2248fc9SDouglas Gilbert 			return check_condition_result;
3349c2248fc9SDouglas Gilbert 		}
33508475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
33518475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3352c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3353c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3354c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3355c2248fc9SDouglas Gilbert 	}
33563a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
33573a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3358c2248fc9SDouglas Gilbert 		num /= 2;
33593a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3360c2248fc9SDouglas Gilbert 	}
3361c2248fc9SDouglas Gilbert 
33629447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
33639447b6ceSMartin K. Petersen 	if (ret)
33649447b6ceSMartin K. Petersen 		return ret;
3365f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3366d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3367d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3368c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3369c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3370c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3371c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3372c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
337332f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
337432f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3375c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3376c65b1445SDouglas Gilbert 		}
3377c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
33781da177e4SLinus Torvalds 		return check_condition_result;
33791da177e4SLinus Torvalds 	}
3380c6a44287SMartin K. Petersen 
33817109f370SDouglas Gilbert 	sdeb_read_lock(sip);
33826c78cc06SAkinobu Mita 
3383c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3384f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3385f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3386f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3387f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33887109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3389f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3390f7be6772SMartin K. Petersen 				return check_condition_result;
3391f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
33927109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3393f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3394c6a44287SMartin K. Petersen 				return illegal_condition_result;
3395c6a44287SMartin K. Petersen 			}
3396f7be6772SMartin K. Petersen 			break;
3397f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3398f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33997109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3400f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3401f7be6772SMartin K. Petersen 				return check_condition_result;
3402f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
34037109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3404f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3405f7be6772SMartin K. Petersen 				return illegal_condition_result;
3406f7be6772SMartin K. Petersen 			}
3407f7be6772SMartin K. Petersen 			break;
3408f7be6772SMartin K. Petersen 		}
3409c6a44287SMartin K. Petersen 	}
3410c6a44287SMartin K. Petersen 
341187c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
34127109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
3413f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3414a4517511SAkinobu Mita 		return DID_ERROR << 16;
3415a4517511SAkinobu Mita 
341642d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3417a4517511SAkinobu Mita 
34183a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
34193a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
34203a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
34213a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
34223a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3423c2248fc9SDouglas Gilbert 			return check_condition_result;
34243a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3425c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3426c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
34273a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3428c2248fc9SDouglas Gilbert 			return illegal_condition_result;
34293a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3430c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
34313a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3432c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3433c2248fc9SDouglas Gilbert 		}
3434c2248fc9SDouglas Gilbert 	}
3435a4517511SAkinobu Mita 	return 0;
34361da177e4SLinus Torvalds }
34371da177e4SLinus Torvalds 
3438c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3439395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3440c6a44287SMartin K. Petersen {
3441be4e11beSAkinobu Mita 	int ret;
34426ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3443be4e11beSAkinobu Mita 	void *daddr;
344465f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3445c6a44287SMartin K. Petersen 	int ppage_offset;
3446be4e11beSAkinobu Mita 	int dpage_offset;
3447be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3448be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3449c6a44287SMartin K. Petersen 
3450c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3451c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3452c6a44287SMartin K. Petersen 
3453be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3454be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3455be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3456be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3457be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3458c6a44287SMartin K. Petersen 
3459be4e11beSAkinobu Mita 	/* For each protection page */
3460be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3461be4e11beSAkinobu Mita 		dpage_offset = 0;
3462be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3463be4e11beSAkinobu Mita 			ret = 0x01;
3464be4e11beSAkinobu Mita 			goto out;
3465c6a44287SMartin K. Petersen 		}
3466c6a44287SMartin K. Petersen 
3467be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
34686ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3469be4e11beSAkinobu Mita 			/* If we're at the end of the current
3470be4e11beSAkinobu Mita 			 * data page advance to the next one
3471be4e11beSAkinobu Mita 			 */
3472be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3473be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3474be4e11beSAkinobu Mita 					ret = 0x01;
3475be4e11beSAkinobu Mita 					goto out;
3476be4e11beSAkinobu Mita 				}
3477be4e11beSAkinobu Mita 				dpage_offset = 0;
3478be4e11beSAkinobu Mita 			}
3479c6a44287SMartin K. Petersen 
3480be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3481be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3482be4e11beSAkinobu Mita 
3483f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3484be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3485c78be80dSMartin K. Petersen 				if (ret)
3486395cef03SMartin K. Petersen 					goto out;
3487395cef03SMartin K. Petersen 			}
3488395cef03SMartin K. Petersen 
3489c6a44287SMartin K. Petersen 			sector++;
3490395cef03SMartin K. Petersen 			ei_lba++;
3491773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3492c6a44287SMartin K. Petersen 		}
3493be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3494be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3495c6a44287SMartin K. Petersen 	}
3496be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3497c6a44287SMartin K. Petersen 
349865f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3499c6a44287SMartin K. Petersen 	dix_writes++;
3500c6a44287SMartin K. Petersen 
3501c6a44287SMartin K. Petersen 	return 0;
3502c6a44287SMartin K. Petersen 
3503c6a44287SMartin K. Petersen out:
3504c6a44287SMartin K. Petersen 	dif_errors++;
3505be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3506be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3507c6a44287SMartin K. Petersen 	return ret;
3508c6a44287SMartin K. Petersen }
3509c6a44287SMartin K. Petersen 
3510b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3511b90ebc3dSAkinobu Mita {
3512773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3513773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3514773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3515b90ebc3dSAkinobu Mita 	return lba;
3516b90ebc3dSAkinobu Mita }
3517b90ebc3dSAkinobu Mita 
3518b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3519b90ebc3dSAkinobu Mita {
3520773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3521a027b5b9SAkinobu Mita 
3522773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3523773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3524a027b5b9SAkinobu Mita 	return lba;
3525a027b5b9SAkinobu Mita }
3526a027b5b9SAkinobu Mita 
352787c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
352887c715dcSDouglas Gilbert 			      unsigned int *num)
352944d92694SMartin K. Petersen {
3530b90ebc3dSAkinobu Mita 	sector_t end;
3531b90ebc3dSAkinobu Mita 	unsigned int mapped;
3532b90ebc3dSAkinobu Mita 	unsigned long index;
3533b90ebc3dSAkinobu Mita 	unsigned long next;
353444d92694SMartin K. Petersen 
3535b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
353687c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
353744d92694SMartin K. Petersen 
353844d92694SMartin K. Petersen 	if (mapped)
353987c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
354044d92694SMartin K. Petersen 	else
354187c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
354244d92694SMartin K. Petersen 
3543b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
354444d92694SMartin K. Petersen 	*num = end - lba;
354544d92694SMartin K. Petersen 	return mapped;
354644d92694SMartin K. Petersen }
354744d92694SMartin K. Petersen 
354887c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
354987c715dcSDouglas Gilbert 		       unsigned int len)
355044d92694SMartin K. Petersen {
355144d92694SMartin K. Petersen 	sector_t end = lba + len;
355244d92694SMartin K. Petersen 
355344d92694SMartin K. Petersen 	while (lba < end) {
3554b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
355544d92694SMartin K. Petersen 
3556b90ebc3dSAkinobu Mita 		if (index < map_size)
355787c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
355844d92694SMartin K. Petersen 
3559b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
356044d92694SMartin K. Petersen 	}
356144d92694SMartin K. Petersen }
356244d92694SMartin K. Petersen 
356387c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
356487c715dcSDouglas Gilbert 			 unsigned int len)
356544d92694SMartin K. Petersen {
356644d92694SMartin K. Petersen 	sector_t end = lba + len;
356787c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
356844d92694SMartin K. Petersen 
356944d92694SMartin K. Petersen 	while (lba < end) {
3570b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
357144d92694SMartin K. Petersen 
3572b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3573773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3574b90ebc3dSAkinobu Mita 		    index < map_size) {
357587c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3576760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
357787c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3578760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3579773642d9SDouglas Gilbert 				       sdebug_sector_size *
3580773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3581be1dd78dSEric Sandeen 			}
358287c715dcSDouglas Gilbert 			if (sip->dif_storep) {
358387c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
358487c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3585773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3586e9926b43SAkinobu Mita 			}
3587b90ebc3dSAkinobu Mita 		}
3588b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
358944d92694SMartin K. Petersen 	}
359044d92694SMartin K. Petersen }
359144d92694SMartin K. Petersen 
3592fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
35931da177e4SLinus Torvalds {
359487c715dcSDouglas Gilbert 	bool check_prot;
3595c2248fc9SDouglas Gilbert 	u32 num;
3596c2248fc9SDouglas Gilbert 	u32 ei_lba;
359719789100SFUJITA Tomonori 	int ret;
359887c715dcSDouglas Gilbert 	u64 lba;
3599b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
360087c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
36011da177e4SLinus Torvalds 
3602c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3603c2248fc9SDouglas Gilbert 	case WRITE_16:
3604c2248fc9SDouglas Gilbert 		ei_lba = 0;
3605c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3606c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3607c2248fc9SDouglas Gilbert 		check_prot = true;
3608c2248fc9SDouglas Gilbert 		break;
3609c2248fc9SDouglas Gilbert 	case WRITE_10:
3610c2248fc9SDouglas Gilbert 		ei_lba = 0;
3611c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3612c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3613c2248fc9SDouglas Gilbert 		check_prot = true;
3614c2248fc9SDouglas Gilbert 		break;
3615c2248fc9SDouglas Gilbert 	case WRITE_6:
3616c2248fc9SDouglas Gilbert 		ei_lba = 0;
3617c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3618c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3619c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3620c2248fc9SDouglas Gilbert 		check_prot = true;
3621c2248fc9SDouglas Gilbert 		break;
3622c2248fc9SDouglas Gilbert 	case WRITE_12:
3623c2248fc9SDouglas Gilbert 		ei_lba = 0;
3624c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3625c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3626c2248fc9SDouglas Gilbert 		check_prot = true;
3627c2248fc9SDouglas Gilbert 		break;
3628c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3629c2248fc9SDouglas Gilbert 		ei_lba = 0;
3630c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3631c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3632c2248fc9SDouglas Gilbert 		check_prot = false;
3633c2248fc9SDouglas Gilbert 		break;
3634c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3635c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3636c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3637c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3638c2248fc9SDouglas Gilbert 		check_prot = false;
3639c2248fc9SDouglas Gilbert 		break;
3640c2248fc9SDouglas Gilbert 	}
3641f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
36428475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3643c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3644c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3645c2248fc9SDouglas Gilbert 			return check_condition_result;
3646c2248fc9SDouglas Gilbert 		}
36478475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
36488475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3649c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3650c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3651c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3652c2248fc9SDouglas Gilbert 	}
3653f0d1cf93SDouglas Gilbert 
36547109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3655f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3656f0d1cf93SDouglas Gilbert 	if (ret) {
36577109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3658f0d1cf93SDouglas Gilbert 		return ret;
3659f0d1cf93SDouglas Gilbert 	}
36606c78cc06SAkinobu Mita 
3661c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3662f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3663f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3664f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3665f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
36667109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3667f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3668c6a44287SMartin K. Petersen 				return illegal_condition_result;
3669f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36707109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3671f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3672f7be6772SMartin K. Petersen 				return check_condition_result;
3673f7be6772SMartin K. Petersen 			}
3674f7be6772SMartin K. Petersen 			break;
3675f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3676f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
36777109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3678f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3679f7be6772SMartin K. Petersen 				return illegal_condition_result;
3680f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36817109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3682f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3683f7be6772SMartin K. Petersen 				return check_condition_result;
3684f7be6772SMartin K. Petersen 			}
3685f7be6772SMartin K. Petersen 			break;
3686c6a44287SMartin K. Petersen 		}
3687c6a44287SMartin K. Petersen 	}
3688c6a44287SMartin K. Petersen 
368987c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3690f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
369187c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3692f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3693f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3694f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
36957109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3696f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3697773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3698c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3699c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3700c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3701cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3702773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
370344d92694SMartin K. Petersen 
37043a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
37053a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
37063a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
37073a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
37083a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3709c2248fc9SDouglas Gilbert 			return check_condition_result;
37103a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3711c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3712c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37133a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3714c2248fc9SDouglas Gilbert 			return illegal_condition_result;
37153a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3716c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37173a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3718c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3719c2248fc9SDouglas Gilbert 		}
3720c2248fc9SDouglas Gilbert 	}
37211da177e4SLinus Torvalds 	return 0;
37221da177e4SLinus Torvalds }
37231da177e4SLinus Torvalds 
3724481b5e5cSDouglas Gilbert /*
3725481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3726481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3727481b5e5cSDouglas Gilbert  */
3728481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3729481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3730481b5e5cSDouglas Gilbert {
3731481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3732481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3733481b5e5cSDouglas Gilbert 	u8 *up;
3734b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3735481b5e5cSDouglas Gilbert 	u8 wrprotect;
3736481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3737481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3738481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3739481b5e5cSDouglas Gilbert 	u32 ei_lba;
3740481b5e5cSDouglas Gilbert 	u64 lba;
3741481b5e5cSDouglas Gilbert 	int ret, res;
3742481b5e5cSDouglas Gilbert 	bool is_16;
3743481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3744481b5e5cSDouglas Gilbert 
3745481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3746481b5e5cSDouglas Gilbert 		is_16 = false;
3747481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3748481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3749481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3750481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3751481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3752481b5e5cSDouglas Gilbert 		is_16 = true;
3753481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3754481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3755481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3756481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3757481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3758481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3759481b5e5cSDouglas Gilbert 			    wrprotect) {
3760481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3761481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3762481b5e5cSDouglas Gilbert 			}
3763481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3764481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3765481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3766481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3767481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3768481b5e5cSDouglas Gilbert 		}
3769481b5e5cSDouglas Gilbert 	}
3770481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3771481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3772481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3773481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3774481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3775481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3776481b5e5cSDouglas Gilbert 				my_name, __func__);
3777481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3778481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3779481b5e5cSDouglas Gilbert 	}
3780481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3781481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3782481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3783481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3784481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3785481b5e5cSDouglas Gilbert 				my_name, __func__);
3786481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3787481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3788481b5e5cSDouglas Gilbert 	}
3789216e1797SHarshit Mogalapalli 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN);
3790481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3791481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3792481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3793481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3794481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3795481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3796481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3797481b5e5cSDouglas Gilbert 	if (res == -1) {
3798481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3799481b5e5cSDouglas Gilbert 		goto err_out;
3800481b5e5cSDouglas Gilbert 	}
3801481b5e5cSDouglas Gilbert 
38027109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3803481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3804481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3805481b5e5cSDouglas Gilbert 	cum_lb = 0;
3806481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3807481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3808481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3809481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3810481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3811481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3812481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3813481b5e5cSDouglas Gilbert 		if (num == 0)
3814481b5e5cSDouglas Gilbert 			continue;
38159447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3816481b5e5cSDouglas Gilbert 		if (ret)
3817481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3818481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3819481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3820481b5e5cSDouglas Gilbert 
3821481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3822481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3823481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3824481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3825481b5e5cSDouglas Gilbert 				    my_name, __func__);
3826481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3827481b5e5cSDouglas Gilbert 					0);
3828481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3829481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3830481b5e5cSDouglas Gilbert 		}
3831481b5e5cSDouglas Gilbert 
3832481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3833481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3834481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3835481b5e5cSDouglas Gilbert 							 ei_lba);
3836481b5e5cSDouglas Gilbert 
3837481b5e5cSDouglas Gilbert 			if (prot_ret) {
3838481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3839481b5e5cSDouglas Gilbert 						prot_ret);
3840481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3841481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3842481b5e5cSDouglas Gilbert 			}
3843481b5e5cSDouglas Gilbert 		}
3844481b5e5cSDouglas Gilbert 
384587c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3846f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3847f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3848f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3849481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
385087c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3851481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3852481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3853481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3854481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3855481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3856481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3857481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3858481b5e5cSDouglas Gilbert 
38593a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
38603a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
38613a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
38623a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
38633a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
38643a90a63dSDouglas Gilbert 				ret = check_condition_result;
3865481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38663a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3867481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
38683a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
38693a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3870481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3871481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38723a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
38733a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
38743a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3875481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3876481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3877481b5e5cSDouglas Gilbert 			}
3878481b5e5cSDouglas Gilbert 		}
3879481b5e5cSDouglas Gilbert 		sg_off += num_by;
3880481b5e5cSDouglas Gilbert 		cum_lb += num;
3881481b5e5cSDouglas Gilbert 	}
3882481b5e5cSDouglas Gilbert 	ret = 0;
3883481b5e5cSDouglas Gilbert err_out_unlock:
38847109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3885481b5e5cSDouglas Gilbert err_out:
3886481b5e5cSDouglas Gilbert 	kfree(lrdp);
3887481b5e5cSDouglas Gilbert 	return ret;
3888481b5e5cSDouglas Gilbert }
3889481b5e5cSDouglas Gilbert 
3890fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3891fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
389244d92694SMartin K. Petersen {
3893f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3894f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
389544d92694SMartin K. Petersen 	unsigned long long i;
389640d07b52SDouglas Gilbert 	u64 block, lbaa;
389787c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
389887c715dcSDouglas Gilbert 	int ret;
389987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3900b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
390140d07b52SDouglas Gilbert 	u8 *fs1p;
390287c715dcSDouglas Gilbert 	u8 *fsp;
390344d92694SMartin K. Petersen 
39047109f370SDouglas Gilbert 	sdeb_write_lock(sip);
390544d92694SMartin K. Petersen 
3906f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3907f0d1cf93SDouglas Gilbert 	if (ret) {
39087109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3909f0d1cf93SDouglas Gilbert 		return ret;
3910f0d1cf93SDouglas Gilbert 	}
3911f0d1cf93SDouglas Gilbert 
39129ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
391387c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
391444d92694SMartin K. Petersen 		goto out;
391544d92694SMartin K. Petersen 	}
391640d07b52SDouglas Gilbert 	lbaa = lba;
391740d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3918c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
391987c715dcSDouglas Gilbert 	fsp = sip->storep;
392087c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3921c2248fc9SDouglas Gilbert 	if (ndob) {
392240d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3923c2248fc9SDouglas Gilbert 		ret = 0;
3924c2248fc9SDouglas Gilbert 	} else
392540d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
392644d92694SMartin K. Petersen 
392744d92694SMartin K. Petersen 	if (-1 == ret) {
39287109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3929773642d9SDouglas Gilbert 		return DID_ERROR << 16;
393040d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3931c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3932e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
393340d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
393444d92694SMartin K. Petersen 
393544d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
393640d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
393740d07b52SDouglas Gilbert 		lbaa = lba + i;
393840d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
393987c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
394040d07b52SDouglas Gilbert 	}
39419ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
394287c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3943f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3944f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3945f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
394644d92694SMartin K. Petersen out:
39477109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
394844d92694SMartin K. Petersen 
394944d92694SMartin K. Petersen 	return 0;
395044d92694SMartin K. Petersen }
395144d92694SMartin K. Petersen 
3952fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3953fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3954c2248fc9SDouglas Gilbert {
3955c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3956c2248fc9SDouglas Gilbert 	u32 lba;
3957c2248fc9SDouglas Gilbert 	u16 num;
3958c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3959c2248fc9SDouglas Gilbert 	bool unmap = false;
3960c2248fc9SDouglas Gilbert 
3961c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3962773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3963c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3964c2248fc9SDouglas Gilbert 			return check_condition_result;
3965c2248fc9SDouglas Gilbert 		} else
3966c2248fc9SDouglas Gilbert 			unmap = true;
3967c2248fc9SDouglas Gilbert 	}
3968c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3969c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3970773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3971c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3972c2248fc9SDouglas Gilbert 		return check_condition_result;
3973c2248fc9SDouglas Gilbert 	}
3974c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3975c2248fc9SDouglas Gilbert }
3976c2248fc9SDouglas Gilbert 
3977fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3978fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3979c2248fc9SDouglas Gilbert {
3980c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3981c2248fc9SDouglas Gilbert 	u64 lba;
3982c2248fc9SDouglas Gilbert 	u32 num;
3983c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3984c2248fc9SDouglas Gilbert 	bool unmap = false;
3985c2248fc9SDouglas Gilbert 	bool ndob = false;
3986c2248fc9SDouglas Gilbert 
3987c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3988773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3989c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3990c2248fc9SDouglas Gilbert 			return check_condition_result;
3991c2248fc9SDouglas Gilbert 		} else
3992c2248fc9SDouglas Gilbert 			unmap = true;
3993c2248fc9SDouglas Gilbert 	}
3994c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3995c2248fc9SDouglas Gilbert 		ndob = true;
3996c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3997c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3998773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3999c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
4000c2248fc9SDouglas Gilbert 		return check_condition_result;
4001c2248fc9SDouglas Gilbert 	}
4002c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
4003c2248fc9SDouglas Gilbert }
4004c2248fc9SDouglas Gilbert 
4005acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
4006acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
4007acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
4008fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
4009fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
4010acafd0b9SEwan D. Milne {
4011acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
4012acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
4013acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
4014acafd0b9SEwan D. Milne 	u8 mode;
4015acafd0b9SEwan D. Milne 
4016acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
4017acafd0b9SEwan D. Milne 	switch (mode) {
4018acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
4019acafd0b9SEwan D. Milne 		/* set UAs on this device only */
4020acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4021acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
4022acafd0b9SEwan D. Milne 		break;
4023acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
4024acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
4025acafd0b9SEwan D. Milne 		break;
4026acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
4027acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
4028acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4029acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4030acafd0b9SEwan D. Milne 				    dev_list)
4031acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
4032acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
4033acafd0b9SEwan D. Milne 				if (devip != dp)
4034acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
4035acafd0b9SEwan D. Milne 						dp->uas_bm);
4036acafd0b9SEwan D. Milne 			}
4037acafd0b9SEwan D. Milne 		break;
4038acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
4039acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
4040acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4041acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4042acafd0b9SEwan D. Milne 				    dev_list)
4043acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
4044acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
4045acafd0b9SEwan D. Milne 					dp->uas_bm);
4046acafd0b9SEwan D. Milne 		break;
4047acafd0b9SEwan D. Milne 	default:
4048acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
4049acafd0b9SEwan D. Milne 		break;
4050acafd0b9SEwan D. Milne 	}
4051acafd0b9SEwan D. Milne 	return 0;
4052acafd0b9SEwan D. Milne }
4053acafd0b9SEwan D. Milne 
4054fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
4055fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
405638d5c833SDouglas Gilbert {
405738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
405838d5c833SDouglas Gilbert 	u8 *arr;
4059b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
406038d5c833SDouglas Gilbert 	u64 lba;
406138d5c833SDouglas Gilbert 	u32 dnum;
4062773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
406338d5c833SDouglas Gilbert 	u8 num;
406438d5c833SDouglas Gilbert 	int ret;
4065d467d31fSDouglas Gilbert 	int retval = 0;
406638d5c833SDouglas Gilbert 
4067d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
406838d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
406938d5c833SDouglas Gilbert 	if (0 == num)
407038d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
40718475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
407238d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
407338d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
407438d5c833SDouglas Gilbert 		return check_condition_result;
407538d5c833SDouglas Gilbert 	}
40768475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
40778475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
407838d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
407938d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
408038d5c833SDouglas Gilbert 			    "to DIF device\n");
40819447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
40829447b6ceSMartin K. Petersen 	if (ret)
40839447b6ceSMartin K. Petersen 		return ret;
4084d467d31fSDouglas Gilbert 	dnum = 2 * num;
40856396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
4086d467d31fSDouglas Gilbert 	if (NULL == arr) {
4087d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4088d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
4089d467d31fSDouglas Gilbert 		return check_condition_result;
4090d467d31fSDouglas Gilbert 	}
409138d5c833SDouglas Gilbert 
40927109f370SDouglas Gilbert 	sdeb_write_lock(sip);
409338d5c833SDouglas Gilbert 
409487c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
409538d5c833SDouglas Gilbert 	if (ret == -1) {
4096d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
4097d467d31fSDouglas Gilbert 		goto cleanup;
4098773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
409938d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
410038d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
410138d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
4102c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
410338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4104d467d31fSDouglas Gilbert 		retval = check_condition_result;
4105d467d31fSDouglas Gilbert 		goto cleanup;
410638d5c833SDouglas Gilbert 	}
410738d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
410887c715dcSDouglas Gilbert 		map_region(sip, lba, num);
4109d467d31fSDouglas Gilbert cleanup:
41107109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4111d467d31fSDouglas Gilbert 	kfree(arr);
4112d467d31fSDouglas Gilbert 	return retval;
411338d5c833SDouglas Gilbert }
411438d5c833SDouglas Gilbert 
411544d92694SMartin K. Petersen struct unmap_block_desc {
411644d92694SMartin K. Petersen 	__be64	lba;
411744d92694SMartin K. Petersen 	__be32	blocks;
411844d92694SMartin K. Petersen 	__be32	__reserved;
411944d92694SMartin K. Petersen };
412044d92694SMartin K. Petersen 
4121fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
412244d92694SMartin K. Petersen {
412344d92694SMartin K. Petersen 	unsigned char *buf;
412444d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
4125b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
412644d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
412744d92694SMartin K. Petersen 	int ret;
412844d92694SMartin K. Petersen 
4129c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
4130c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
4131c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
4132c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
413344d92694SMartin K. Petersen 
413444d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
4135773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
4136c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
413744d92694SMartin K. Petersen 		return check_condition_result;
4138c2248fc9SDouglas Gilbert 	}
413944d92694SMartin K. Petersen 
4140b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
4141c2248fc9SDouglas Gilbert 	if (!buf) {
4142c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4143c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
4144c2248fc9SDouglas Gilbert 		return check_condition_result;
4145c2248fc9SDouglas Gilbert 	}
4146c2248fc9SDouglas Gilbert 
4147c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
414844d92694SMartin K. Petersen 
414944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
415044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
415144d92694SMartin K. Petersen 
415244d92694SMartin K. Petersen 	desc = (void *)&buf[8];
415344d92694SMartin K. Petersen 
41547109f370SDouglas Gilbert 	sdeb_write_lock(sip);
41556c78cc06SAkinobu Mita 
415644d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
415744d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
415844d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
415944d92694SMartin K. Petersen 
41609447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
416144d92694SMartin K. Petersen 		if (ret)
416244d92694SMartin K. Petersen 			goto out;
416344d92694SMartin K. Petersen 
416487c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
416544d92694SMartin K. Petersen 	}
416644d92694SMartin K. Petersen 
416744d92694SMartin K. Petersen 	ret = 0;
416844d92694SMartin K. Petersen 
416944d92694SMartin K. Petersen out:
41707109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
417144d92694SMartin K. Petersen 	kfree(buf);
417244d92694SMartin K. Petersen 
417344d92694SMartin K. Petersen 	return ret;
417444d92694SMartin K. Petersen }
417544d92694SMartin K. Petersen 
417644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
417744d92694SMartin K. Petersen 
4178fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4179fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
418044d92694SMartin K. Petersen {
4181c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4182c2248fc9SDouglas Gilbert 	u64 lba;
4183c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
418444d92694SMartin K. Petersen 	int ret;
418587c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
418644d92694SMartin K. Petersen 
4187c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4188c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
418944d92694SMartin K. Petersen 
419044d92694SMartin K. Petersen 	if (alloc_len < 24)
419144d92694SMartin K. Petersen 		return 0;
419244d92694SMartin K. Petersen 
41939447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
419444d92694SMartin K. Petersen 	if (ret)
419544d92694SMartin K. Petersen 		return ret;
419644d92694SMartin K. Petersen 
4197b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4198b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4199b6ff8ca7SDouglas Gilbert 
420087c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4201b6ff8ca7SDouglas Gilbert 	} else {
4202c2248fc9SDouglas Gilbert 		mapped = 1;
4203c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4204c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4205c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4206c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4207c2248fc9SDouglas Gilbert 		else
4208c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4209c2248fc9SDouglas Gilbert 	}
421044d92694SMartin K. Petersen 
421144d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4212c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4213c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4214c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4215c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
421644d92694SMartin K. Petersen 
4217c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
421844d92694SMartin K. Petersen }
421944d92694SMartin K. Petersen 
422080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
422180c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
422280c49563SDouglas Gilbert {
42234f2c8bf6SDouglas Gilbert 	int res = 0;
422480c49563SDouglas Gilbert 	u64 lba;
422580c49563SDouglas Gilbert 	u32 num_blocks;
422680c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
422780c49563SDouglas Gilbert 
422880c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
422980c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
423080c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
423180c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
423280c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
423380c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
423480c49563SDouglas Gilbert 	}
423580c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
423680c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
423780c49563SDouglas Gilbert 		return check_condition_result;
423880c49563SDouglas Gilbert 	}
4239fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
42404f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
42414f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
42424f2c8bf6SDouglas Gilbert 		write_since_sync = false;
42434f2c8bf6SDouglas Gilbert 	return res;
424480c49563SDouglas Gilbert }
424580c49563SDouglas Gilbert 
4246ed9f3e25SDouglas Gilbert /*
4247ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4248ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4249ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4250ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4251ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4252ed9f3e25SDouglas Gilbert  */
4253ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4254ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4255ed9f3e25SDouglas Gilbert {
4256ed9f3e25SDouglas Gilbert 	int res = 0;
4257ed9f3e25SDouglas Gilbert 	u64 lba;
4258ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4259ed9f3e25SDouglas Gilbert 	u32 nblks;
4260ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4261b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4262b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4263ed9f3e25SDouglas Gilbert 
4264ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4265ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4266ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4267ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4268ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4269ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4270ed9f3e25SDouglas Gilbert 	}
4271ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4272ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4273ed9f3e25SDouglas Gilbert 		return check_condition_result;
4274ed9f3e25SDouglas Gilbert 	}
4275ed9f3e25SDouglas Gilbert 	if (!fsp)
4276ed9f3e25SDouglas Gilbert 		goto fini;
4277ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4278ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4279ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4280ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4281ed9f3e25SDouglas Gilbert 
4282ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
42837109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4284ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4285ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4286ed9f3e25SDouglas Gilbert 	if (rest)
4287ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
42887109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4289ed9f3e25SDouglas Gilbert fini:
4290ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4291ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4292ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4293ed9f3e25SDouglas Gilbert }
4294ed9f3e25SDouglas Gilbert 
4295fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4296fb0cc8d1SDouglas Gilbert 
42978d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
42988d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
42998d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
43008d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
43018d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
43028d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
43038d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
43048d039e22SDouglas Gilbert  */
43051da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
43061da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
43071da177e4SLinus Torvalds {
430801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
43098d039e22SDouglas Gilbert 	unsigned int alloc_len;
43108d039e22SDouglas Gilbert 	unsigned char select_report;
43118d039e22SDouglas Gilbert 	u64 lun;
43128d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4313fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
43148d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
43158d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
43168d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
43178d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4318fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4319fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4320fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
43211da177e4SLinus Torvalds 
432219c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
43238d039e22SDouglas Gilbert 
43248d039e22SDouglas Gilbert 	select_report = cmd[2];
43258d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
43268d039e22SDouglas Gilbert 
43278d039e22SDouglas Gilbert 	if (alloc_len < 4) {
43288d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
43298d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
43301da177e4SLinus Torvalds 		return check_condition_result;
43311da177e4SLinus Torvalds 	}
43328d039e22SDouglas Gilbert 
43338d039e22SDouglas Gilbert 	switch (select_report) {
43348d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4335773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43368d039e22SDouglas Gilbert 		wlun_cnt = 0;
43378d039e22SDouglas Gilbert 		break;
43388d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4339c65b1445SDouglas Gilbert 		lun_cnt = 0;
43408d039e22SDouglas Gilbert 		wlun_cnt = 1;
43418d039e22SDouglas Gilbert 		break;
43428d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
43438d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43448d039e22SDouglas Gilbert 		wlun_cnt = 1;
43458d039e22SDouglas Gilbert 		break;
43468d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
43478d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
43488d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
43498d039e22SDouglas Gilbert 	default:
43508d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
43518d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
43528d039e22SDouglas Gilbert 		return check_condition_result;
43538d039e22SDouglas Gilbert 	}
43548d039e22SDouglas Gilbert 
43558d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4356c65b1445SDouglas Gilbert 		--lun_cnt;
43578d039e22SDouglas Gilbert 
43588d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4359fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4360fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
43618d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
43628d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
43638d039e22SDouglas Gilbert 
4364fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
43658d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4366fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4367fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4368fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4369fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4370fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4371fb0cc8d1SDouglas Gilbert 			++lun_p;
4372fb0cc8d1SDouglas Gilbert 			j = 1;
4373fb0cc8d1SDouglas Gilbert 		}
4374fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4375fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4376fb0cc8d1SDouglas Gilbert 				break;
4377fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4378ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4379ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4380fb0cc8d1SDouglas Gilbert 		}
4381fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4382fb0cc8d1SDouglas Gilbert 			break;
4383fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4384fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4385fb0cc8d1SDouglas Gilbert 		if (res)
4386fb0cc8d1SDouglas Gilbert 			return res;
4387fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4388fb0cc8d1SDouglas Gilbert 	}
4389fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4390fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4391fb0cc8d1SDouglas Gilbert 		++j;
4392fb0cc8d1SDouglas Gilbert 	}
4393fb0cc8d1SDouglas Gilbert 	if (j > 0)
4394fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
43958d039e22SDouglas Gilbert 	return res;
43961da177e4SLinus Torvalds }
43971da177e4SLinus Torvalds 
4398c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4399c3e2fe92SDouglas Gilbert {
4400c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4401c3e2fe92SDouglas Gilbert 	u8 bytchk;
4402c3e2fe92SDouglas Gilbert 	int ret, j;
4403c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4404c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4405c3e2fe92SDouglas Gilbert 	u64 lba;
4406c3e2fe92SDouglas Gilbert 	u8 *arr;
4407c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4408b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4409c3e2fe92SDouglas Gilbert 
4410c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4411c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4412c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4413c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4414c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4415c3e2fe92SDouglas Gilbert 		return check_condition_result;
4416c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4417c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4418c3e2fe92SDouglas Gilbert 	}
4419c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4420c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4421c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4422c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4423c3e2fe92SDouglas Gilbert 		break;
4424c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4425c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4426c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4427c3e2fe92SDouglas Gilbert 		break;
4428c3e2fe92SDouglas Gilbert 	default:
4429c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4430c3e2fe92SDouglas Gilbert 		return check_condition_result;
4431c3e2fe92SDouglas Gilbert 	}
44323344b58bSGeorge Kennedy 	if (vnum == 0)
44333344b58bSGeorge Kennedy 		return 0;	/* not an error */
4434c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4435c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4436c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4437c3e2fe92SDouglas Gilbert 	if (ret)
4438c3e2fe92SDouglas Gilbert 		return ret;
4439c3e2fe92SDouglas Gilbert 
4440ed0f17b7SHarshit Mogalapalli 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN);
4441c3e2fe92SDouglas Gilbert 	if (!arr) {
4442c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4443c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4444c3e2fe92SDouglas Gilbert 		return check_condition_result;
4445c3e2fe92SDouglas Gilbert 	}
4446c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
44477109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4448c3e2fe92SDouglas Gilbert 
4449c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4450c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4451c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4452c3e2fe92SDouglas Gilbert 		goto cleanup;
4453c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4454c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4455c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4456c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4457c3e2fe92SDouglas Gilbert 	}
4458c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4459c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4460c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4461c3e2fe92SDouglas Gilbert 	}
4462c3e2fe92SDouglas Gilbert 	ret = 0;
4463c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4464c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4465c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4466c3e2fe92SDouglas Gilbert 		goto cleanup;
4467c3e2fe92SDouglas Gilbert 	}
4468c3e2fe92SDouglas Gilbert cleanup:
44697109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4470c3e2fe92SDouglas Gilbert 	kfree(arr);
4471c3e2fe92SDouglas Gilbert 	return ret;
4472c3e2fe92SDouglas Gilbert }
4473c3e2fe92SDouglas Gilbert 
4474f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4475f0d1cf93SDouglas Gilbert 
4476897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */
4477f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4478f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4479f0d1cf93SDouglas Gilbert {
44804a5fc1c6SDamien Le Moal 	unsigned int rep_max_zones, nrz = 0;
4481f0d1cf93SDouglas Gilbert 	int ret = 0;
4482f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4483f0d1cf93SDouglas Gilbert 	bool partial;
4484f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4485f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4486f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
44874a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp = NULL;
4488b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4489f0d1cf93SDouglas Gilbert 
4490f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4491f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4492f0d1cf93SDouglas Gilbert 		return check_condition_result;
4493f0d1cf93SDouglas Gilbert 	}
4494f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4495f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
44963344b58bSGeorge Kennedy 	if (alloc_len == 0)
44973344b58bSGeorge Kennedy 		return 0;	/* not an error */
4498f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4499f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4500f0d1cf93SDouglas Gilbert 
4501f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4502f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4503f0d1cf93SDouglas Gilbert 		return check_condition_result;
4504f0d1cf93SDouglas Gilbert 	}
4505f0d1cf93SDouglas Gilbert 
45064a5fc1c6SDamien Le Moal 	rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
4507f0d1cf93SDouglas Gilbert 
450807f2ca13SHarshit Mogalapalli 	arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
4509f0d1cf93SDouglas Gilbert 	if (!arr) {
4510f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4511f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4512f0d1cf93SDouglas Gilbert 		return check_condition_result;
4513f0d1cf93SDouglas Gilbert 	}
4514f0d1cf93SDouglas Gilbert 
45157109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4516f0d1cf93SDouglas Gilbert 
4517f0d1cf93SDouglas Gilbert 	desc = arr + 64;
45184a5fc1c6SDamien Le Moal 	for (lba = zs_lba; lba < sdebug_capacity;
45194a5fc1c6SDamien Le Moal 	     lba = zsp->z_start + zsp->z_size) {
45204a5fc1c6SDamien Le Moal 		if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba))
4521f0d1cf93SDouglas Gilbert 			break;
4522f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4523f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4524f0d1cf93SDouglas Gilbert 		case 0x00:
4525f0d1cf93SDouglas Gilbert 			/* All zones */
4526f0d1cf93SDouglas Gilbert 			break;
4527f0d1cf93SDouglas Gilbert 		case 0x01:
4528f0d1cf93SDouglas Gilbert 			/* Empty zones */
4529f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4530f0d1cf93SDouglas Gilbert 				continue;
4531f0d1cf93SDouglas Gilbert 			break;
4532f0d1cf93SDouglas Gilbert 		case 0x02:
4533f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4534f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4535f0d1cf93SDouglas Gilbert 				continue;
4536f0d1cf93SDouglas Gilbert 			break;
4537f0d1cf93SDouglas Gilbert 		case 0x03:
4538f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4539f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4540f0d1cf93SDouglas Gilbert 				continue;
4541f0d1cf93SDouglas Gilbert 			break;
4542f0d1cf93SDouglas Gilbert 		case 0x04:
4543f0d1cf93SDouglas Gilbert 			/* Closed zones */
4544f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4545f0d1cf93SDouglas Gilbert 				continue;
4546f0d1cf93SDouglas Gilbert 			break;
4547f0d1cf93SDouglas Gilbert 		case 0x05:
4548f0d1cf93SDouglas Gilbert 			/* Full zones */
4549f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4550f0d1cf93SDouglas Gilbert 				continue;
4551f0d1cf93SDouglas Gilbert 			break;
4552f0d1cf93SDouglas Gilbert 		case 0x06:
4553f0d1cf93SDouglas Gilbert 		case 0x07:
4554f0d1cf93SDouglas Gilbert 		case 0x10:
4555f0d1cf93SDouglas Gilbert 			/*
455664e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
455764e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4558f0d1cf93SDouglas Gilbert 			 */
4559f0d1cf93SDouglas Gilbert 			continue;
456064e14eceSDamien Le Moal 		case 0x11:
456164e14eceSDamien Le Moal 			/* non-seq-resource set */
456264e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
456364e14eceSDamien Le Moal 				continue;
456464e14eceSDamien Le Moal 			break;
45654a5fc1c6SDamien Le Moal 		case 0x3e:
45664a5fc1c6SDamien Le Moal 			/* All zones except gap zones. */
45674a5fc1c6SDamien Le Moal 			if (zbc_zone_is_gap(zsp))
45684a5fc1c6SDamien Le Moal 				continue;
45694a5fc1c6SDamien Le Moal 			break;
4570f0d1cf93SDouglas Gilbert 		case 0x3f:
4571f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
45724a5fc1c6SDamien Le Moal 			if (zbc_zone_is_seq(zsp))
4573f0d1cf93SDouglas Gilbert 				continue;
4574f0d1cf93SDouglas Gilbert 			break;
4575f0d1cf93SDouglas Gilbert 		default:
4576f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4577f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4578f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4579f0d1cf93SDouglas Gilbert 			goto fini;
4580f0d1cf93SDouglas Gilbert 		}
4581f0d1cf93SDouglas Gilbert 
4582f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4583f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
458464e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4585f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
458664e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
458764e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4588f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4589f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4590f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4591f0d1cf93SDouglas Gilbert 			desc += 64;
4592f0d1cf93SDouglas Gilbert 		}
4593f0d1cf93SDouglas Gilbert 
4594f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4595f0d1cf93SDouglas Gilbert 			break;
4596f0d1cf93SDouglas Gilbert 
4597f0d1cf93SDouglas Gilbert 		nrz++;
4598f0d1cf93SDouglas Gilbert 	}
4599f0d1cf93SDouglas Gilbert 
4600f0d1cf93SDouglas Gilbert 	/* Report header */
46014a5fc1c6SDamien Le Moal 	/* Zone list length. */
4602f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
46034a5fc1c6SDamien Le Moal 	/* Maximum LBA */
4604f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
46054a5fc1c6SDamien Le Moal 	/* Zone starting LBA granularity. */
46064a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
46074a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, arr + 16);
4608f0d1cf93SDouglas Gilbert 
4609f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
461036e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4611f0d1cf93SDouglas Gilbert 
4612f0d1cf93SDouglas Gilbert fini:
46137109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4614f0d1cf93SDouglas Gilbert 	kfree(arr);
4615f0d1cf93SDouglas Gilbert 	return ret;
4616f0d1cf93SDouglas Gilbert }
4617f0d1cf93SDouglas Gilbert 
4618f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4619f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4620f0d1cf93SDouglas Gilbert {
4621f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4622f0d1cf93SDouglas Gilbert 	unsigned int i;
4623f0d1cf93SDouglas Gilbert 
4624f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4625f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4626f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4627f0d1cf93SDouglas Gilbert 	}
4628f0d1cf93SDouglas Gilbert }
4629f0d1cf93SDouglas Gilbert 
4630f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4631f0d1cf93SDouglas Gilbert {
4632f0d1cf93SDouglas Gilbert 	int res = 0;
4633f0d1cf93SDouglas Gilbert 	u64 z_id;
4634f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4635f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4636f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4637f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4638b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4639f0d1cf93SDouglas Gilbert 
4640f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4641f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4642f0d1cf93SDouglas Gilbert 		return check_condition_result;
4643f0d1cf93SDouglas Gilbert 	}
4644f0d1cf93SDouglas Gilbert 
46457109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4646f0d1cf93SDouglas Gilbert 
4647f0d1cf93SDouglas Gilbert 	if (all) {
4648f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4649f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4650f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4651f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4652f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4653f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4654f0d1cf93SDouglas Gilbert 			goto fini;
4655f0d1cf93SDouglas Gilbert 		}
4656f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4657f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4658f0d1cf93SDouglas Gilbert 		goto fini;
4659f0d1cf93SDouglas Gilbert 	}
4660f0d1cf93SDouglas Gilbert 
4661f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4662f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4663f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4664f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4665f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4666f0d1cf93SDouglas Gilbert 		goto fini;
4667f0d1cf93SDouglas Gilbert 	}
4668f0d1cf93SDouglas Gilbert 
4669f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4670f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4671f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4672f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4673f0d1cf93SDouglas Gilbert 		goto fini;
4674f0d1cf93SDouglas Gilbert 	}
4675f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4676f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4677f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4678f0d1cf93SDouglas Gilbert 		goto fini;
4679f0d1cf93SDouglas Gilbert 	}
4680f0d1cf93SDouglas Gilbert 
4681f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4682f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4683f0d1cf93SDouglas Gilbert 		goto fini;
4684f0d1cf93SDouglas Gilbert 
4685f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4686f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4687f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4688f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4689f0d1cf93SDouglas Gilbert 		goto fini;
4690f0d1cf93SDouglas Gilbert 	}
4691f0d1cf93SDouglas Gilbert 
4692f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4693f0d1cf93SDouglas Gilbert fini:
46947109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4695f0d1cf93SDouglas Gilbert 	return res;
4696f0d1cf93SDouglas Gilbert }
4697f0d1cf93SDouglas Gilbert 
4698f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4699f0d1cf93SDouglas Gilbert {
4700f0d1cf93SDouglas Gilbert 	unsigned int i;
4701f0d1cf93SDouglas Gilbert 
4702f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4703f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4704f0d1cf93SDouglas Gilbert }
4705f0d1cf93SDouglas Gilbert 
4706f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4707f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4708f0d1cf93SDouglas Gilbert {
4709f0d1cf93SDouglas Gilbert 	int res = 0;
4710f0d1cf93SDouglas Gilbert 	u64 z_id;
4711f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4712f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4713f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4714b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4715f0d1cf93SDouglas Gilbert 
4716f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4717f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4718f0d1cf93SDouglas Gilbert 		return check_condition_result;
4719f0d1cf93SDouglas Gilbert 	}
4720f0d1cf93SDouglas Gilbert 
47217109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4722f0d1cf93SDouglas Gilbert 
4723f0d1cf93SDouglas Gilbert 	if (all) {
4724f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4725f0d1cf93SDouglas Gilbert 		goto fini;
4726f0d1cf93SDouglas Gilbert 	}
4727f0d1cf93SDouglas Gilbert 
4728f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4729f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4730f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4731f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4732f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4733f0d1cf93SDouglas Gilbert 		goto fini;
4734f0d1cf93SDouglas Gilbert 	}
4735f0d1cf93SDouglas Gilbert 
4736f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4737f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4738f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4739f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4740f0d1cf93SDouglas Gilbert 		goto fini;
4741f0d1cf93SDouglas Gilbert 	}
4742f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4743f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4744f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4745f0d1cf93SDouglas Gilbert 		goto fini;
4746f0d1cf93SDouglas Gilbert 	}
4747f0d1cf93SDouglas Gilbert 
4748f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4749f0d1cf93SDouglas Gilbert fini:
47507109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4751f0d1cf93SDouglas Gilbert 	return res;
4752f0d1cf93SDouglas Gilbert }
4753f0d1cf93SDouglas Gilbert 
4754f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4755f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4756f0d1cf93SDouglas Gilbert {
4757f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4758f0d1cf93SDouglas Gilbert 
4759f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4760f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4761f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4762f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4763f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4764f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4765f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4766f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4767f0d1cf93SDouglas Gilbert 	}
4768f0d1cf93SDouglas Gilbert }
4769f0d1cf93SDouglas Gilbert 
4770f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4771f0d1cf93SDouglas Gilbert {
4772f0d1cf93SDouglas Gilbert 	unsigned int i;
4773f0d1cf93SDouglas Gilbert 
4774f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4775f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4776f0d1cf93SDouglas Gilbert }
4777f0d1cf93SDouglas Gilbert 
4778f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4779f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4780f0d1cf93SDouglas Gilbert {
4781f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4782f0d1cf93SDouglas Gilbert 	int res = 0;
4783f0d1cf93SDouglas Gilbert 	u64 z_id;
4784f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4785f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4786b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4787f0d1cf93SDouglas Gilbert 
4788f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4789f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4790f0d1cf93SDouglas Gilbert 		return check_condition_result;
4791f0d1cf93SDouglas Gilbert 	}
4792f0d1cf93SDouglas Gilbert 
47937109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4794f0d1cf93SDouglas Gilbert 
4795f0d1cf93SDouglas Gilbert 	if (all) {
4796f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4797f0d1cf93SDouglas Gilbert 		goto fini;
4798f0d1cf93SDouglas Gilbert 	}
4799f0d1cf93SDouglas Gilbert 
4800f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4801f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4802f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4803f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4804f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4805f0d1cf93SDouglas Gilbert 		goto fini;
4806f0d1cf93SDouglas Gilbert 	}
4807f0d1cf93SDouglas Gilbert 
4808f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4809f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4810f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4811f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4812f0d1cf93SDouglas Gilbert 		goto fini;
4813f0d1cf93SDouglas Gilbert 	}
4814f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4815f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4816f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4817f0d1cf93SDouglas Gilbert 		goto fini;
4818f0d1cf93SDouglas Gilbert 	}
4819f0d1cf93SDouglas Gilbert 
4820f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4821f0d1cf93SDouglas Gilbert fini:
48227109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4823f0d1cf93SDouglas Gilbert 	return res;
4824f0d1cf93SDouglas Gilbert }
4825f0d1cf93SDouglas Gilbert 
4826f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4827f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4828f0d1cf93SDouglas Gilbert {
4829f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
48302d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4831f0d1cf93SDouglas Gilbert 
48324a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
4833f0d1cf93SDouglas Gilbert 		return;
4834f0d1cf93SDouglas Gilbert 
4835f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4836f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4837f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4838f0d1cf93SDouglas Gilbert 
4839f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4840f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4841f0d1cf93SDouglas Gilbert 
48422d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
48432d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
48442d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
48452d62253eSShin'ichiro Kawasaki 
484664e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4847f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4848f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4849f0d1cf93SDouglas Gilbert }
4850f0d1cf93SDouglas Gilbert 
4851f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4852f0d1cf93SDouglas Gilbert {
4853f0d1cf93SDouglas Gilbert 	unsigned int i;
4854f0d1cf93SDouglas Gilbert 
4855f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4856f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4857f0d1cf93SDouglas Gilbert }
4858f0d1cf93SDouglas Gilbert 
4859f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4860f0d1cf93SDouglas Gilbert {
4861f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4862f0d1cf93SDouglas Gilbert 	int res = 0;
4863f0d1cf93SDouglas Gilbert 	u64 z_id;
4864f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4865f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4866b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4867f0d1cf93SDouglas Gilbert 
4868f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4869f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4870f0d1cf93SDouglas Gilbert 		return check_condition_result;
4871f0d1cf93SDouglas Gilbert 	}
4872f0d1cf93SDouglas Gilbert 
48737109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4874f0d1cf93SDouglas Gilbert 
4875f0d1cf93SDouglas Gilbert 	if (all) {
4876f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4877f0d1cf93SDouglas Gilbert 		goto fini;
4878f0d1cf93SDouglas Gilbert 	}
4879f0d1cf93SDouglas Gilbert 
4880f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4881f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4882f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4883f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4884f0d1cf93SDouglas Gilbert 		goto fini;
4885f0d1cf93SDouglas Gilbert 	}
4886f0d1cf93SDouglas Gilbert 
4887f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4888f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4889f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4890f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4891f0d1cf93SDouglas Gilbert 		goto fini;
4892f0d1cf93SDouglas Gilbert 	}
4893f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4894f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4895f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4896f0d1cf93SDouglas Gilbert 		goto fini;
4897f0d1cf93SDouglas Gilbert 	}
4898f0d1cf93SDouglas Gilbert 
4899f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4900f0d1cf93SDouglas Gilbert fini:
49017109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4902f0d1cf93SDouglas Gilbert 	return res;
4903f0d1cf93SDouglas Gilbert }
4904f0d1cf93SDouglas Gilbert 
4905c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4906c4837394SDouglas Gilbert {
4907c10fa55fSJohn Garry 	u16 hwq;
4908a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4909c10fa55fSJohn Garry 
4910c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4911c4837394SDouglas Gilbert 
4912458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4913458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4914458df78bSBart Van Assche 		hwq = 0;
4915f7c4cdc7SJohn Garry 
4916458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4917c4837394SDouglas Gilbert }
4918c4837394SDouglas Gilbert 
4919c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4920c10fa55fSJohn Garry {
4921a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4922c10fa55fSJohn Garry }
4923c10fa55fSJohn Garry 
4924c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4925fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
49261da177e4SLinus Torvalds {
49277382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4928c4837394SDouglas Gilbert 	int qc_idx;
4929cbf67842SDouglas Gilbert 	int retiring = 0;
49301da177e4SLinus Torvalds 	unsigned long iflags;
4931c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4932cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4933cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4934cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
49351da177e4SLinus Torvalds 
49367382f9d8SDouglas Gilbert 	if (unlikely(aborted))
49377382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4938c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4939c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4940c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4941cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4942c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4943c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4944c4837394SDouglas Gilbert 	}
4945c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4946c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
49471da177e4SLinus Torvalds 		return;
49481da177e4SLinus Torvalds 	}
4949c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4950d9d23a5aSDouglas Gilbert 	WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
4951c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4952cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4953b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4954c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4955c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4956c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
49571da177e4SLinus Torvalds 		return;
49581da177e4SLinus Torvalds 	}
4959cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4960f46eb0e9SDouglas Gilbert 	if (likely(devip))
4961cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4962cbf67842SDouglas Gilbert 	else
4963c1287970STomas Winkler 		pr_err("devip=NULL\n");
4964f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4965cbf67842SDouglas Gilbert 		retiring = 1;
4966cbf67842SDouglas Gilbert 
4967cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4968c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4969c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4970c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4971cbf67842SDouglas Gilbert 		return;
49721da177e4SLinus Torvalds 	}
49731da177e4SLinus Torvalds 
4974cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4975cbf67842SDouglas Gilbert 		int k, retval;
4976cbf67842SDouglas Gilbert 
4977cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4978c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4979c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4980c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4981cbf67842SDouglas Gilbert 			return;
4982cbf67842SDouglas Gilbert 		}
4983c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4984773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4985cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4986cbf67842SDouglas Gilbert 		else
4987cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4988cbf67842SDouglas Gilbert 	}
4989c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
49907382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
49917382f9d8SDouglas Gilbert 		if (sdebug_verbose)
49927382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
49937382f9d8SDouglas Gilbert 		return;
49947382f9d8SDouglas Gilbert 	}
49956c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
4996cbf67842SDouglas Gilbert }
4997cbf67842SDouglas Gilbert 
4998cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4999fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
5000cbf67842SDouglas Gilbert {
5001a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
5002a10bc12aSDouglas Gilbert 						  hrt);
5003a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5004cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
5005cbf67842SDouglas Gilbert }
50061da177e4SLinus Torvalds 
5007a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
5008fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
5009a10bc12aSDouglas Gilbert {
5010a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
5011a10bc12aSDouglas Gilbert 						  ew.work);
5012a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5013a10bc12aSDouglas Gilbert }
5014a10bc12aSDouglas Gilbert 
501509ba24c1SDouglas Gilbert static bool got_shared_uuid;
5016bf476433SChristoph Hellwig static uuid_t shared_uuid;
501709ba24c1SDouglas Gilbert 
5018f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
5019f0d1cf93SDouglas Gilbert {
5020f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
5021f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
50224a5fc1c6SDamien Le Moal 	sector_t conv_capacity;
5023f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
5024f0d1cf93SDouglas Gilbert 	unsigned int i;
5025f0d1cf93SDouglas Gilbert 
5026f0d1cf93SDouglas Gilbert 	/*
502798e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
502898e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
5029f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
5030f0d1cf93SDouglas Gilbert 	 * created for the device.
5031f0d1cf93SDouglas Gilbert 	 */
503298e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
5033f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
5034f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5035f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
5036f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
5037f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
5038f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
5039f0d1cf93SDouglas Gilbert 			return -EINVAL;
5040f0d1cf93SDouglas Gilbert 		}
5041f0d1cf93SDouglas Gilbert 	} else {
5042108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
5043108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
5044108e36f0SDamien Le Moal 			return -EINVAL;
5045108e36f0SDamien Le Moal 		}
504698e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
5047f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5048f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
5049f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
5050f0d1cf93SDouglas Gilbert 			return -EINVAL;
5051f0d1cf93SDouglas Gilbert 		}
5052f0d1cf93SDouglas Gilbert 	}
5053f0d1cf93SDouglas Gilbert 
5054f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
5055f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
5056f0d1cf93SDouglas Gilbert 
50574a5fc1c6SDamien Le Moal 	if (sdeb_zbc_zone_cap_mb == 0) {
50584a5fc1c6SDamien Le Moal 		devip->zcap = devip->zsize;
50594a5fc1c6SDamien Le Moal 	} else {
50604a5fc1c6SDamien Le Moal 		devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >>
50614a5fc1c6SDamien Le Moal 			      ilog2(sdebug_sector_size);
50624a5fc1c6SDamien Le Moal 		if (devip->zcap > devip->zsize) {
50634a5fc1c6SDamien Le Moal 			pr_err("Zone capacity too large\n");
50644a5fc1c6SDamien Le Moal 			return -EINVAL;
50654a5fc1c6SDamien Le Moal 		}
50664a5fc1c6SDamien Le Moal 	}
50674a5fc1c6SDamien Le Moal 
50684a5fc1c6SDamien Le Moal 	conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift;
50694a5fc1c6SDamien Le Moal 	if (conv_capacity >= capacity) {
5070aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
5071aa8fecf9SDamien Le Moal 		return -EINVAL;
5072aa8fecf9SDamien Le Moal 	}
5073aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
50744a5fc1c6SDamien Le Moal 	devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >>
50754a5fc1c6SDamien Le Moal 			      devip->zsize_shift;
50764a5fc1c6SDamien Le Moal 	devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones;
50774a5fc1c6SDamien Le Moal 
50784a5fc1c6SDamien Le Moal 	/* Add gap zones if zone capacity is smaller than the zone size */
50794a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
50804a5fc1c6SDamien Le Moal 		devip->nr_zones += devip->nr_seq_zones;
5081aa8fecf9SDamien Le Moal 
508264e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
508364e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
5084380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
5085f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
5086f0d1cf93SDouglas Gilbert 		else
5087380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
508864e14eceSDamien Le Moal 	}
5089f0d1cf93SDouglas Gilbert 
5090f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
5091f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
5092f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
5093f0d1cf93SDouglas Gilbert 		return -ENOMEM;
5094f0d1cf93SDouglas Gilbert 
5095f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
5096f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
5097f0d1cf93SDouglas Gilbert 
5098f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
5099f0d1cf93SDouglas Gilbert 
5100aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
510135dbe2b9SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_CNV;
5102f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
5103f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
51044a5fc1c6SDamien Le Moal 			zsp->z_size =
51054a5fc1c6SDamien Le Moal 				min_t(u64, devip->zsize, capacity - zstart);
51064a5fc1c6SDamien Le Moal 		} else if ((zstart & (devip->zsize - 1)) == 0) {
510764e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
510835dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWR;
510964e14eceSDamien Le Moal 			else
511035dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWP;
5111f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
5112f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
51134a5fc1c6SDamien Le Moal 			zsp->z_size =
51144a5fc1c6SDamien Le Moal 				min_t(u64, devip->zcap, capacity - zstart);
51154a5fc1c6SDamien Le Moal 		} else {
51164a5fc1c6SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_GAP;
51174a5fc1c6SDamien Le Moal 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
51184a5fc1c6SDamien Le Moal 			zsp->z_wp = (sector_t)-1;
51194a5fc1c6SDamien Le Moal 			zsp->z_size = min_t(u64, devip->zsize - devip->zcap,
51204a5fc1c6SDamien Le Moal 					    capacity - zstart);
5121f0d1cf93SDouglas Gilbert 		}
5122f0d1cf93SDouglas Gilbert 
51234a5fc1c6SDamien Le Moal 		WARN_ON_ONCE((int)zsp->z_size <= 0);
5124f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
5125f0d1cf93SDouglas Gilbert 	}
5126f0d1cf93SDouglas Gilbert 
5127f0d1cf93SDouglas Gilbert 	return 0;
5128f0d1cf93SDouglas Gilbert }
5129f0d1cf93SDouglas Gilbert 
5130fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
5131fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
51325cb2fc06SFUJITA Tomonori {
51335cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
51345cb2fc06SFUJITA Tomonori 
51355cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
51365cb2fc06SFUJITA Tomonori 	if (devip) {
513709ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
5138bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
513909ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
514009ba24c1SDouglas Gilbert 			if (got_shared_uuid)
514109ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
514209ba24c1SDouglas Gilbert 			else {
5143bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
514409ba24c1SDouglas Gilbert 				got_shared_uuid = true;
514509ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
514609ba24c1SDouglas Gilbert 			}
514709ba24c1SDouglas Gilbert 		}
51485cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
5149f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
515064e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
5151f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
5152f0d1cf93SDouglas Gilbert 				kfree(devip);
5153f0d1cf93SDouglas Gilbert 				return NULL;
5154f0d1cf93SDouglas Gilbert 			}
515564e14eceSDamien Le Moal 		} else {
515664e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
5157f0d1cf93SDouglas Gilbert 		}
5158fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
5159fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
51605cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
51615cb2fc06SFUJITA Tomonori 	}
51625cb2fc06SFUJITA Tomonori 	return devip;
51635cb2fc06SFUJITA Tomonori }
51645cb2fc06SFUJITA Tomonori 
5165f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
51661da177e4SLinus Torvalds {
51671da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51681da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
5169f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
51701da177e4SLinus Torvalds 
5171785d6b7cSJohn Garry 	sdbg_host = shost_to_sdebug_host(sdev->host);
5172ad0c7775SDouglas Gilbert 
51731da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
51741da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
51751da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
51761da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
51771da177e4SLinus Torvalds 			return devip;
51781da177e4SLinus Torvalds 		else {
51791da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
51801da177e4SLinus Torvalds 				open_devip = devip;
51811da177e4SLinus Torvalds 		}
51821da177e4SLinus Torvalds 	}
51835cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
51845cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
51855cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5186c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51871da177e4SLinus Torvalds 			return NULL;
51881da177e4SLinus Torvalds 		}
51891da177e4SLinus Torvalds 	}
5190a75869d1SFUJITA Tomonori 
51911da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
51921da177e4SLinus Torvalds 	open_devip->target = sdev->id;
51931da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
51941da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5195cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
5196500d0d24SDouglas Gilbert 	set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
5197c2248fc9SDouglas Gilbert 	open_devip->used = true;
51981da177e4SLinus Torvalds 	return open_devip;
51991da177e4SLinus Torvalds }
52001da177e4SLinus Torvalds 
52018dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
52021da177e4SLinus Torvalds {
5203773642d9SDouglas Gilbert 	if (sdebug_verbose)
5204c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
52058dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52068dea0d02SFUJITA Tomonori 	return 0;
52078dea0d02SFUJITA Tomonori }
52081da177e4SLinus Torvalds 
52098dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
52108dea0d02SFUJITA Tomonori {
5211f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5212f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5213a34c4e98SFUJITA Tomonori 
5214773642d9SDouglas Gilbert 	if (sdebug_verbose)
5215c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
52168dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5217b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5218b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5219b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5220f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5221b01f6f83SDouglas Gilbert 		if (devip == NULL)
52228dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5223f46eb0e9SDouglas Gilbert 	}
5224c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5225773642d9SDouglas Gilbert 	if (sdebug_no_uld)
522678d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
52279b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
52288dea0d02SFUJITA Tomonori 	return 0;
52298dea0d02SFUJITA Tomonori }
52308dea0d02SFUJITA Tomonori 
52318dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
52328dea0d02SFUJITA Tomonori {
52338dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
52348dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
52358dea0d02SFUJITA Tomonori 
5236773642d9SDouglas Gilbert 	if (sdebug_verbose)
5237c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
52388dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52398dea0d02SFUJITA Tomonori 	if (devip) {
524025985edcSLucas De Marchi 		/* make this slot available for re-use */
5241c2248fc9SDouglas Gilbert 		devip->used = false;
52428dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
52438dea0d02SFUJITA Tomonori 	}
52448dea0d02SFUJITA Tomonori }
52458dea0d02SFUJITA Tomonori 
524610bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
524710bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5248c4837394SDouglas Gilbert {
5249c4837394SDouglas Gilbert 	if (!sd_dp)
5250c4837394SDouglas Gilbert 		return;
525110bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5252c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
525310bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5254c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5255c4837394SDouglas Gilbert }
5256c4837394SDouglas Gilbert 
5257a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5258a10bc12aSDouglas Gilbert    returns false */
5259a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
52608dea0d02SFUJITA Tomonori {
52618dea0d02SFUJITA Tomonori 	unsigned long iflags;
5262c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
526310bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5264c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
52658dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5266cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5267a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
52688dea0d02SFUJITA Tomonori 
5269c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5270c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5271773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5272cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5273cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5274cbf67842SDouglas Gilbert 			qmax = r_qmax;
5275cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5276c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5277c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5278a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5279a10bc12aSDouglas Gilbert 					continue;
5280c4837394SDouglas Gilbert 				/* found */
5281db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5282db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5283db525fceSDouglas Gilbert 				if (devip)
5284db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5285db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5286a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
528710bde980SDouglas Gilbert 				if (sd_dp) {
5288d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5289d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
529010bde980SDouglas Gilbert 				} else
529110bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5292c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
529310bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5294c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5295a10bc12aSDouglas Gilbert 				return true;
52968dea0d02SFUJITA Tomonori 			}
5297cbf67842SDouglas Gilbert 		}
5298c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5299c4837394SDouglas Gilbert 	}
5300a10bc12aSDouglas Gilbert 	return false;
53018dea0d02SFUJITA Tomonori }
53028dea0d02SFUJITA Tomonori 
5303a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
5304f19fe8f3SBart Van Assche static void stop_all_queued(void)
53058dea0d02SFUJITA Tomonori {
53068dea0d02SFUJITA Tomonori 	unsigned long iflags;
5307c4837394SDouglas Gilbert 	int j, k;
530810bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5309c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
53108dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5311cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5312a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53138dea0d02SFUJITA Tomonori 
5314c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5315c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5316c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5317c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5318c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5319f19fe8f3SBart Van Assche 				if (sqcp->a_cmnd == NULL)
5320a10bc12aSDouglas Gilbert 					continue;
5321db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5322db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5323db525fceSDouglas Gilbert 				if (devip)
5324db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5325db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5326a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
532710bde980SDouglas Gilbert 				if (sd_dp) {
5328d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5329d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
533010bde980SDouglas Gilbert 				} else
533110bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5332c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
533310bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5334c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5335c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
53368dea0d02SFUJITA Tomonori 			}
53378dea0d02SFUJITA Tomonori 		}
5338c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5339c4837394SDouglas Gilbert 	}
5340cbf67842SDouglas Gilbert }
5341cbf67842SDouglas Gilbert 
5342cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5343cbf67842SDouglas Gilbert static void free_all_queued(void)
5344cbf67842SDouglas Gilbert {
5345c4837394SDouglas Gilbert 	int j, k;
5346c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5347cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5348cbf67842SDouglas Gilbert 
5349c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5350c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5351c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5352a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5353a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5354cbf67842SDouglas Gilbert 		}
53551da177e4SLinus Torvalds 	}
5356c4837394SDouglas Gilbert }
53571da177e4SLinus Torvalds 
53581da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
53591da177e4SLinus Torvalds {
5360a10bc12aSDouglas Gilbert 	bool ok;
5361a10bc12aSDouglas Gilbert 
53621da177e4SLinus Torvalds 	++num_aborts;
536306be9fbeSJohn Garry 
5364a10bc12aSDouglas Gilbert 	ok = stop_queued_cmnd(SCpnt);
536506be9fbeSJohn Garry 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5366a10bc12aSDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5367a10bc12aSDouglas Gilbert 			    "%s: command%s found\n", __func__,
5368a10bc12aSDouglas Gilbert 			    ok ? "" : " not");
536906be9fbeSJohn Garry 
53701da177e4SLinus Torvalds 	return SUCCESS;
53711da177e4SLinus Torvalds }
53721da177e4SLinus Torvalds 
53731da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
53741da177e4SLinus Torvalds {
5375cbf67842SDouglas Gilbert 	struct scsi_device *sdp = SCpnt->device;
5376a19226f8SJohn Garry 	struct sdebug_dev_info *devip = sdp->hostdata;
5377a19226f8SJohn Garry 
5378a19226f8SJohn Garry 	++num_dev_resets;
5379cbf67842SDouglas Gilbert 
5380773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5381cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
53821da177e4SLinus Torvalds 	if (devip)
5383cbf67842SDouglas Gilbert 		set_bit(SDEBUG_UA_POR, devip->uas_bm);
5384a19226f8SJohn Garry 
53851da177e4SLinus Torvalds 	return SUCCESS;
53861da177e4SLinus Torvalds }
53871da177e4SLinus Torvalds 
5388cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5389cbf67842SDouglas Gilbert {
5390a15df530SJohn Garry 	struct scsi_device *sdp = SCpnt->device;
5391a15df530SJohn Garry 	struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host);
5392cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5393cbf67842SDouglas Gilbert 	int k = 0;
5394cbf67842SDouglas Gilbert 
5395cbf67842SDouglas Gilbert 	++num_target_resets;
5396773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5397cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5398a15df530SJohn Garry 
5399a15df530SJohn Garry 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
5400cbf67842SDouglas Gilbert 		if (devip->target == sdp->id) {
5401cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5402cbf67842SDouglas Gilbert 			++k;
5403cbf67842SDouglas Gilbert 		}
5404cbf67842SDouglas Gilbert 	}
5405a15df530SJohn Garry 
5406773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5407cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5408cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5409a15df530SJohn Garry 
5410cbf67842SDouglas Gilbert 	return SUCCESS;
5411cbf67842SDouglas Gilbert }
5412cbf67842SDouglas Gilbert 
54131da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
54141da177e4SLinus Torvalds {
5415519bfc14SJohn Garry 	struct scsi_device *sdp = SCpnt->device;
5416519bfc14SJohn Garry 	struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host);
5417cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5418cbf67842SDouglas Gilbert 	int k = 0;
54191da177e4SLinus Torvalds 
54201da177e4SLinus Torvalds 	++num_bus_resets;
5421519bfc14SJohn Garry 
5422773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5423cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5424519bfc14SJohn Garry 
5425519bfc14SJohn Garry 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
5426cbf67842SDouglas Gilbert 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5427cbf67842SDouglas Gilbert 		++k;
54281da177e4SLinus Torvalds 	}
5429519bfc14SJohn Garry 
5430773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5431cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5432cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
54331da177e4SLinus Torvalds 	return SUCCESS;
54341da177e4SLinus Torvalds }
54351da177e4SLinus Torvalds 
54361da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
54371da177e4SLinus Torvalds {
54381da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5439cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5440cbf67842SDouglas Gilbert 	int k = 0;
54411da177e4SLinus Torvalds 
54421da177e4SLinus Torvalds 	++num_host_resets;
5443*9c230382SJohn Garry 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5444cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
54451da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
54461da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5447cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5448cbf67842SDouglas Gilbert 				    dev_list) {
5449cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5450cbf67842SDouglas Gilbert 			++k;
5451cbf67842SDouglas Gilbert 		}
54521da177e4SLinus Torvalds 	}
54531da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
5454f19fe8f3SBart Van Assche 	stop_all_queued();
5455773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5456cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5457cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
54581da177e4SLinus Torvalds 	return SUCCESS;
54591da177e4SLinus Torvalds }
54601da177e4SLinus Torvalds 
546187c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
54621da177e4SLinus Torvalds {
54631442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5464979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
54651da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
54661da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
54671da177e4SLinus Torvalds 
54681da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5469773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
54701da177e4SLinus Torvalds 		return;
5471773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5472773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5473c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
54741da177e4SLinus Torvalds 	}
54758c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
54761da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5477773642d9SDouglas Gilbert 			   / sdebug_num_parts;
54781da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
54791da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5480979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5481979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
54821da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
54831da177e4SLinus Torvalds 			    * heads_by_sects;
5484979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5485979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5486979e0dc3SJohn Pittman 	}
5487773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5488773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
54891da177e4SLinus Torvalds 
54901da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
54911da177e4SLinus Torvalds 	ramp[511] = 0xAA;
54921442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
54931da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
54941da177e4SLinus Torvalds 		start_sec = starts[k];
5495979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
54961da177e4SLinus Torvalds 		pp->boot_ind = 0;
54971da177e4SLinus Torvalds 
54981da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
54991da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
55001da177e4SLinus Torvalds 			   / sdebug_sectors_per;
55011da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
55021da177e4SLinus Torvalds 
55031da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
55041da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
55051da177e4SLinus Torvalds 			       / sdebug_sectors_per;
55061da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
55071da177e4SLinus Torvalds 
5508150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5509150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
55101da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
55111da177e4SLinus Torvalds 	}
55121da177e4SLinus Torvalds }
55131da177e4SLinus Torvalds 
5514f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block)
5515c4837394SDouglas Gilbert {
5516c4837394SDouglas Gilbert 	int j;
5517c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5518c4837394SDouglas Gilbert 
5519c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5520f19fe8f3SBart Van Assche 		atomic_set(&sqp->blocked, (int)block);
5521c4837394SDouglas Gilbert }
5522c4837394SDouglas Gilbert 
5523c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5524c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5525c4837394SDouglas Gilbert  */
5526c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5527c4837394SDouglas Gilbert {
5528c4837394SDouglas Gilbert 	int count, modulo;
5529c4837394SDouglas Gilbert 
5530c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5531c4837394SDouglas Gilbert 	if (modulo < 2)
5532c4837394SDouglas Gilbert 		return;
5533f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
5534c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5535c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5536f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
5537c4837394SDouglas Gilbert }
5538c4837394SDouglas Gilbert 
5539c4837394SDouglas Gilbert static void clear_queue_stats(void)
5540c4837394SDouglas Gilbert {
5541c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5542c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5543c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5544c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5545c4837394SDouglas Gilbert }
5546c4837394SDouglas Gilbert 
55473a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5548c4837394SDouglas Gilbert {
55493a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
55503a90a63dSDouglas Gilbert 		return false;
55513a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5552c4837394SDouglas Gilbert }
5553c4837394SDouglas Gilbert 
5554a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5555a2aede97SDouglas Gilbert 
5556c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5557c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5558c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5559c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5560c4837394SDouglas Gilbert  */
5561fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5562f66b8517SMartin Wilck 			 int scsi_result,
5563f19fe8f3SBart Van Assche 			 int (*pfp)(struct scsi_cmnd *,
5564f19fe8f3SBart Van Assche 				    struct sdebug_dev_info *),
5565f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
55661da177e4SLinus Torvalds {
5567a2aede97SDouglas Gilbert 	bool new_sd_dp;
55683a90a63dSDouglas Gilbert 	bool inject = false;
55696ce913feSChristoph Hellwig 	bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED;
55703a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5571a2aede97SDouglas Gilbert 	unsigned long iflags;
5572a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5573c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5574c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5575299b6c07STomas Winkler 	struct scsi_device *sdp;
5576a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
55771da177e4SLinus Torvalds 
5578b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5579b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5580f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5581f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
55821da177e4SLinus Torvalds 	}
5583299b6c07STomas Winkler 	sdp = cmnd->device;
5584299b6c07STomas Winkler 
5585f19fe8f3SBart Van Assche 	if (delta_jiff == 0)
5586cd62b7daSDouglas Gilbert 		goto respond_in_thread;
55871da177e4SLinus Torvalds 
5588c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5589c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5590c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5591c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5592c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5593c4837394SDouglas Gilbert 	}
5594cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5595cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5596f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5597cd62b7daSDouglas Gilbert 		if (scsi_result) {
5598c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5599cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5600cd62b7daSDouglas Gilbert 		} else
5601cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5602c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5603773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5604f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5605cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5606cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5607773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5608cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
56093a90a63dSDouglas Gilbert 			inject = true;
5610cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
56111da177e4SLinus Torvalds 		}
5612cbf67842SDouglas Gilbert 	}
5613cbf67842SDouglas Gilbert 
5614c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5615f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5616c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5617cd62b7daSDouglas Gilbert 		if (scsi_result)
5618cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5619cd62b7daSDouglas Gilbert 		scsi_result = device_qfull_result;
5620773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
56217d5a129bSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
56227d5a129bSDouglas Gilbert 				    __func__, sdebug_max_queue);
5623cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56241da177e4SLinus Torvalds 	}
562574595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5626cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5627c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
56281da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5629c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5630a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5631c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5632c4b57d89SKashyap Desai 
563374595c04SDouglas Gilbert 	if (!sd_dp) {
563410bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
563574595c04SDouglas Gilbert 		if (!sd_dp) {
563674595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
563774595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
563810bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
563974595c04SDouglas Gilbert 		}
5640a2aede97SDouglas Gilbert 		new_sd_dp = true;
5641a2aede97SDouglas Gilbert 	} else {
5642a2aede97SDouglas Gilbert 		new_sd_dp = false;
564310bde980SDouglas Gilbert 	}
5644f66b8517SMartin Wilck 
5645c10fa55fSJohn Garry 	/* Set the hostwide tag */
5646c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5647c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5648c10fa55fSJohn Garry 
56496ce913feSChristoph Hellwig 	if (polled)
5650a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5651a2aede97SDouglas Gilbert 
5652a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
56533a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5654f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5655f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5656f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5657f66b8517SMartin Wilck 	}
5658f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5659f66b8517SMartin Wilck 		cmnd->result = scsi_result;
56603a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
56613a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
56623a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
56633a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56643a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
56653a90a63dSDouglas Gilbert 		}
56663a90a63dSDouglas Gilbert 	}
5667f66b8517SMartin Wilck 
5668f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5669f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5670f66b8517SMartin Wilck 			    __func__, cmnd->result);
5671f66b8517SMartin Wilck 
567210bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5673b333a819SDouglas Gilbert 		ktime_t kt;
5674cbf67842SDouglas Gilbert 
5675b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
56760c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
56770c4bc91dSDouglas Gilbert 
56780c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
56798032bf12SJason A. Donenfeld 				ns = get_random_u32_below((u32)ns);
56800c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
56810c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
56820c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
56838032bf12SJason A. Donenfeld 					ns = get_random_u32_below((u32)ns);
56840c4bc91dSDouglas Gilbert 				ns <<= 12;
56850c4bc91dSDouglas Gilbert 			}
56860c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
56870c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
56888032bf12SJason A. Donenfeld 			kt = sdebug_random ? get_random_u32_below((u32)ndelay) :
56890c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5690a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5691a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5692a2aede97SDouglas Gilbert 
5693a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5694223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5695a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5696a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5697a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5698223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5699a2aede97SDouglas Gilbert 					if (new_sd_dp)
5700a2aede97SDouglas Gilbert 						kfree(sd_dp);
5701a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
57026c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5703a2aede97SDouglas Gilbert 					return 0;
5704a2aede97SDouglas Gilbert 				}
5705a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5706a2aede97SDouglas Gilbert 				kt -= d;
5707a2aede97SDouglas Gilbert 			}
57080c4bc91dSDouglas Gilbert 		}
57096ce913feSChristoph Hellwig 		if (polled) {
57104a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
57114a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57124a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57134a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57144a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57154a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57164a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57174a0c6f43SDouglas Gilbert 			}
5718d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57194a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57204a0c6f43SDouglas Gilbert 		} else {
572110bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
572210bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5723a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5724a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5725c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5726a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5727c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5728c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5729cbf67842SDouglas Gilbert 			}
5730d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
5731a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5732c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
57334a0c6f43SDouglas Gilbert 		}
57344a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
57354a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5736c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
57374a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
57384a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
57394a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
57406ce913feSChristoph Hellwig 		if (polled) {
57414a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
57424a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57434a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57444a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57454a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57464a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57474a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57484a0c6f43SDouglas Gilbert 			}
5749d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57504a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57514a0c6f43SDouglas Gilbert 		} else {
575210bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
575310bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5754a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5755c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5756c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5757a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5758cbf67842SDouglas Gilbert 			}
5759d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
57604a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
57614a0c6f43SDouglas Gilbert 		}
5762c4837394SDouglas Gilbert 		if (sdebug_statistics)
5763c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
57644a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
5765a6e76e6fSBart Van Assche 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5766a6e76e6fSBart Van Assche 				    scsi_cmd_to_rq(cmnd)->tag);
5767a6e76e6fSBart Van Assche 			blk_abort_request(scsi_cmd_to_rq(cmnd));
57683a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
57694a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
57707382f9d8SDouglas Gilbert 		}
5771cbf67842SDouglas Gilbert 	}
57723a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
57733a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
57743a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
57751da177e4SLinus Torvalds 	return 0;
5776cd62b7daSDouglas Gilbert 
5777cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5778f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5779f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5780f19fe8f3SBart Van Assche 	if (cmnd->result == 0 && scsi_result != 0)
5781cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
57826c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5783cd62b7daSDouglas Gilbert 	return 0;
57841da177e4SLinus Torvalds }
5785cbf67842SDouglas Gilbert 
578623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
578723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
578823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
578923183910SDouglas Gilbert    as it can when the corresponding attribute in the
579023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
579123183910SDouglas Gilbert  */
5792773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5793773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
57949b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5795773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5796c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5797773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5798773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5799773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5800773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5801773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5802773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5803773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5804773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5805c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5806e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5807e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5808e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5809e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
58105d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
58115d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
58125d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5813773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5814773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5815773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5816773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5817ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5818773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5819773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
58205d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
58215d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58225d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
58235d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5824773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5825773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
58267109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
5827773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5828773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5829773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5830773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
58315d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5832773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
583387c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
583487c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5835773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5836773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
58370c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5838773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5839773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5840773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5841c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5842773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5843c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5844c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5845fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5846773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5847773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5848773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5849773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
585009ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
58515d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5852773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
585323183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58549447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5855773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
58565b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
58579267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
58584a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO);
5859380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5860aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
586198e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
58621da177e4SLinus Torvalds 
58631da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
58641da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
58651da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5866b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
58671da177e4SLinus Torvalds 
58685d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
58695b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
58709b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
58710759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5872cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5873c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
58745b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
58755b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5876c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5877beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
587823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
58795b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5880185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5881c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5882c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5883e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
58849b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
58859b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
58865d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
58875d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
58885d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
58895b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
58905b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
58915b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
58925b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5893ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5894fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5895cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5896d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
58975d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5898cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5899c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
59007109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
590178d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
59021da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5903c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
590432c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
590586e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
59065d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
59075d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
59085d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5909fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
59101da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
59110c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5912d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5913760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5914ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5915c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5916c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5917c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5918fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
59195b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
59205b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
59216014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
59226014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
592309ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
592409ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5925c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
59265b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
59279447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
59285b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
59299267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
59304a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)");
5931380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5932aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
593398e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
59341da177e4SLinus Torvalds 
5935760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5936760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
59371da177e4SLinus Torvalds 
59381da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
59391da177e4SLinus Torvalds {
5940c4837394SDouglas Gilbert 	int k;
5941c4837394SDouglas Gilbert 
5942760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5943760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5944760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5945c4837394SDouglas Gilbert 		return sdebug_info;
5946760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5947760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5948760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5949760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
59501da177e4SLinus Torvalds 	return sdebug_info;
59511da177e4SLinus Torvalds }
59521da177e4SLinus Torvalds 
5953cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5954fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5955fd32119bSDouglas Gilbert 				 int length)
59561da177e4SLinus Torvalds {
59571da177e4SLinus Torvalds 	char arr[16];
5958c8ed555aSAl Viro 	int opts;
59591da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
59601da177e4SLinus Torvalds 
59611da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
59621da177e4SLinus Torvalds 		return -EACCES;
59631da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
59641da177e4SLinus Torvalds 	arr[minLen] = '\0';
5965c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
59661da177e4SLinus Torvalds 		return -EINVAL;
5967773642d9SDouglas Gilbert 	sdebug_opts = opts;
5968773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5969773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5970773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5971c4837394SDouglas Gilbert 		tweak_cmnd_count();
59721da177e4SLinus Torvalds 	return length;
59731da177e4SLinus Torvalds }
5974c8ed555aSAl Viro 
5975cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5976cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5977cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5978c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5979c8ed555aSAl Viro {
5980c4837394SDouglas Gilbert 	int f, j, l;
5981c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
598287c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5983cbf67842SDouglas Gilbert 
5984c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5985c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5986c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5987c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5988c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5989c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5990c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5991c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5992c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5993c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5994c4837394SDouglas Gilbert 		   num_aborts);
5995c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5996c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5997c4837394SDouglas Gilbert 		   num_host_resets);
5998c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5999c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
6000458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
6001458df78bSBart Van Assche 		   sdebug_statistics);
60024a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
6003c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
6004c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
6005c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
60064a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
60074a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
6008cbf67842SDouglas Gilbert 
6009c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
6010c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
6011c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
6012c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
6013773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
6014c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
6015c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
6016c4837394SDouglas Gilbert 				   "first,last bits", f, l);
6017c4837394SDouglas Gilbert 		}
6018cbf67842SDouglas Gilbert 	}
601987c715dcSDouglas Gilbert 
602087c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
602187c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
602287c715dcSDouglas Gilbert 		bool niu;
602387c715dcSDouglas Gilbert 		int idx;
602487c715dcSDouglas Gilbert 		unsigned long l_idx;
602587c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
602687c715dcSDouglas Gilbert 
602787c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
602887c715dcSDouglas Gilbert 		j = 0;
602987c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
603087c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
603187c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
603287c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
603387c715dcSDouglas Gilbert 			++j;
603487c715dcSDouglas Gilbert 		}
603587c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
603687c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
603787c715dcSDouglas Gilbert 		j = 0;
603887c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
603987c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
604087c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
604187c715dcSDouglas Gilbert 			idx = (int)l_idx;
604287c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
604387c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
604487c715dcSDouglas Gilbert 			++j;
604587c715dcSDouglas Gilbert 		}
604687c715dcSDouglas Gilbert 	}
6047c8ed555aSAl Viro 	return 0;
60481da177e4SLinus Torvalds }
60491da177e4SLinus Torvalds 
605082069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
60511da177e4SLinus Torvalds {
6052c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
60531da177e4SLinus Torvalds }
6054c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
6055c4837394SDouglas Gilbert  * of delay is jiffies.
6056c4837394SDouglas Gilbert  */
605782069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
605882069379SAkinobu Mita 			   size_t count)
60591da177e4SLinus Torvalds {
6060c2206098SDouglas Gilbert 	int jdelay, res;
60611da177e4SLinus Torvalds 
6062b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
6063cbf67842SDouglas Gilbert 		res = count;
6064c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
6065c4837394SDouglas Gilbert 			int j, k;
6066c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6067cbf67842SDouglas Gilbert 
6068f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6069c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6070c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6071c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6072c4837394SDouglas Gilbert 						   sdebug_max_queue);
6073c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6074c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6075c4837394SDouglas Gilbert 					break;
6076c4837394SDouglas Gilbert 				}
6077c4837394SDouglas Gilbert 			}
6078c4837394SDouglas Gilbert 			if (res > 0) {
6079c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
6080773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
60811da177e4SLinus Torvalds 			}
6082f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
6083cbf67842SDouglas Gilbert 		}
6084cbf67842SDouglas Gilbert 		return res;
60851da177e4SLinus Torvalds 	}
60861da177e4SLinus Torvalds 	return -EINVAL;
60871da177e4SLinus Torvalds }
608882069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
60891da177e4SLinus Torvalds 
6090cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
6091cbf67842SDouglas Gilbert {
6092773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
6093cbf67842SDouglas Gilbert }
6094cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6095c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
6096cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6097cbf67842SDouglas Gilbert 			    size_t count)
6098cbf67842SDouglas Gilbert {
6099c4837394SDouglas Gilbert 	int ndelay, res;
6100cbf67842SDouglas Gilbert 
6101cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6102c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6103cbf67842SDouglas Gilbert 		res = count;
6104773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
6105c4837394SDouglas Gilbert 			int j, k;
6106c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6107c4837394SDouglas Gilbert 
6108f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6109c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6110c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6111c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6112c4837394SDouglas Gilbert 						   sdebug_max_queue);
6113c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6114c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6115c4837394SDouglas Gilbert 					break;
6116c4837394SDouglas Gilbert 				}
6117c4837394SDouglas Gilbert 			}
6118c4837394SDouglas Gilbert 			if (res > 0) {
6119773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6120c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6121c2206098SDouglas Gilbert 							: DEF_JDELAY;
6122cbf67842SDouglas Gilbert 			}
6123f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
6124cbf67842SDouglas Gilbert 		}
6125cbf67842SDouglas Gilbert 		return res;
6126cbf67842SDouglas Gilbert 	}
6127cbf67842SDouglas Gilbert 	return -EINVAL;
6128cbf67842SDouglas Gilbert }
6129cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6130cbf67842SDouglas Gilbert 
613182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
61321da177e4SLinus Torvalds {
6133773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
61341da177e4SLinus Torvalds }
61351da177e4SLinus Torvalds 
613682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
613782069379SAkinobu Mita 			  size_t count)
61381da177e4SLinus Torvalds {
61391da177e4SLinus Torvalds 	int opts;
61401da177e4SLinus Torvalds 	char work[20];
61411da177e4SLinus Torvalds 
61429a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61439a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61449a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
61451da177e4SLinus Torvalds 				goto opts_done;
61461da177e4SLinus Torvalds 		} else {
61479a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
61481da177e4SLinus Torvalds 				goto opts_done;
61491da177e4SLinus Torvalds 		}
61501da177e4SLinus Torvalds 	}
61511da177e4SLinus Torvalds 	return -EINVAL;
61521da177e4SLinus Torvalds opts_done:
6153773642d9SDouglas Gilbert 	sdebug_opts = opts;
6154773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6155773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6156c4837394SDouglas Gilbert 	tweak_cmnd_count();
61571da177e4SLinus Torvalds 	return count;
61581da177e4SLinus Torvalds }
615982069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
61601da177e4SLinus Torvalds 
616182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
61621da177e4SLinus Torvalds {
6163773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
61641da177e4SLinus Torvalds }
616582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
616682069379SAkinobu Mita 			   size_t count)
61671da177e4SLinus Torvalds {
61681da177e4SLinus Torvalds 	int n;
61691da177e4SLinus Torvalds 
6170f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6171f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6172f0d1cf93SDouglas Gilbert 		return -EINVAL;
6173f0d1cf93SDouglas Gilbert 
61741da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6175f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6176f0d1cf93SDouglas Gilbert 			return -EINVAL;
6177773642d9SDouglas Gilbert 		sdebug_ptype = n;
61781da177e4SLinus Torvalds 		return count;
61791da177e4SLinus Torvalds 	}
61801da177e4SLinus Torvalds 	return -EINVAL;
61811da177e4SLinus Torvalds }
618282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
61831da177e4SLinus Torvalds 
618482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
61851da177e4SLinus Torvalds {
6186773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
61871da177e4SLinus Torvalds }
618882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
618982069379SAkinobu Mita 			    size_t count)
61901da177e4SLinus Torvalds {
61911da177e4SLinus Torvalds 	int n;
61921da177e4SLinus Torvalds 
61931da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6194773642d9SDouglas Gilbert 		sdebug_dsense = n;
61951da177e4SLinus Torvalds 		return count;
61961da177e4SLinus Torvalds 	}
61971da177e4SLinus Torvalds 	return -EINVAL;
61981da177e4SLinus Torvalds }
619982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
62001da177e4SLinus Torvalds 
620182069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
620223183910SDouglas Gilbert {
6203773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
620423183910SDouglas Gilbert }
620582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
620682069379SAkinobu Mita 			     size_t count)
620723183910SDouglas Gilbert {
620887c715dcSDouglas Gilbert 	int n, idx;
620923183910SDouglas Gilbert 
621023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
621187c715dcSDouglas Gilbert 		bool want_store = (n == 0);
621287c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
621387c715dcSDouglas Gilbert 
6214cbf67842SDouglas Gilbert 		n = (n > 0);
6215773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
621687c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
621787c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6218cbf67842SDouglas Gilbert 
621987c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
622087c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
622187c715dcSDouglas Gilbert 				idx = sdebug_add_store();
622287c715dcSDouglas Gilbert 				if (idx < 0)
622387c715dcSDouglas Gilbert 					return idx;
622487c715dcSDouglas Gilbert 			} else {
622587c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
622687c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
622787c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6228cbf67842SDouglas Gilbert 			}
622987c715dcSDouglas Gilbert 			/* make all hosts use same store */
623087c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
623187c715dcSDouglas Gilbert 					    host_list) {
623287c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
623387c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
623487c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
623587c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
623687c715dcSDouglas Gilbert 				}
623787c715dcSDouglas Gilbert 			}
623887c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
623987c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
624087c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6241cbf67842SDouglas Gilbert 		}
6242773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
624323183910SDouglas Gilbert 		return count;
624423183910SDouglas Gilbert 	}
624523183910SDouglas Gilbert 	return -EINVAL;
624623183910SDouglas Gilbert }
624782069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
624823183910SDouglas Gilbert 
624982069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6250c65b1445SDouglas Gilbert {
6251773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6252c65b1445SDouglas Gilbert }
625382069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
625482069379SAkinobu Mita 			      size_t count)
6255c65b1445SDouglas Gilbert {
6256c65b1445SDouglas Gilbert 	int n;
6257c65b1445SDouglas Gilbert 
6258c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6259773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6260c65b1445SDouglas Gilbert 		return count;
6261c65b1445SDouglas Gilbert 	}
6262c65b1445SDouglas Gilbert 	return -EINVAL;
6263c65b1445SDouglas Gilbert }
626482069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6265c65b1445SDouglas Gilbert 
626682069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
62671da177e4SLinus Torvalds {
6268773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
62691da177e4SLinus Torvalds }
627082069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
627182069379SAkinobu Mita 			      size_t count)
62721da177e4SLinus Torvalds {
62731da177e4SLinus Torvalds 	int n;
62741da177e4SLinus Torvalds 
62751da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6276773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
62771da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
62781da177e4SLinus Torvalds 		return count;
62791da177e4SLinus Torvalds 	}
62801da177e4SLinus Torvalds 	return -EINVAL;
62811da177e4SLinus Torvalds }
628282069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
62831da177e4SLinus Torvalds 
628482069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
62851da177e4SLinus Torvalds {
6286773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
62871da177e4SLinus Torvalds }
628882069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
62891da177e4SLinus Torvalds 
629087c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
629187c715dcSDouglas Gilbert {
629287c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
629387c715dcSDouglas Gilbert }
629487c715dcSDouglas Gilbert 
629587c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
629687c715dcSDouglas Gilbert 				    size_t count)
629787c715dcSDouglas Gilbert {
629887c715dcSDouglas Gilbert 	bool v;
629987c715dcSDouglas Gilbert 
630087c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
630187c715dcSDouglas Gilbert 		return -EINVAL;
630287c715dcSDouglas Gilbert 
630387c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
630487c715dcSDouglas Gilbert 	return count;
630587c715dcSDouglas Gilbert }
630687c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
630787c715dcSDouglas Gilbert 
630882069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
63091da177e4SLinus Torvalds {
6310773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
63111da177e4SLinus Torvalds }
631282069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
63131da177e4SLinus Torvalds 
631482069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
63151da177e4SLinus Torvalds {
6316773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
63171da177e4SLinus Torvalds }
631882069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
631982069379SAkinobu Mita 			       size_t count)
63201da177e4SLinus Torvalds {
63211da177e4SLinus Torvalds 	int nth;
63223a90a63dSDouglas Gilbert 	char work[20];
63231da177e4SLinus Torvalds 
63243a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
63253a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
63263a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
63273a90a63dSDouglas Gilbert 				goto every_nth_done;
63283a90a63dSDouglas Gilbert 		} else {
63293a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
63303a90a63dSDouglas Gilbert 				goto every_nth_done;
63313a90a63dSDouglas Gilbert 		}
63323a90a63dSDouglas Gilbert 	}
63333a90a63dSDouglas Gilbert 	return -EINVAL;
63343a90a63dSDouglas Gilbert 
63353a90a63dSDouglas Gilbert every_nth_done:
6336773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6337c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6338c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6339c4837394SDouglas Gilbert 		sdebug_statistics = true;
6340c4837394SDouglas Gilbert 	}
6341c4837394SDouglas Gilbert 	tweak_cmnd_count();
63421da177e4SLinus Torvalds 	return count;
63431da177e4SLinus Torvalds }
634482069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
63451da177e4SLinus Torvalds 
6346ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6347ad0c7775SDouglas Gilbert {
6348ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6349ad0c7775SDouglas Gilbert }
6350ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6351ad0c7775SDouglas Gilbert 				size_t count)
6352ad0c7775SDouglas Gilbert {
6353ad0c7775SDouglas Gilbert 	int n;
6354ad0c7775SDouglas Gilbert 	bool changed;
6355ad0c7775SDouglas Gilbert 
6356ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6357ad0c7775SDouglas Gilbert 		return -EINVAL;
6358ad0c7775SDouglas Gilbert 	if (n >= 0) {
6359ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6360ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6361ad0c7775SDouglas Gilbert 			return -EINVAL;
6362ad0c7775SDouglas Gilbert 		}
6363ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6364ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6365ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6366ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6367ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6368ad0c7775SDouglas Gilbert 
6369ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6370ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6371ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6372ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6373ad0c7775SDouglas Gilbert 				}
6374ad0c7775SDouglas Gilbert 			}
6375ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6376ad0c7775SDouglas Gilbert 		}
6377ad0c7775SDouglas Gilbert 		return count;
6378ad0c7775SDouglas Gilbert 	}
6379ad0c7775SDouglas Gilbert 	return -EINVAL;
6380ad0c7775SDouglas Gilbert }
6381ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6382ad0c7775SDouglas Gilbert 
638382069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
63841da177e4SLinus Torvalds {
6385773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
63861da177e4SLinus Torvalds }
638782069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
638882069379SAkinobu Mita 			      size_t count)
63891da177e4SLinus Torvalds {
63901da177e4SLinus Torvalds 	int n;
639119c8ead7SEwan D. Milne 	bool changed;
63921da177e4SLinus Torvalds 
63931da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
63948d039e22SDouglas Gilbert 		if (n > 256) {
63958d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
63968d039e22SDouglas Gilbert 			return -EINVAL;
63978d039e22SDouglas Gilbert 		}
6398773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6399773642d9SDouglas Gilbert 		sdebug_max_luns = n;
64001da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6401773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
640219c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
640319c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
640419c8ead7SEwan D. Milne 
640519c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
640619c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
640719c8ead7SEwan D. Milne 					    host_list) {
640819c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
640919c8ead7SEwan D. Milne 						    dev_list) {
641019c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
641119c8ead7SEwan D. Milne 						dp->uas_bm);
641219c8ead7SEwan D. Milne 				}
641319c8ead7SEwan D. Milne 			}
641419c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
641519c8ead7SEwan D. Milne 		}
64161da177e4SLinus Torvalds 		return count;
64171da177e4SLinus Torvalds 	}
64181da177e4SLinus Torvalds 	return -EINVAL;
64191da177e4SLinus Torvalds }
642082069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
64211da177e4SLinus Torvalds 
642282069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
642378d4e5a0SDouglas Gilbert {
6424773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
642578d4e5a0SDouglas Gilbert }
6426cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6427cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
642882069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
642982069379SAkinobu Mita 			       size_t count)
643078d4e5a0SDouglas Gilbert {
6431c4837394SDouglas Gilbert 	int j, n, k, a;
6432c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
643378d4e5a0SDouglas Gilbert 
643478d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6435c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6436c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6437f19fe8f3SBart Van Assche 		block_unblock_all_queues(true);
6438c4837394SDouglas Gilbert 		k = 0;
6439c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6440c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6441c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6442c4837394SDouglas Gilbert 			if (a > k)
6443c4837394SDouglas Gilbert 				k = a;
6444c4837394SDouglas Gilbert 		}
6445773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6446c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6447cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6448cbf67842SDouglas Gilbert 		else if (k >= n)
6449cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6450cbf67842SDouglas Gilbert 		else
6451cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6452f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
645378d4e5a0SDouglas Gilbert 		return count;
645478d4e5a0SDouglas Gilbert 	}
645578d4e5a0SDouglas Gilbert 	return -EINVAL;
645678d4e5a0SDouglas Gilbert }
645782069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
645878d4e5a0SDouglas Gilbert 
6459c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6460c10fa55fSJohn Garry {
6461c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6462c10fa55fSJohn Garry }
6463c10fa55fSJohn Garry 
64647109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
64657109f370SDouglas Gilbert {
64667109f370SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
64677109f370SDouglas Gilbert }
64687109f370SDouglas Gilbert 
64697109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
64707109f370SDouglas Gilbert {
64717109f370SDouglas Gilbert 	bool v;
64727109f370SDouglas Gilbert 
64737109f370SDouglas Gilbert 	if (kstrtobool(buf, &v))
64747109f370SDouglas Gilbert 		return -EINVAL;
64757109f370SDouglas Gilbert 
64767109f370SDouglas Gilbert 	sdebug_no_rwlock = v;
64777109f370SDouglas Gilbert 	return count;
64787109f370SDouglas Gilbert }
64797109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock);
64807109f370SDouglas Gilbert 
6481c10fa55fSJohn Garry /*
6482c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6483c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6484c10fa55fSJohn Garry  */
6485c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6486c10fa55fSJohn Garry 
648782069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
648878d4e5a0SDouglas Gilbert {
6489773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
649078d4e5a0SDouglas Gilbert }
649182069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
649278d4e5a0SDouglas Gilbert 
649382069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
64941da177e4SLinus Torvalds {
6495773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
64961da177e4SLinus Torvalds }
649782069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
64981da177e4SLinus Torvalds 
649982069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6500c65b1445SDouglas Gilbert {
6501773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6502c65b1445SDouglas Gilbert }
650382069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
650482069379SAkinobu Mita 				size_t count)
6505c65b1445SDouglas Gilbert {
6506c65b1445SDouglas Gilbert 	int n;
65070d01c5dfSDouglas Gilbert 	bool changed;
6508c65b1445SDouglas Gilbert 
6509f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6510f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6511f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6512f0d1cf93SDouglas Gilbert 
6513c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6514773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6515773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
651628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
65170d01c5dfSDouglas Gilbert 		if (changed) {
65180d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
65190d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
652028898873SFUJITA Tomonori 
65214bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
65220d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
65230d01c5dfSDouglas Gilbert 					    host_list) {
65240d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
65250d01c5dfSDouglas Gilbert 						    dev_list) {
65260d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
65270d01c5dfSDouglas Gilbert 						dp->uas_bm);
65280d01c5dfSDouglas Gilbert 				}
65290d01c5dfSDouglas Gilbert 			}
65304bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
65310d01c5dfSDouglas Gilbert 		}
6532c65b1445SDouglas Gilbert 		return count;
6533c65b1445SDouglas Gilbert 	}
6534c65b1445SDouglas Gilbert 	return -EINVAL;
6535c65b1445SDouglas Gilbert }
653682069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6537c65b1445SDouglas Gilbert 
653882069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
65391da177e4SLinus Torvalds {
654087c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
6541f19fe8f3SBart Van Assche 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
65421da177e4SLinus Torvalds }
65431da177e4SLinus Torvalds 
654482069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
654582069379SAkinobu Mita 			      size_t count)
65461da177e4SLinus Torvalds {
6547f19fe8f3SBart Van Assche 	bool found;
6548f19fe8f3SBart Van Assche 	unsigned long idx;
6549f19fe8f3SBart Van Assche 	struct sdeb_store_info *sip;
6550f19fe8f3SBart Van Assche 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
65511da177e4SLinus Torvalds 	int delta_hosts;
65521da177e4SLinus Torvalds 
6553f19fe8f3SBart Van Assche 	if (sscanf(buf, "%d", &delta_hosts) != 1)
65541da177e4SLinus Torvalds 		return -EINVAL;
65551da177e4SLinus Torvalds 	if (delta_hosts > 0) {
65561da177e4SLinus Torvalds 		do {
6557f19fe8f3SBart Van Assche 			found = false;
6558f19fe8f3SBart Van Assche 			if (want_phs) {
6559f19fe8f3SBart Van Assche 				xa_for_each_marked(per_store_ap, idx, sip,
6560f19fe8f3SBart Van Assche 						   SDEB_XA_NOT_IN_USE) {
6561f19fe8f3SBart Van Assche 					sdeb_most_recent_idx = (int)idx;
6562f19fe8f3SBart Van Assche 					found = true;
656387c715dcSDouglas Gilbert 					break;
656487c715dcSDouglas Gilbert 				}
6565f19fe8f3SBart Van Assche 				if (found)	/* re-use case */
6566f19fe8f3SBart Van Assche 					sdebug_add_host_helper((int)idx);
6567f19fe8f3SBart Van Assche 				else
6568f19fe8f3SBart Van Assche 					sdebug_do_add_host(true);
6569f19fe8f3SBart Van Assche 			} else {
6570f19fe8f3SBart Van Assche 				sdebug_do_add_host(false);
6571f19fe8f3SBart Van Assche 			}
6572f19fe8f3SBart Van Assche 		} while (--delta_hosts);
6573f19fe8f3SBart Van Assche 	} else if (delta_hosts < 0) {
6574f19fe8f3SBart Van Assche 		do {
657587c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
65761da177e4SLinus Torvalds 		} while (++delta_hosts);
65771da177e4SLinus Torvalds 	}
65781da177e4SLinus Torvalds 	return count;
65791da177e4SLinus Torvalds }
658082069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
65811da177e4SLinus Torvalds 
658282069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
658323183910SDouglas Gilbert {
6584773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
658523183910SDouglas Gilbert }
658682069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
658782069379SAkinobu Mita 				    size_t count)
658823183910SDouglas Gilbert {
658923183910SDouglas Gilbert 	int n;
659023183910SDouglas Gilbert 
659123183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6592773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
659323183910SDouglas Gilbert 		return count;
659423183910SDouglas Gilbert 	}
659523183910SDouglas Gilbert 	return -EINVAL;
659623183910SDouglas Gilbert }
659782069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
659823183910SDouglas Gilbert 
6599c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6600c4837394SDouglas Gilbert {
6601c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6602c4837394SDouglas Gilbert }
6603c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6604c4837394SDouglas Gilbert 				size_t count)
6605c4837394SDouglas Gilbert {
6606c4837394SDouglas Gilbert 	int n;
6607c4837394SDouglas Gilbert 
6608c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6609c4837394SDouglas Gilbert 		if (n > 0)
6610c4837394SDouglas Gilbert 			sdebug_statistics = true;
6611c4837394SDouglas Gilbert 		else {
6612c4837394SDouglas Gilbert 			clear_queue_stats();
6613c4837394SDouglas Gilbert 			sdebug_statistics = false;
6614c4837394SDouglas Gilbert 		}
6615c4837394SDouglas Gilbert 		return count;
6616c4837394SDouglas Gilbert 	}
6617c4837394SDouglas Gilbert 	return -EINVAL;
6618c4837394SDouglas Gilbert }
6619c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6620c4837394SDouglas Gilbert 
662182069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6622597136abSMartin K. Petersen {
6623773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6624597136abSMartin K. Petersen }
662582069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6626597136abSMartin K. Petersen 
6627c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6628c4837394SDouglas Gilbert {
6629c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6630c4837394SDouglas Gilbert }
6631c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6632c4837394SDouglas Gilbert 
663382069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6634c6a44287SMartin K. Petersen {
6635773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6636c6a44287SMartin K. Petersen }
663782069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6638c6a44287SMartin K. Petersen 
663982069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6640c6a44287SMartin K. Petersen {
6641773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6642c6a44287SMartin K. Petersen }
664382069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6644c6a44287SMartin K. Petersen 
664582069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6646c6a44287SMartin K. Petersen {
6647773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6648c6a44287SMartin K. Petersen }
664982069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6650c6a44287SMartin K. Petersen 
665182069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6652c6a44287SMartin K. Petersen {
6653773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6654c6a44287SMartin K. Petersen }
665582069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6656c6a44287SMartin K. Petersen 
665782069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
665844d92694SMartin K. Petersen {
665987c715dcSDouglas Gilbert 	ssize_t count = 0;
666044d92694SMartin K. Petersen 
66615b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
666244d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
666344d92694SMartin K. Petersen 				 sdebug_store_sectors);
666444d92694SMartin K. Petersen 
666587c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
666687c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
666787c715dcSDouglas Gilbert 
666887c715dcSDouglas Gilbert 		if (sip)
6669c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
667087c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
667187c715dcSDouglas Gilbert 	}
667244d92694SMartin K. Petersen 	buf[count++] = '\n';
6673c7badc90STejun Heo 	buf[count] = '\0';
667444d92694SMartin K. Petersen 
667544d92694SMartin K. Petersen 	return count;
667644d92694SMartin K. Petersen }
667782069379SAkinobu Mita static DRIVER_ATTR_RO(map);
667844d92694SMartin K. Petersen 
66790c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
66800c4bc91dSDouglas Gilbert {
66810c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
66820c4bc91dSDouglas Gilbert }
66830c4bc91dSDouglas Gilbert 
66840c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
66850c4bc91dSDouglas Gilbert 			    size_t count)
66860c4bc91dSDouglas Gilbert {
66870c4bc91dSDouglas Gilbert 	bool v;
66880c4bc91dSDouglas Gilbert 
66890c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
66900c4bc91dSDouglas Gilbert 		return -EINVAL;
66910c4bc91dSDouglas Gilbert 
66920c4bc91dSDouglas Gilbert 	sdebug_random = v;
66930c4bc91dSDouglas Gilbert 	return count;
66940c4bc91dSDouglas Gilbert }
66950c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
66960c4bc91dSDouglas Gilbert 
669782069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6698d986788bSMartin Pitt {
6699773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6700d986788bSMartin Pitt }
670182069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
670282069379SAkinobu Mita 			       size_t count)
6703d986788bSMartin Pitt {
6704d986788bSMartin Pitt 	int n;
6705d986788bSMartin Pitt 
6706d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6707773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6708d986788bSMartin Pitt 		return count;
6709d986788bSMartin Pitt 	}
6710d986788bSMartin Pitt 	return -EINVAL;
6711d986788bSMartin Pitt }
671282069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6713d986788bSMartin Pitt 
6714cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6715cbf67842SDouglas Gilbert {
6716773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6717cbf67842SDouglas Gilbert }
6718185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6719cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6720cbf67842SDouglas Gilbert 			       size_t count)
6721cbf67842SDouglas Gilbert {
6722185dd232SDouglas Gilbert 	int n;
6723cbf67842SDouglas Gilbert 
6724cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6725185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6726185dd232SDouglas Gilbert 		return count;
6727cbf67842SDouglas Gilbert 	}
6728cbf67842SDouglas Gilbert 	return -EINVAL;
6729cbf67842SDouglas Gilbert }
6730cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6731cbf67842SDouglas Gilbert 
6732c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6733c2248fc9SDouglas Gilbert {
6734773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6735c2248fc9SDouglas Gilbert }
6736c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6737c2248fc9SDouglas Gilbert 			    size_t count)
6738c2248fc9SDouglas Gilbert {
6739c2248fc9SDouglas Gilbert 	int n;
6740c2248fc9SDouglas Gilbert 
6741c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6742773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6743c2248fc9SDouglas Gilbert 		return count;
6744c2248fc9SDouglas Gilbert 	}
6745c2248fc9SDouglas Gilbert 	return -EINVAL;
6746c2248fc9SDouglas Gilbert }
6747c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6748c2248fc9SDouglas Gilbert 
674909ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
675009ba24c1SDouglas Gilbert {
675109ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
675209ba24c1SDouglas Gilbert }
675309ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
675409ba24c1SDouglas Gilbert 
67559b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
67569b760fd8SDouglas Gilbert {
67579b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
67589b760fd8SDouglas Gilbert }
67599b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
67609b760fd8SDouglas Gilbert 			     size_t count)
67619b760fd8SDouglas Gilbert {
67629b760fd8SDouglas Gilbert 	int ret, n;
67639b760fd8SDouglas Gilbert 
67649b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
67659b760fd8SDouglas Gilbert 	if (ret)
67669b760fd8SDouglas Gilbert 		return ret;
67679b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
67689b760fd8SDouglas Gilbert 	all_config_cdb_len();
67699b760fd8SDouglas Gilbert 	return count;
67709b760fd8SDouglas Gilbert }
67719b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
67729b760fd8SDouglas Gilbert 
67739267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
67749267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
67759267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
67769267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
67779267e0ebSDouglas Gilbert };
67789267e0ebSDouglas Gilbert 
67799267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
67809267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
67819267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
67829267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
67839267e0ebSDouglas Gilbert };
67849267e0ebSDouglas Gilbert 
67859267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
67869267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
67879267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
67889267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
67899267e0ebSDouglas Gilbert };
67909267e0ebSDouglas Gilbert 
67919267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
67929267e0ebSDouglas Gilbert {
67939267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
67949267e0ebSDouglas Gilbert 
67959267e0ebSDouglas Gilbert 	if (res < 0) {
67969267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
67979267e0ebSDouglas Gilbert 		if (res < 0) {
67989267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
679947742bdeSDan Carpenter 			if (res < 0)
68009267e0ebSDouglas Gilbert 				return -EINVAL;
68019267e0ebSDouglas Gilbert 		}
68029267e0ebSDouglas Gilbert 	}
68039267e0ebSDouglas Gilbert 	return res;
68049267e0ebSDouglas Gilbert }
68059267e0ebSDouglas Gilbert 
68069267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
68079267e0ebSDouglas Gilbert {
68089267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
68099267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
68109267e0ebSDouglas Gilbert }
68119267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6812cbf67842SDouglas Gilbert 
6813fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6814fc13638aSDouglas Gilbert {
6815fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6816fc13638aSDouglas Gilbert }
6817fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6818fc13638aSDouglas Gilbert 
681982069379SAkinobu Mita /* Note: The following array creates attribute files in the
682023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
682123183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
682223183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
682387c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
682423183910SDouglas Gilbert  */
68256ecaff7fSRandy Dunlap 
682682069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
682782069379SAkinobu Mita 	&driver_attr_delay.attr,
682882069379SAkinobu Mita 	&driver_attr_opts.attr,
682982069379SAkinobu Mita 	&driver_attr_ptype.attr,
683082069379SAkinobu Mita 	&driver_attr_dsense.attr,
683182069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6832c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
683382069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
683482069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
683582069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
683682069379SAkinobu Mita 	&driver_attr_num_parts.attr,
683782069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6838ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
683982069379SAkinobu Mita 	&driver_attr_max_luns.attr,
684082069379SAkinobu Mita 	&driver_attr_max_queue.attr,
68417109f370SDouglas Gilbert 	&driver_attr_no_rwlock.attr,
684282069379SAkinobu Mita 	&driver_attr_no_uld.attr,
684382069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
684482069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
684582069379SAkinobu Mita 	&driver_attr_add_host.attr,
684687c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
684782069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
684882069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6849c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6850c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
685182069379SAkinobu Mita 	&driver_attr_dix.attr,
685282069379SAkinobu Mita 	&driver_attr_dif.attr,
685382069379SAkinobu Mita 	&driver_attr_guard.attr,
685482069379SAkinobu Mita 	&driver_attr_ato.attr,
685582069379SAkinobu Mita 	&driver_attr_map.attr,
68560c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
685782069379SAkinobu Mita 	&driver_attr_removable.attr,
6858cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6859cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6860c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
686109ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
68629b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6863fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
68649267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
686582069379SAkinobu Mita 	NULL,
686682069379SAkinobu Mita };
686782069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
68681da177e4SLinus Torvalds 
686911ddcecaSAkinobu Mita static struct device *pseudo_primary;
68708dea0d02SFUJITA Tomonori 
68711da177e4SLinus Torvalds static int __init scsi_debug_init(void)
68721da177e4SLinus Torvalds {
687387c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
68745f2578e5SFUJITA Tomonori 	unsigned long sz;
687587c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
687687c715dcSDouglas Gilbert 	int idx = -1;
68771da177e4SLinus Torvalds 
687887c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
687987c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6880cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6881cbf67842SDouglas Gilbert 
6882773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6883c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6884773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6885773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6886c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6887cbf67842SDouglas Gilbert 
6888773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6889597136abSMartin K. Petersen 	case  512:
6890597136abSMartin K. Petersen 	case 1024:
6891597136abSMartin K. Petersen 	case 2048:
6892597136abSMartin K. Petersen 	case 4096:
6893597136abSMartin K. Petersen 		break;
6894597136abSMartin K. Petersen 	default:
6895773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6896597136abSMartin K. Petersen 		return -EINVAL;
6897597136abSMartin K. Petersen 	}
6898597136abSMartin K. Petersen 
6899773642d9SDouglas Gilbert 	switch (sdebug_dif) {
69008475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6901f46eb0e9SDouglas Gilbert 		break;
69028475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
69038475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
69048475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6905f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6906c6a44287SMartin K. Petersen 		break;
6907c6a44287SMartin K. Petersen 
6908c6a44287SMartin K. Petersen 	default:
6909c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6910c6a44287SMartin K. Petersen 		return -EINVAL;
6911c6a44287SMartin K. Petersen 	}
6912c6a44287SMartin K. Petersen 
6913aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6914aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6915aa5334c4SMaurizio Lombardi 		return -EINVAL;
6916aa5334c4SMaurizio Lombardi 	}
6917aa5334c4SMaurizio Lombardi 
6918773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6919c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6920c6a44287SMartin K. Petersen 		return -EINVAL;
6921c6a44287SMartin K. Petersen 	}
6922c6a44287SMartin K. Petersen 
6923773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6924c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6925c6a44287SMartin K. Petersen 		return -EINVAL;
6926c6a44287SMartin K. Petersen 	}
6927c6a44287SMartin K. Petersen 
6928773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6929773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6930ea61fca5SMartin K. Petersen 		return -EINVAL;
6931ea61fca5SMartin K. Petersen 	}
6932ad0c7775SDouglas Gilbert 
6933ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6934ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6935ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6936ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6937ad0c7775SDouglas Gilbert 	}
6938ad0c7775SDouglas Gilbert 
69398d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6940ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6941ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
69428d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
69438d039e22SDouglas Gilbert 		}
6944ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6945ad0c7775SDouglas Gilbert 	}
6946ea61fca5SMartin K. Petersen 
6947773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6948773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6949ea61fca5SMartin K. Petersen 		return -EINVAL;
6950ea61fca5SMartin K. Petersen 	}
6951ea61fca5SMartin K. Petersen 
6952c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6953c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6954c4837394SDouglas Gilbert 		return -EINVAL;
6955c4837394SDouglas Gilbert 	}
6956c87bf24cSJohn Garry 
6957c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6958c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6959c87bf24cSJohn Garry 		return -EINVAL;
6960c87bf24cSJohn Garry 	}
6961c87bf24cSJohn Garry 
6962c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6963c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6964c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6965c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6966c10fa55fSJohn Garry 		return -EINVAL;
6967c10fa55fSJohn Garry 	}
6968c10fa55fSJohn Garry 
6969c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6970c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6971c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6972c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6973c10fa55fSJohn Garry 			sdebug_max_queue);
6974c10fa55fSJohn Garry 	}
6975c10fa55fSJohn Garry 
6976c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6977c4837394SDouglas Gilbert 			       GFP_KERNEL);
6978c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6979c4837394SDouglas Gilbert 		return -ENOMEM;
6980c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6981c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6982c4837394SDouglas Gilbert 
6983f0d1cf93SDouglas Gilbert 	/*
69849267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
69859267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6986f0d1cf93SDouglas Gilbert 	 */
69879267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
69889267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
69899267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
69909267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
69919267e0ebSDouglas Gilbert 		if (k < 0) {
69929267e0ebSDouglas Gilbert 			ret = k;
69933b01d7eaSDinghao Liu 			goto free_q_arr;
69949267e0ebSDouglas Gilbert 		}
69959267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
69969267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
69979267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
699864e14eceSDamien Le Moal 		case BLK_ZONED_HA:
69999267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
70009267e0ebSDouglas Gilbert 			break;
70019267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
70029267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
70039267e0ebSDouglas Gilbert 			break;
70049267e0ebSDouglas Gilbert 		default:
70059267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
70063b01d7eaSDinghao Liu 			ret = -EINVAL;
70073b01d7eaSDinghao Liu 			goto free_q_arr;
70089267e0ebSDouglas Gilbert 		}
70099267e0ebSDouglas Gilbert 	}
70109267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
7011f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
70129267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70139267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
70149267e0ebSDouglas Gilbert 	}
7015f0d1cf93SDouglas Gilbert 
70169267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70179267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
7018773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
7019773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
7020773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
7021773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
702228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
70231da177e4SLinus Torvalds 
70241da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
70251da177e4SLinus Torvalds 	sdebug_heads = 8;
70261da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
7027773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
70281da177e4SLinus Torvalds 		sdebug_heads = 64;
7029773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
7030fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
70311da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70321da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70331da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
70341da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
70351da177e4SLinus Torvalds 		sdebug_heads = 255;
70361da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
70371da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70381da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70391da177e4SLinus Torvalds 	}
70405b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
7041773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
7042773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
70436014759cSMartin K. Petersen 
7044773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
7045773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
70466014759cSMartin K. Petersen 
7047773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
7048773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
70496014759cSMartin K. Petersen 
7050773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
7051773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
7052773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
7053c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
7054c4837394SDouglas Gilbert 			ret = -EINVAL;
705587c715dcSDouglas Gilbert 			goto free_q_arr;
705644d92694SMartin K. Petersen 		}
705744d92694SMartin K. Petersen 	}
705887c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
705987c715dcSDouglas Gilbert 	if (want_store) {
706087c715dcSDouglas Gilbert 		idx = sdebug_add_store();
706187c715dcSDouglas Gilbert 		if (idx < 0) {
706287c715dcSDouglas Gilbert 			ret = idx;
706387c715dcSDouglas Gilbert 			goto free_q_arr;
706487c715dcSDouglas Gilbert 		}
706544d92694SMartin K. Petersen 	}
706644d92694SMartin K. Petersen 
70679b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
70689b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
7069c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
70709b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
70716ecaff7fSRandy Dunlap 		goto free_vm;
70726ecaff7fSRandy Dunlap 	}
70736ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
70746ecaff7fSRandy Dunlap 	if (ret < 0) {
7075c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
70766ecaff7fSRandy Dunlap 		goto dev_unreg;
70776ecaff7fSRandy Dunlap 	}
70786ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
70796ecaff7fSRandy Dunlap 	if (ret < 0) {
7080c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
70816ecaff7fSRandy Dunlap 		goto bus_unreg;
70826ecaff7fSRandy Dunlap 	}
70831da177e4SLinus Torvalds 
708487c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
7085773642d9SDouglas Gilbert 	sdebug_add_host = 0;
70861da177e4SLinus Torvalds 
708787c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
708887c715dcSDouglas Gilbert 		if (want_store && k == 0) {
708987c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
709087c715dcSDouglas Gilbert 			if (ret < 0) {
709187c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
709287c715dcSDouglas Gilbert 				       k, -ret);
709387c715dcSDouglas Gilbert 				break;
709487c715dcSDouglas Gilbert 			}
709587c715dcSDouglas Gilbert 		} else {
709687c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
709787c715dcSDouglas Gilbert 						 sdebug_per_host_store);
709887c715dcSDouglas Gilbert 			if (ret < 0) {
709987c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
71001da177e4SLinus Torvalds 				break;
71011da177e4SLinus Torvalds 			}
71021da177e4SLinus Torvalds 		}
710387c715dcSDouglas Gilbert 	}
7104773642d9SDouglas Gilbert 	if (sdebug_verbose)
7105f19fe8f3SBart Van Assche 		pr_info("built %d host(s)\n", sdebug_num_hosts);
7106c1287970STomas Winkler 
71071da177e4SLinus Torvalds 	return 0;
71086ecaff7fSRandy Dunlap 
71096ecaff7fSRandy Dunlap bus_unreg:
71106ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
71116ecaff7fSRandy Dunlap dev_unreg:
71129b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71136ecaff7fSRandy Dunlap free_vm:
711487c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
7115c4837394SDouglas Gilbert free_q_arr:
7116c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
71176ecaff7fSRandy Dunlap 	return ret;
71181da177e4SLinus Torvalds }
71191da177e4SLinus Torvalds 
71201da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
71211da177e4SLinus Torvalds {
7122f19fe8f3SBart Van Assche 	int k = sdebug_num_hosts;
71231da177e4SLinus Torvalds 
7124f19fe8f3SBart Van Assche 	stop_all_queued();
7125f19fe8f3SBart Van Assche 	for (; k; k--)
712687c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
712752ab9768SLuis Henriques 	free_all_queued();
71281da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
71291da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
71309b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71311da177e4SLinus Torvalds 
713287c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
713387c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
7134f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
71351da177e4SLinus Torvalds }
71361da177e4SLinus Torvalds 
71371da177e4SLinus Torvalds device_initcall(scsi_debug_init);
71381da177e4SLinus Torvalds module_exit(scsi_debug_exit);
71391da177e4SLinus Torvalds 
71401da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
71411da177e4SLinus Torvalds {
71421da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71431da177e4SLinus Torvalds 
7144785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
71451da177e4SLinus Torvalds 	kfree(sdbg_host);
71461da177e4SLinus Torvalds }
71471da177e4SLinus Torvalds 
714887c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
714987c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
71501da177e4SLinus Torvalds {
715187c715dcSDouglas Gilbert 	if (idx < 0)
715287c715dcSDouglas Gilbert 		return;
715387c715dcSDouglas Gilbert 	if (!sip) {
715487c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
715587c715dcSDouglas Gilbert 			return;
715687c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
715787c715dcSDouglas Gilbert 		if (!sip)
715887c715dcSDouglas Gilbert 			return;
715987c715dcSDouglas Gilbert 	}
716087c715dcSDouglas Gilbert 	vfree(sip->map_storep);
716187c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
716287c715dcSDouglas Gilbert 	vfree(sip->storep);
716387c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
716487c715dcSDouglas Gilbert 	kfree(sip);
716587c715dcSDouglas Gilbert }
716687c715dcSDouglas Gilbert 
716787c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
716887c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
716987c715dcSDouglas Gilbert {
717087c715dcSDouglas Gilbert 	unsigned long idx;
717187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
717287c715dcSDouglas Gilbert 
717387c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
717487c715dcSDouglas Gilbert 		if (apart_from_first)
717587c715dcSDouglas Gilbert 			apart_from_first = false;
717687c715dcSDouglas Gilbert 		else
717787c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
717887c715dcSDouglas Gilbert 	}
717987c715dcSDouglas Gilbert 	if (apart_from_first)
718087c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
718187c715dcSDouglas Gilbert }
718287c715dcSDouglas Gilbert 
718387c715dcSDouglas Gilbert /*
718487c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
718587c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
718687c715dcSDouglas Gilbert  */
718787c715dcSDouglas Gilbert static int sdebug_add_store(void)
718887c715dcSDouglas Gilbert {
718987c715dcSDouglas Gilbert 	int res;
719087c715dcSDouglas Gilbert 	u32 n_idx;
719187c715dcSDouglas Gilbert 	unsigned long iflags;
719287c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
719387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
719487c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
719587c715dcSDouglas Gilbert 
719687c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
719787c715dcSDouglas Gilbert 	if (!sip)
719887c715dcSDouglas Gilbert 		return -ENOMEM;
719987c715dcSDouglas Gilbert 
720087c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
720187c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
720287c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
720387c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
720487c715dcSDouglas Gilbert 		kfree(sip);
720587c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
720687c715dcSDouglas Gilbert 		return res;
720787c715dcSDouglas Gilbert 	}
720887c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
720987c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
721087c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
721187c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
721287c715dcSDouglas Gilbert 
721387c715dcSDouglas Gilbert 	res = -ENOMEM;
721487c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
721587c715dcSDouglas Gilbert 	if (!sip->storep) {
721687c715dcSDouglas Gilbert 		pr_err("user data oom\n");
721787c715dcSDouglas Gilbert 		goto err;
721887c715dcSDouglas Gilbert 	}
721987c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
722087c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
722187c715dcSDouglas Gilbert 
722287c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
722387c715dcSDouglas Gilbert 	if (sdebug_dix) {
722487c715dcSDouglas Gilbert 		int dif_size;
722587c715dcSDouglas Gilbert 
722687c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
722787c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
722887c715dcSDouglas Gilbert 
722987c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
723087c715dcSDouglas Gilbert 			sip->dif_storep);
723187c715dcSDouglas Gilbert 
723287c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
723387c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
723487c715dcSDouglas Gilbert 			goto err;
723587c715dcSDouglas Gilbert 		}
723687c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
723787c715dcSDouglas Gilbert 	}
723887c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
723987c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
724087c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
724187c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
724287c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
724387c715dcSDouglas Gilbert 
724487c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
724587c715dcSDouglas Gilbert 
724687c715dcSDouglas Gilbert 		if (!sip->map_storep) {
724787c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
724887c715dcSDouglas Gilbert 			goto err;
724987c715dcSDouglas Gilbert 		}
725087c715dcSDouglas Gilbert 
725187c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
725287c715dcSDouglas Gilbert 
725387c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
725487c715dcSDouglas Gilbert 		if (sdebug_num_parts)
725587c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
725687c715dcSDouglas Gilbert 	}
725787c715dcSDouglas Gilbert 
725887c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
725987c715dcSDouglas Gilbert 	return (int)n_idx;
726087c715dcSDouglas Gilbert err:
726187c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
726287c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
726387c715dcSDouglas Gilbert 	return res;
726487c715dcSDouglas Gilbert }
726587c715dcSDouglas Gilbert 
726687c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
726787c715dcSDouglas Gilbert {
726887c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
726987c715dcSDouglas Gilbert 	int error = -ENOMEM;
72701da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72718b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
72721da177e4SLinus Torvalds 
727324669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
727487c715dcSDouglas Gilbert 	if (!sdbg_host)
72751da177e4SLinus Torvalds 		return -ENOMEM;
727687c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
727787c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
727887c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
727987c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
72801da177e4SLinus Torvalds 
72811da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
72821da177e4SLinus Torvalds 
7283773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
72841da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
72855cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
728687c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
72871da177e4SLinus Torvalds 			goto clean;
72881da177e4SLinus Torvalds 	}
72891da177e4SLinus Torvalds 
72901da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
72911da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
72921da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
72931da177e4SLinus Torvalds 
72941da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
72959b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
72961da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
7297f19fe8f3SBart Van Assche 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
72981da177e4SLinus Torvalds 
72991da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
7300e208a1d7SYuan Can 	if (error) {
7301e208a1d7SYuan Can 		spin_lock(&sdebug_host_list_lock);
7302e208a1d7SYuan Can 		list_del(&sdbg_host->host_list);
7303e208a1d7SYuan Can 		spin_unlock(&sdebug_host_list_lock);
73041da177e4SLinus Torvalds 		goto clean;
7305e208a1d7SYuan Can 	}
73061da177e4SLinus Torvalds 
7307f19fe8f3SBart Van Assche 	++sdebug_num_hosts;
730887c715dcSDouglas Gilbert 	return 0;
73091da177e4SLinus Torvalds 
73101da177e4SLinus Torvalds clean:
73118b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73128b40228fSFUJITA Tomonori 				 dev_list) {
73131da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7314f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73151da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73161da177e4SLinus Torvalds 	}
7317e6d773f9SYang Yingliang 	if (sdbg_host->dev.release)
7318e6d773f9SYang Yingliang 		put_device(&sdbg_host->dev);
7319e6d773f9SYang Yingliang 	else
73201da177e4SLinus Torvalds 		kfree(sdbg_host);
732187c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
73221da177e4SLinus Torvalds 	return error;
73231da177e4SLinus Torvalds }
73241da177e4SLinus Torvalds 
732587c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
73261da177e4SLinus Torvalds {
732787c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
732887c715dcSDouglas Gilbert 
732987c715dcSDouglas Gilbert 	if (mk_new_store) {
733087c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
733187c715dcSDouglas Gilbert 		if (ph_idx < 0)
733287c715dcSDouglas Gilbert 			return ph_idx;
733387c715dcSDouglas Gilbert 	}
733487c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
733587c715dcSDouglas Gilbert }
733687c715dcSDouglas Gilbert 
733787c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
733887c715dcSDouglas Gilbert {
733987c715dcSDouglas Gilbert 	int idx = -1;
73401da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
734187c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
73421da177e4SLinus Torvalds 
73431da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73441da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
73451da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
73461da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
734787c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
73481da177e4SLinus Torvalds 	}
734987c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
735087c715dcSDouglas Gilbert 		bool unique = true;
735187c715dcSDouglas Gilbert 
735287c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
735387c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
735487c715dcSDouglas Gilbert 				continue;
735587c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
735687c715dcSDouglas Gilbert 				unique = false;
735787c715dcSDouglas Gilbert 				break;
735887c715dcSDouglas Gilbert 			}
735987c715dcSDouglas Gilbert 		}
736087c715dcSDouglas Gilbert 		if (unique) {
736187c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
736287c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
736387c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
736487c715dcSDouglas Gilbert 		}
736587c715dcSDouglas Gilbert 	}
736687c715dcSDouglas Gilbert 	if (sdbg_host)
736787c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
73681da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73691da177e4SLinus Torvalds 
73701da177e4SLinus Torvalds 	if (!sdbg_host)
73711da177e4SLinus Torvalds 		return;
73721da177e4SLinus Torvalds 
73731da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
7374f19fe8f3SBart Van Assche 	--sdebug_num_hosts;
73751da177e4SLinus Torvalds }
73761da177e4SLinus Torvalds 
7377fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7378cbf67842SDouglas Gilbert {
7379cbf67842SDouglas Gilbert 	int num_in_q = 0;
7380cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7381cbf67842SDouglas Gilbert 
7382f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
7383cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7384cbf67842SDouglas Gilbert 	if (NULL == devip) {
7385f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
7386cbf67842SDouglas Gilbert 		return	-ENODEV;
7387cbf67842SDouglas Gilbert 	}
7388cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7389c40ecc12SChristoph Hellwig 
7390fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7391fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7392fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7393fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7394fc09acb7SDouglas Gilbert 	}
7395cbf67842SDouglas Gilbert 	if (qdepth < 1)
7396cbf67842SDouglas Gilbert 		qdepth = 1;
7397fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7398db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7399cbf67842SDouglas Gilbert 
7400773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7401c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7402c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7403cbf67842SDouglas Gilbert 	}
7404f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
7405cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7406cbf67842SDouglas Gilbert }
7407cbf67842SDouglas Gilbert 
7408c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7409817fd66bSDouglas Gilbert {
7410c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7411773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7412773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7413773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7414c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7415773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7416817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7417c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7418817fd66bSDouglas Gilbert 	}
7419c4837394SDouglas Gilbert 	return false;
7420817fd66bSDouglas Gilbert }
7421817fd66bSDouglas Gilbert 
7422fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7423fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7424fc13638aSDouglas Gilbert {
7425fc13638aSDouglas Gilbert 	int stopped_state;
7426fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7427fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7428fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7429fc13638aSDouglas Gilbert 
7430fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7431fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7432fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7433fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7434fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7435fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7436fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7437fc13638aSDouglas Gilbert 				return 0;
7438fc13638aSDouglas Gilbert 			}
7439fc13638aSDouglas Gilbert 		}
7440fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7441fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7442fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7443fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7444fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7445fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7446fc13638aSDouglas Gilbert 
7447fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7448fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7449fc13638aSDouglas Gilbert 			else
7450fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7451fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7452fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7453fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7454fc13638aSDouglas Gilbert 						   diff_ns);
7455fc13638aSDouglas Gilbert 			return check_condition_result;
7456fc13638aSDouglas Gilbert 		}
7457fc13638aSDouglas Gilbert 	}
7458fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7459fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7460fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7461fc13638aSDouglas Gilbert 			    my_name);
7462fc13638aSDouglas Gilbert 	return check_condition_result;
7463fc13638aSDouglas Gilbert }
7464fc13638aSDouglas Gilbert 
7465a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost)
7466c4b57d89SKashyap Desai {
7467c4b57d89SKashyap Desai 	int i, qoff;
7468c4b57d89SKashyap Desai 
7469c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7470a4e1d0b7SBart Van Assche 		return;
7471c4b57d89SKashyap Desai 
7472c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7473c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7474c4b57d89SKashyap Desai 
7475c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7476c4b57d89SKashyap Desai 
7477c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7478c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7479c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7480c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7481c4b57d89SKashyap Desai 
7482c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7483c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7484c4b57d89SKashyap Desai 			continue;
7485c4b57d89SKashyap Desai 		}
7486c4b57d89SKashyap Desai 
7487c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7488c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7489c4b57d89SKashyap Desai 
7490c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7491c4b57d89SKashyap Desai 	}
7492c4b57d89SKashyap Desai }
7493c4b57d89SKashyap Desai 
7494c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7495c4b57d89SKashyap Desai {
74964a0c6f43SDouglas Gilbert 	bool first;
74974a0c6f43SDouglas Gilbert 	bool retiring = false;
74984a0c6f43SDouglas Gilbert 	int num_entries = 0;
74994a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7500c4b57d89SKashyap Desai 	unsigned long iflags;
75014a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7502c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7503c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7504c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7505c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
75064a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7507c4b57d89SKashyap Desai 
7508c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
75094a0c6f43SDouglas Gilbert 
7510c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
75114a0c6f43SDouglas Gilbert 
75126a0d0ae3SDamien Le Moal 	qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
75136a0d0ae3SDamien Le Moal 	if (qc_idx >= sdebug_max_queue)
75146a0d0ae3SDamien Le Moal 		goto unlock;
75156a0d0ae3SDamien Le Moal 
75164a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
75174a0c6f43SDouglas Gilbert 		if (first) {
75184a0c6f43SDouglas Gilbert 			first = false;
7519b05d4e48SDouglas Gilbert 			if (!test_bit(qc_idx, sqp->in_use_bm))
7520b05d4e48SDouglas Gilbert 				continue;
75214a0c6f43SDouglas Gilbert 		} else {
75224a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
75234a0c6f43SDouglas Gilbert 		}
7524b05d4e48SDouglas Gilbert 		if (qc_idx >= sdebug_max_queue)
75254a0c6f43SDouglas Gilbert 			break;
7526c4b57d89SKashyap Desai 
7527c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
75284a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
75294a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
75304a0c6f43SDouglas Gilbert 			continue;
7531c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7532c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
75334a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7534c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
75354a0c6f43SDouglas Gilbert 			break;
7536c4b57d89SKashyap Desai 		}
7537d9d23a5aSDouglas Gilbert 		if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) {
75384a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
75394a0c6f43SDouglas Gilbert 				continue;
75404a0c6f43SDouglas Gilbert 
75416ce913feSChristoph Hellwig 		} else		/* ignoring non REQ_POLLED requests */
75424a0c6f43SDouglas Gilbert 			continue;
7543c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7544c4b57d89SKashyap Desai 		if (likely(devip))
7545c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7546c4b57d89SKashyap Desai 		else
7547c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7548c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
75494a0c6f43SDouglas Gilbert 			retiring = true;
7550c4b57d89SKashyap Desai 
7551c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7552c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
75534a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7554c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
75554a0c6f43SDouglas Gilbert 			break;
7556c4b57d89SKashyap Desai 		}
7557c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7558c4b57d89SKashyap Desai 			int k, retval;
7559c4b57d89SKashyap Desai 
7560c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7561c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7562c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
75634a0c6f43SDouglas Gilbert 				break;
7564c4b57d89SKashyap Desai 			}
7565c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7566c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7567c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7568c4b57d89SKashyap Desai 			else
7569c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7570c4b57d89SKashyap Desai 		}
7571d9d23a5aSDouglas Gilbert 		WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
7572c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75736c2c7d6aSBart Van Assche 		scsi_done(scp); /* callback to mid level */
7574c4b57d89SKashyap Desai 		num_entries++;
75753fd07aecSDamien Le Moal 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7576b05d4e48SDouglas Gilbert 		if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue)
75773fd07aecSDamien Le Moal 			break;
75784a0c6f43SDouglas Gilbert 	}
75793fd07aecSDamien Le Moal 
75806a0d0ae3SDamien Le Moal unlock:
7581c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75823fd07aecSDamien Le Moal 
75834a0c6f43SDouglas Gilbert 	if (num_entries > 0)
75844a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7585c4b57d89SKashyap Desai 	return num_entries;
7586c4b57d89SKashyap Desai }
7587c4b57d89SKashyap Desai 
7588fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7589fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7590c2248fc9SDouglas Gilbert {
7591c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7592c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7593c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7594c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7595c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7596c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7597c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7598f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7599c2248fc9SDouglas Gilbert 	int k, na;
7600c2248fc9SDouglas Gilbert 	int errsts = 0;
7601ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7602c2248fc9SDouglas Gilbert 	u32 flags;
7603c2248fc9SDouglas Gilbert 	u16 sa;
7604c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7605c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
76063a90a63dSDouglas Gilbert 	bool inject_now;
7607c2248fc9SDouglas Gilbert 
7608c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
76093a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7610c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
76113a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
76123a90a63dSDouglas Gilbert 	} else {
76133a90a63dSDouglas Gilbert 		inject_now = false;
76143a90a63dSDouglas Gilbert 	}
7615f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7616f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7617c2248fc9SDouglas Gilbert 		char b[120];
7618c2248fc9SDouglas Gilbert 		int n, len, sb;
7619c2248fc9SDouglas Gilbert 
7620c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7621c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7622c2248fc9SDouglas Gilbert 		if (len > 32)
7623c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7624c2248fc9SDouglas Gilbert 		else {
7625c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7626c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7627c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7628c2248fc9SDouglas Gilbert 		}
7629458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7630a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7631c2248fc9SDouglas Gilbert 	}
76323a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
76337ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
763434d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7635ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7636f46eb0e9SDouglas Gilbert 		goto err_out;
7637c2248fc9SDouglas Gilbert 
7638c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7639c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7640c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7641f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7642f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7643c2248fc9SDouglas Gilbert 		if (NULL == devip)
7644f46eb0e9SDouglas Gilbert 			goto err_out;
7645c2248fc9SDouglas Gilbert 	}
76463a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
76473a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
76483a90a63dSDouglas Gilbert 
7649c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7650c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7651c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7652c2248fc9SDouglas Gilbert 		r_oip = oip;
7653c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7654c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7655c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7656c2248fc9SDouglas Gilbert 			else
7657c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7658c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7659c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7660c2248fc9SDouglas Gilbert 					break;
7661c2248fc9SDouglas Gilbert 			}
7662c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7663c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7664c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7665c2248fc9SDouglas Gilbert 					break;
7666c2248fc9SDouglas Gilbert 			}
7667c2248fc9SDouglas Gilbert 		}
7668c2248fc9SDouglas Gilbert 		if (k > na) {
7669c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7670c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7671c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7672c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7673c2248fc9SDouglas Gilbert 			else
7674c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7675c2248fc9SDouglas Gilbert 			goto check_cond;
7676c2248fc9SDouglas Gilbert 		}
7677c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7678c2248fc9SDouglas Gilbert 	flags = oip->flags;
7679f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7680c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7681c2248fc9SDouglas Gilbert 		goto check_cond;
7682c2248fc9SDouglas Gilbert 	}
7683f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7684773642d9SDouglas Gilbert 		if (sdebug_verbose)
7685773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7686773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7687c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7688c2248fc9SDouglas Gilbert 		goto check_cond;
7689c2248fc9SDouglas Gilbert 	}
7690f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7691c2248fc9SDouglas Gilbert 		u8 rem;
7692c2248fc9SDouglas Gilbert 		int j;
7693c2248fc9SDouglas Gilbert 
7694c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7695c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7696c2248fc9SDouglas Gilbert 			if (rem) {
7697c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7698c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7699c2248fc9SDouglas Gilbert 						break;
7700c2248fc9SDouglas Gilbert 				}
7701c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7702c2248fc9SDouglas Gilbert 				goto check_cond;
7703c2248fc9SDouglas Gilbert 			}
7704c2248fc9SDouglas Gilbert 		}
7705c2248fc9SDouglas Gilbert 	}
7706f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7707b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7708b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7709f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7710c2248fc9SDouglas Gilbert 		if (errsts)
7711c2248fc9SDouglas Gilbert 			goto check_cond;
7712c2248fc9SDouglas Gilbert 	}
7713fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7714fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7715fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7716fc13638aSDouglas Gilbert 		if (errsts)
7717c2248fc9SDouglas Gilbert 			goto fini;
7718c2248fc9SDouglas Gilbert 	}
7719773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7720c2248fc9SDouglas Gilbert 		goto fini;
7721f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7722c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7723c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7724c2248fc9SDouglas Gilbert 	}
7725f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7726f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7727f66b8517SMartin Wilck 	else
7728f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7729c2248fc9SDouglas Gilbert 
7730c2248fc9SDouglas Gilbert fini:
773167da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7732f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
773375aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
773475aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
773580c49563SDouglas Gilbert 		/*
773675aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
773775aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
773875aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
773975aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
774080c49563SDouglas Gilbert 		 */
774180c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
77424f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
774380c49563SDouglas Gilbert 
77444f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7745f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
774680c49563SDouglas Gilbert 	} else
7747f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
774810bde980SDouglas Gilbert 				     sdebug_ndelay);
7749c2248fc9SDouglas Gilbert check_cond:
7750f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7751f46eb0e9SDouglas Gilbert err_out:
7752f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7753c2248fc9SDouglas Gilbert }
7754c2248fc9SDouglas Gilbert 
77559e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7756c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7757c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
77589e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
77599e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
77609e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
77619e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
77629e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
77639e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
77649e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7765185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7766cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7767c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7768c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
77699e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
77709e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7771cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7772cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
77739e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7774c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
77759e603ca0SFUJITA Tomonori 	.this_id =		7,
777665e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7777cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
77786bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
777950c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
77809e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7781c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
77829e603ca0SFUJITA Tomonori };
77839e603ca0SFUJITA Tomonori 
77841da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
77851da177e4SLinus Torvalds {
77861da177e4SLinus Torvalds 	int error = 0;
77871da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
77881da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7789f46eb0e9SDouglas Gilbert 	int hprot;
77901da177e4SLinus Torvalds 
7791785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
77921da177e4SLinus Torvalds 
7793773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7794fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
77952a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
77964af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
77974af14d11SChristoph Hellwig 
7798785d6b7cSJohn Garry 	hpnt = scsi_host_alloc(&sdebug_driver_template, 0);
77991da177e4SLinus Torvalds 	if (NULL == hpnt) {
7800c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
78011da177e4SLinus Torvalds 		error = -ENODEV;
78021da177e4SLinus Torvalds 		return error;
78031da177e4SLinus Torvalds 	}
7804c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
78059b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7806c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7807c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7808c4837394SDouglas Gilbert 	}
7809c10fa55fSJohn Garry 	/*
7810c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7811f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7812c10fa55fSJohn Garry 	 */
7813c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7814f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7815f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
78161da177e4SLinus Torvalds 
7817c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7818c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7819c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7820c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7821c4b57d89SKashyap Desai 		poll_queues = 0;
7822c4b57d89SKashyap Desai 	}
7823c4b57d89SKashyap Desai 
7824c4b57d89SKashyap Desai 	/*
7825c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7826c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7827c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7828c4b57d89SKashyap Desai 	 */
7829c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7830fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7831c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7832fc09acb7SDouglas Gilbert 		else
7833fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7834fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7835c4b57d89SKashyap Desai 		poll_queues = 1;
7836c4b57d89SKashyap Desai 	}
7837c4b57d89SKashyap Desai 	if (poll_queues)
7838c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7839c4b57d89SKashyap Desai 
78401da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
7841773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7842773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
78431da177e4SLinus Torvalds 	else
7844773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7845773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7846f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
78471da177e4SLinus Torvalds 
7848f46eb0e9SDouglas Gilbert 	hprot = 0;
7849c6a44287SMartin K. Petersen 
7850773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7851c6a44287SMartin K. Petersen 
78528475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7853f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7854773642d9SDouglas Gilbert 		if (sdebug_dix)
7855f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7856c6a44287SMartin K. Petersen 		break;
7857c6a44287SMartin K. Petersen 
78588475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7859f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7860773642d9SDouglas Gilbert 		if (sdebug_dix)
7861f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7862c6a44287SMartin K. Petersen 		break;
7863c6a44287SMartin K. Petersen 
78648475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7865f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7866773642d9SDouglas Gilbert 		if (sdebug_dix)
7867f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7868c6a44287SMartin K. Petersen 		break;
7869c6a44287SMartin K. Petersen 
7870c6a44287SMartin K. Petersen 	default:
7871773642d9SDouglas Gilbert 		if (sdebug_dix)
7872f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7873c6a44287SMartin K. Petersen 		break;
7874c6a44287SMartin K. Petersen 	}
7875c6a44287SMartin K. Petersen 
7876f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7877c6a44287SMartin K. Petersen 
7878f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7879c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7880f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7881f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7882f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7883f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7884f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7885f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7886f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7887c6a44287SMartin K. Petersen 
7888773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7889c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7890c6a44287SMartin K. Petersen 	else
7891c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7892c6a44287SMartin K. Petersen 
7893773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7894773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7895c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7896c4837394SDouglas Gilbert 		sdebug_statistics = true;
78971da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
78981da177e4SLinus Torvalds 	if (error) {
7899c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
79001da177e4SLinus Torvalds 		error = -ENODEV;
79011da177e4SLinus Torvalds 		scsi_host_put(hpnt);
790287c715dcSDouglas Gilbert 	} else {
79031da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
790487c715dcSDouglas Gilbert 	}
79051da177e4SLinus Torvalds 
79061da177e4SLinus Torvalds 	return error;
79071da177e4SLinus Torvalds }
79081da177e4SLinus Torvalds 
7909fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
79101da177e4SLinus Torvalds {
79111da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
79128b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
79131da177e4SLinus Torvalds 
7914785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
79151da177e4SLinus Torvalds 
79161da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
79171da177e4SLinus Torvalds 
79188b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
79198b40228fSFUJITA Tomonori 				 dev_list) {
79201da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7921f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
79221da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
79231da177e4SLinus Torvalds 	}
79241da177e4SLinus Torvalds 
79251da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
79261da177e4SLinus Torvalds }
79271da177e4SLinus Torvalds 
79288dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
79298dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
79301da177e4SLinus Torvalds {
79318dea0d02SFUJITA Tomonori 	return 1;
79328dea0d02SFUJITA Tomonori }
79331da177e4SLinus Torvalds 
79348dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
79358dea0d02SFUJITA Tomonori 	.name = "pseudo",
79368dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
79378dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
79388dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
793982069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
79408dea0d02SFUJITA Tomonori };
7941