xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 3344b58b)
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  *
1048e3bf16SDouglas Gilbert  * Copyright (C) 2001 - 2020 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>
191da177e4SLinus Torvalds 
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/genhd.h>
271da177e4SLinus Torvalds #include <linux/fs.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/vmalloc.h>
311da177e4SLinus Torvalds #include <linux/moduleparam.h>
32852e034dSJens Axboe #include <linux/scatterlist.h>
331da177e4SLinus Torvalds #include <linux/blkdev.h>
34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
35cbf67842SDouglas Gilbert #include <linux/spinlock.h>
36cbf67842SDouglas Gilbert #include <linux/interrupt.h>
37cbf67842SDouglas Gilbert #include <linux/atomic.h>
38cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3909ba24c1SDouglas Gilbert #include <linux/uuid.h>
406ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
411442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
420c4bc91dSDouglas Gilbert #include <linux/random.h>
4387c715dcSDouglas Gilbert #include <linux/xarray.h>
44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6330f67481SDouglas Gilbert #define SDEBUG_VERSION "0190"	/* format to fit INQUIRY revision field */
6430f67481SDouglas Gilbert static const char *sdebug_version_date = "20200710";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
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
101f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1021da177e4SLinus Torvalds 
1036f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1046f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1056f3cbf55SDouglas Gilbert 
1061da177e4SLinus Torvalds /* Default values for driver parameters */
1071da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1081da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1091da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1111da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1121da177e4SLinus Torvalds  */
1135b94e232SMartin K. Petersen #define DEF_ATO 1
1149b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
115c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1169267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1171da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1189267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1195b94e232SMartin K. Petersen #define DEF_DIF 0
1205b94e232SMartin K. Petersen #define DEF_DIX 0
12187c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1225b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1231da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1245b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1255b94e232SMartin K. Petersen #define DEF_GUARD 0
126cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1275b94e232SMartin K. Petersen #define DEF_LBPU 0
1285b94e232SMartin K. Petersen #define DEF_LBPWS 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS10 0
130be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1315b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
132cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1335b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1341da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1351da177e4SLinus Torvalds #define DEF_OPTS   0
13632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1375b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
139b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1400c4bc91dSDouglas Gilbert #define DEF_RANDOM false
141d986788bSMartin Pitt #define DEF_REMOVABLE false
142760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1435b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1445b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1455b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1466014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1485b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1495b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1505b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
151c2248fc9SDouglas Gilbert #define DEF_STRICT 0
152c4837394SDouglas Gilbert #define DEF_STATISTICS false
153c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
154fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15509ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
156c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1571da177e4SLinus Torvalds 
158f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
159f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
161aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
162f0d1cf93SDouglas Gilbert 
163b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
164b01f6f83SDouglas Gilbert 
165773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
166773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
167773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
168773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
169773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
170773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
171773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
173773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
174773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
175773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
176773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
177773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
178773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
179773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
180773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1817ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1827382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
183773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
184773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
185773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
186773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
187773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1887ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1897382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1907382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1913a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1923a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1931da177e4SLinus Torvalds 
194cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
195cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
196cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
197cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
198cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
200cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2010d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
20219c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
203acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
204acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
205acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
206cbf67842SDouglas Gilbert 
207773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2081da177e4SLinus Torvalds  * sector on read commands: */
2091da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21032f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2111da177e4SLinus Torvalds 
212c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
213c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
214c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
215c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
216c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
217c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
218c4837394SDouglas Gilbert  */
219c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
220c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
221fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN  SDEBUG_CANQUEUE
222cbf67842SDouglas Gilbert 
223b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
224b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
225b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
226fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
227fd32119bSDouglas Gilbert #define F_D_UNKN		8
228b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
229b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
230b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
231b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
232b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
233b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
234b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
235b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
236b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
237b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
238fd32119bSDouglas Gilbert 
239b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
240fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24146f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
242fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2434f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
244fd32119bSDouglas Gilbert 
245fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
246fd32119bSDouglas Gilbert 
247b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
248fd32119bSDouglas Gilbert 
24987c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25087c715dcSDouglas Gilbert 
25164e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25264e14eceSDamien Le Moal enum sdebug_z_type {
25364e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_CNV	= 0x1,
25464e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWR	= 0x2,
25564e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWP	= 0x3,
25664e14eceSDamien Le Moal };
25764e14eceSDamien Le Moal 
258f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
259f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
260f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
261f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
262f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
263f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
264f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
265f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
266f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
267f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
268f0d1cf93SDouglas Gilbert };
269f0d1cf93SDouglas Gilbert 
270f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
27164e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
272f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
27364e14eceSDamien Le Moal 	bool z_non_seq_resource;
274f0d1cf93SDouglas Gilbert 	unsigned int z_size;
275f0d1cf93SDouglas Gilbert 	sector_t z_start;
276f0d1cf93SDouglas Gilbert 	sector_t z_wp;
277f0d1cf93SDouglas Gilbert };
278fd32119bSDouglas Gilbert 
279fd32119bSDouglas Gilbert struct sdebug_dev_info {
280fd32119bSDouglas Gilbert 	struct list_head dev_list;
281fd32119bSDouglas Gilbert 	unsigned int channel;
282fd32119bSDouglas Gilbert 	unsigned int target;
283fd32119bSDouglas Gilbert 	u64 lun;
284bf476433SChristoph Hellwig 	uuid_t lu_name;
285fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
286fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
287fd32119bSDouglas Gilbert 	atomic_t num_in_q;
288fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
289fd32119bSDouglas Gilbert 	bool used;
290f0d1cf93SDouglas Gilbert 
291f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
29264e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
293f0d1cf93SDouglas Gilbert 	unsigned int zsize;
294f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
295f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
296aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
297f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
298f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
299f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
300f0d1cf93SDouglas Gilbert 	unsigned int max_open;
301fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
302f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
303fd32119bSDouglas Gilbert };
304fd32119bSDouglas Gilbert 
305fd32119bSDouglas Gilbert struct sdebug_host_info {
306fd32119bSDouglas Gilbert 	struct list_head host_list;
30787c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
308fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
309fd32119bSDouglas Gilbert 	struct device dev;
310fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
311fd32119bSDouglas Gilbert };
312fd32119bSDouglas Gilbert 
31387c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
31487c715dcSDouglas Gilbert struct sdeb_store_info {
31587c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
31687c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
31787c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
31887c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
31987c715dcSDouglas Gilbert };
32087c715dcSDouglas Gilbert 
321fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
322fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
323fd32119bSDouglas Gilbert 
32410bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3254a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
32610bde980SDouglas Gilbert 
327fd32119bSDouglas Gilbert struct sdebug_defer {
328fd32119bSDouglas Gilbert 	struct hrtimer hrt;
329fd32119bSDouglas Gilbert 	struct execute_work ew;
3304a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
331c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
332c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
333c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
334c4837394SDouglas Gilbert 	int issuing_cpu;
33510bde980SDouglas Gilbert 	bool init_hrt;
33610bde980SDouglas Gilbert 	bool init_wq;
3374a0c6f43SDouglas Gilbert 	bool init_poll;
3387382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
33910bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
340fd32119bSDouglas Gilbert };
341fd32119bSDouglas Gilbert 
342fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
343c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
344c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
345c4837394SDouglas Gilbert 	 */
346fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
347fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
348fd32119bSDouglas Gilbert };
349fd32119bSDouglas Gilbert 
350c4837394SDouglas Gilbert struct sdebug_queue {
351c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
352c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
353c4837394SDouglas Gilbert 	spinlock_t qc_lock;
354c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
355fd32119bSDouglas Gilbert };
356fd32119bSDouglas Gilbert 
357c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
358c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
359c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
360c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3613a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3624a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
363c4837394SDouglas Gilbert 
364fd32119bSDouglas Gilbert struct opcode_info_t {
365b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
366b01f6f83SDouglas Gilbert 				/* for terminating element */
367fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
368fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
369fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
370fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
371fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3729a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3739a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
374fd32119bSDouglas Gilbert };
375fd32119bSDouglas Gilbert 
376fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
377c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
378c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
379c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
380c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
381c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
382c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
383c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
384c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
385c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
386c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
387c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
388c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
389c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39046f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39146f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
392c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
393c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
394c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
395481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
396c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
397c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
398c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
399c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
400c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
401c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
402c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
403c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
404c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
405c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
406c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
407ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
408f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
409f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
410f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
411c2248fc9SDouglas Gilbert };
412c2248fc9SDouglas Gilbert 
413c4837394SDouglas Gilbert 
414c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
415c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
416c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
417c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
418c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
419c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
420c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
421c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
422c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
423c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
424c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
425c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
426ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
427c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
428c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
429c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
430c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
431c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
432c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
433c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
434fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
435c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
436c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
437c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
438c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
439c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
440c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
441c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
442f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
443f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44446f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
445c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
446c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
447c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
44846f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
44946f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
450c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
451c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
452c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
455c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
456c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
457c2248fc9SDouglas Gilbert };
458c2248fc9SDouglas Gilbert 
45980c49563SDouglas Gilbert /*
46080c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46180c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46280c49563SDouglas Gilbert  * command completion, they can mask their return value with
46380c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46480c49563SDouglas Gilbert  */
46580c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46680c49563SDouglas Gilbert 
467c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
468c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
469c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
470c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
476481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
484c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
48738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
488acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
48980c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
490ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
491f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
492f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
493f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
494f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
495f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
496c2248fc9SDouglas Gilbert 
49787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
49887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
49987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50087c715dcSDouglas Gilbert static int sdebug_add_store(void);
50187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50287c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50387c715dcSDouglas Gilbert 
50446f64e70SDouglas Gilbert /*
50546f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50646f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
50746f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
50846f64e70SDouglas Gilbert  */
50946f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
510c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
511c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512c2248fc9SDouglas Gilbert };
513c2248fc9SDouglas Gilbert 
51446f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
515c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
516c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517c2248fc9SDouglas Gilbert };
518c2248fc9SDouglas Gilbert 
51946f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52046f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
521b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
522c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52346f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
524c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52546f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
526b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
527c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
528c2248fc9SDouglas Gilbert };
529c2248fc9SDouglas Gilbert 
53046f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53146f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53246f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53346f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53446f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53546f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53646f64e70SDouglas Gilbert 		   0, 0, 0} },
53746f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
53846f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53946f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
540c2248fc9SDouglas Gilbert };
541c2248fc9SDouglas Gilbert 
542c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
543c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
544c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
545c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
546c3e2fe92SDouglas Gilbert };
547c3e2fe92SDouglas Gilbert 
54846f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
549c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
550c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55146f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
552c2248fc9SDouglas Gilbert };
553c2248fc9SDouglas Gilbert 
55446f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55546f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
556b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
557c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
558481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
559481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
560481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
561c2248fc9SDouglas Gilbert };
562c2248fc9SDouglas Gilbert 
56346f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56438d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
565c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56646f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
56738d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
568c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
56946f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
570c2248fc9SDouglas Gilbert };
571c2248fc9SDouglas Gilbert 
57246f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57346f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
574c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57546f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
576c2248fc9SDouglas Gilbert };
577c2248fc9SDouglas Gilbert 
57846f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
579c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
580c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
581c2248fc9SDouglas Gilbert };
582c2248fc9SDouglas Gilbert 
58346f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
584c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
585c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
586c2248fc9SDouglas Gilbert };
587c2248fc9SDouglas Gilbert 
58880c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5894f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59080c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59180c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59280c49563SDouglas Gilbert };
59380c49563SDouglas Gilbert 
594ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
595b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
596ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
597ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
598ed9f3e25SDouglas Gilbert };
599ed9f3e25SDouglas Gilbert 
600f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
601b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
602f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
604b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
605f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
607b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
608f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
609f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
610f0d1cf93SDouglas Gilbert };
611f0d1cf93SDouglas Gilbert 
612f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
613b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
614f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
615f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
616f0d1cf93SDouglas Gilbert };
617f0d1cf93SDouglas Gilbert 
618c2248fc9SDouglas Gilbert 
619c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
620c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
621c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
622ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
623c2248fc9SDouglas Gilbert /* 0 */
62446f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
625c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62646f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
627c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
628c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
629c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63046f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
631c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
632c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
633c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
634c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63546f64e70SDouglas Gilbert /* 5 */
63646f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
63746f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
63846f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
63946f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64046f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64146f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64246f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
643c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
644c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64546f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
646c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
647c2248fc9SDouglas Gilbert 	     0, 0} },
64846f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
64946f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65046f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
651c2248fc9SDouglas Gilbert /* 10 */
65246f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65346f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65446f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65580c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6564f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
657c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65846f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
65946f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66046f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66146f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
662481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
663481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
664481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66546f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66646f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
66746f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
66846f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
66946f64e70SDouglas Gilbert /* 15 */
670c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
671c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
672c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
673c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
674c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
675c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67646f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
67746f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
67846f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
67946f64e70SDouglas Gilbert 	     0xff, 0xff} },
68046f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68146f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
682c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
683c2248fc9SDouglas Gilbert 	     0} },
68446f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68546f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
686c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
687c2248fc9SDouglas Gilbert 	     0} },
688c2248fc9SDouglas Gilbert /* 20 */
689f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
690f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
691c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
692c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
693c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
694c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
695c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
696c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
69746f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
698b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
69946f64e70SDouglas Gilbert /* 25 */
700acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
701acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
702acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70346f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70446f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70546f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70646f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7074f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
70880c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
709b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71080c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71146f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
712c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
713b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
714b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
715ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
716ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
717ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
718c2248fc9SDouglas Gilbert 
719ed9f3e25SDouglas Gilbert /* 30 */
720b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
721f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
722f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
723f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
724b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
725f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
726f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
727f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
728f0d1cf93SDouglas Gilbert /* sentinel */
729c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
730c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
731c2248fc9SDouglas Gilbert };
732c2248fc9SDouglas Gilbert 
73387c715dcSDouglas Gilbert static int sdebug_num_hosts;
73487c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
735773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7369b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
737c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7389267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
739773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
740773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
741773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
742773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
743773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
744773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
745c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
746773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
747773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
748c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
749d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
750d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
751cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
752c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
753773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
754773642d9SDouglas Gilbert static int sdebug_no_uld;
755773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
756773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
757773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
758773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
759773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76086e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
761b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
762773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
763773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
764fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
765773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
766773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
767773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
768773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
769773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
770773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
771773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
772773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
773773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
775773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
77609ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7770c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
77887c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
779773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
780773642d9SDouglas Gilbert static bool sdebug_clustering;
781773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
782773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
783817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
784773642d9SDouglas Gilbert static bool sdebug_verbose;
785f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7864f2c8bf6SDouglas Gilbert static bool write_since_sync;
787c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7889447b6ceSMartin K. Petersen static bool sdebug_wp;
7899267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7909267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7919267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7921da177e4SLinus Torvalds 
793ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
794ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
795ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
796ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
797ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
798ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
799ad0c7775SDouglas Gilbert 
800c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8011da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8041da177e4SLinus Torvalds    may still need them */
8051da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8061da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8071da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8111da177e4SLinus Torvalds 
81287c715dcSDouglas Gilbert static struct xarray per_store_arr;
81387c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
81487c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
81587c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
81687c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8171da177e4SLinus Torvalds 
81844d92694SMartin K. Petersen static unsigned long map_size;
819cbf67842SDouglas Gilbert static int num_aborts;
820cbf67842SDouglas Gilbert static int num_dev_resets;
821cbf67842SDouglas Gilbert static int num_target_resets;
822cbf67842SDouglas Gilbert static int num_bus_resets;
823cbf67842SDouglas Gilbert static int num_host_resets;
824c6a44287SMartin K. Petersen static int dix_writes;
825c6a44287SMartin K. Petersen static int dix_reads;
826c6a44287SMartin K. Petersen static int dif_errors;
8271da177e4SLinus Torvalds 
828f0d1cf93SDouglas Gilbert /* ZBC global data */
82964e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
83098e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
831380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
832aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
833f0d1cf93SDouglas Gilbert 
834c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
835c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
836c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
837fd32119bSDouglas Gilbert 
8381da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
83987c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84087c715dcSDouglas Gilbert 
84187c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8421da177e4SLinus Torvalds 
843cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
844cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8491da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8501da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8511da177e4SLinus Torvalds };
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds static const int check_condition_result =
854464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8551da177e4SLinus Torvalds 
856c6a44287SMartin K. Petersen static const int illegal_condition_result =
857464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
858c6a44287SMartin K. Petersen 
859cbf67842SDouglas Gilbert static const int device_qfull_result =
8607a64c814SHannes Reinecke 	(DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
861cbf67842SDouglas Gilbert 
862ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
863ed9f3e25SDouglas Gilbert 
864fd32119bSDouglas Gilbert 
865760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
866760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
867760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
868760f3b03SDouglas Gilbert  */
869760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
870fd32119bSDouglas Gilbert {
871fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
872fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
873fd32119bSDouglas Gilbert }
874c65b1445SDouglas Gilbert 
87587c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
87687c715dcSDouglas Gilbert 			    unsigned long long lba)
87714faa944SAkinobu Mita {
87887c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
87914faa944SAkinobu Mita 
88087c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88187c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88287c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
88387c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
88487c715dcSDouglas Gilbert 	}
88587c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
88614faa944SAkinobu Mita }
88714faa944SAkinobu Mita 
88887c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
88987c715dcSDouglas Gilbert 				      sector_t sector)
89014faa944SAkinobu Mita {
89149413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89214faa944SAkinobu Mita 
89387c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
89414faa944SAkinobu Mita }
89514faa944SAkinobu Mita 
8968dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8978dea0d02SFUJITA Tomonori {
8988dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
8998dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9008dea0d02SFUJITA Tomonori 
9018dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9028dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9038dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9048dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
905773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
906773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9078dea0d02SFUJITA Tomonori 		else
908773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
909773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
910f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9118dea0d02SFUJITA Tomonori 	}
9128dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9138dea0d02SFUJITA Tomonori }
9148dea0d02SFUJITA Tomonori 
91522017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
91622017ed2SDouglas Gilbert 
91722017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
918fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
919fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92022017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92122017ed2SDouglas Gilbert {
92222017ed2SDouglas Gilbert 	unsigned char *sbuff;
92322017ed2SDouglas Gilbert 	u8 sks[4];
92422017ed2SDouglas Gilbert 	int sl, asc;
92522017ed2SDouglas Gilbert 
92622017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
92722017ed2SDouglas Gilbert 	if (!sbuff) {
92822017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
92922017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93022017ed2SDouglas Gilbert 		return;
93122017ed2SDouglas Gilbert 	}
93222017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
93322017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
934f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
93522017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
93622017ed2SDouglas Gilbert 	sks[0] = 0x80;
93722017ed2SDouglas Gilbert 	if (c_d)
93822017ed2SDouglas Gilbert 		sks[0] |= 0x40;
93922017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94022017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94122017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94222017ed2SDouglas Gilbert 	}
94322017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
944773642d9SDouglas Gilbert 	if (sdebug_dsense) {
94522017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
94622017ed2SDouglas Gilbert 		sbuff[7] = sl;
94722017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
94822017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
94922017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95022017ed2SDouglas Gilbert 	} else
95122017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
952773642d9SDouglas Gilbert 	if (sdebug_verbose)
95322017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
95422017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
95522017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
95622017ed2SDouglas Gilbert }
95722017ed2SDouglas Gilbert 
958cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9598dea0d02SFUJITA Tomonori {
960f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
961cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
962cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
963cbf67842SDouglas Gilbert 		return;
964cbf67842SDouglas Gilbert 	}
965f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9668dea0d02SFUJITA Tomonori 
967f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9688dea0d02SFUJITA Tomonori 
969773642d9SDouglas Gilbert 	if (sdebug_verbose)
970cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
971cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
972cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9738dea0d02SFUJITA Tomonori }
9741da177e4SLinus Torvalds 
975fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
97622017ed2SDouglas Gilbert {
97722017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
97822017ed2SDouglas Gilbert }
97922017ed2SDouglas Gilbert 
9806f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9816f4e626fSNathan Chancellor 			    void __user *arg)
9821da177e4SLinus Torvalds {
983773642d9SDouglas Gilbert 	if (sdebug_verbose) {
984cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
985cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
986cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
987cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
988cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
989cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
990cbf67842SDouglas Gilbert 				    __func__);
991cbf67842SDouglas Gilbert 		else
992cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
993cbf67842SDouglas Gilbert 				    __func__, cmd);
9941da177e4SLinus Torvalds 	}
9951da177e4SLinus Torvalds 	return -EINVAL;
9961da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
9971da177e4SLinus Torvalds }
9981da177e4SLinus Torvalds 
9999b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10009b760fd8SDouglas Gilbert {
10019b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10029b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10039b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10049b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10059b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10069b760fd8SDouglas Gilbert 		break;
10079b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10089b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10099b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10109b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10119b760fd8SDouglas Gilbert 		break;
10129b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10149b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10159b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10169b760fd8SDouglas Gilbert 		break;
10179b760fd8SDouglas Gilbert 	case 16:
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10199b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10209b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10219b760fd8SDouglas Gilbert 		break;
10229b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10239b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10249b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10259b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10269b760fd8SDouglas Gilbert 		break;
10279b760fd8SDouglas Gilbert 	default:
10289b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10299b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10309b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10319b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10329b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10339b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10349b760fd8SDouglas Gilbert 		break;
10359b760fd8SDouglas Gilbert 	}
10369b760fd8SDouglas Gilbert }
10379b760fd8SDouglas Gilbert 
10389b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10399b760fd8SDouglas Gilbert {
10409b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10419b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10429b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10439b760fd8SDouglas Gilbert 
10449b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10459b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10469b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10479b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10489b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10499b760fd8SDouglas Gilbert 		}
10509b760fd8SDouglas Gilbert 	}
10519b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10529b760fd8SDouglas Gilbert }
10539b760fd8SDouglas Gilbert 
105419c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
105519c8ead7SEwan D. Milne {
105619c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
105719c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
105819c8ead7SEwan D. Milne 
105919c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
106019c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106119c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
106219c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
106319c8ead7SEwan D. Milne 			    (devip->target == dp->target))
106419c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
106519c8ead7SEwan D. Milne 		}
106619c8ead7SEwan D. Milne 	}
106719c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
106819c8ead7SEwan D. Milne }
106919c8ead7SEwan D. Milne 
1070f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10711da177e4SLinus Torvalds {
1072cbf67842SDouglas Gilbert 	int k;
1073cbf67842SDouglas Gilbert 
1074cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1075cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1076cbf67842SDouglas Gilbert 		const char *cp = NULL;
1077cbf67842SDouglas Gilbert 
1078cbf67842SDouglas Gilbert 		switch (k) {
1079cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1080f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1081f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1082773642d9SDouglas Gilbert 			if (sdebug_verbose)
1083cbf67842SDouglas Gilbert 				cp = "power on reset";
1084cbf67842SDouglas Gilbert 			break;
1085cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1086f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1087f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1088773642d9SDouglas Gilbert 			if (sdebug_verbose)
1089cbf67842SDouglas Gilbert 				cp = "bus reset";
1090cbf67842SDouglas Gilbert 			break;
1091cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1092f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1093f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1094773642d9SDouglas Gilbert 			if (sdebug_verbose)
1095cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1096cbf67842SDouglas Gilbert 			break;
10970d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1098f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1099f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1100773642d9SDouglas Gilbert 			if (sdebug_verbose)
11010d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1102f49accf1SEwan D. Milne 			break;
1103acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1104f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1105b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1106b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1107773642d9SDouglas Gilbert 			if (sdebug_verbose)
1108acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1109acafd0b9SEwan D. Milne 			break;
1110acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1111f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1112acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1113acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1114773642d9SDouglas Gilbert 			if (sdebug_verbose)
1115acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1116acafd0b9SEwan D. Milne 			break;
111719c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
111819c8ead7SEwan D. Milne 			/*
111919c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
112019c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
112119c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
112219c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1123773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
112419c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
112519c8ead7SEwan D. Milne 			 */
1126773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
112719c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1128f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
112919c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
113019c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1131773642d9SDouglas Gilbert 			if (sdebug_verbose)
113219c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
113319c8ead7SEwan D. Milne 			break;
1134cbf67842SDouglas Gilbert 		default:
1135773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1136773642d9SDouglas Gilbert 			if (sdebug_verbose)
1137cbf67842SDouglas Gilbert 				cp = "unknown";
1138cbf67842SDouglas Gilbert 			break;
1139cbf67842SDouglas Gilbert 		}
1140cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1141773642d9SDouglas Gilbert 		if (sdebug_verbose)
1142f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1143cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1144cbf67842SDouglas Gilbert 				   my_name, cp);
11451da177e4SLinus Torvalds 		return check_condition_result;
11461da177e4SLinus Torvalds 	}
11471da177e4SLinus Torvalds 	return 0;
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds 
1150fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11511da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11521da177e4SLinus Torvalds 				int arr_len)
11531da177e4SLinus Torvalds {
115421a61829SFUJITA Tomonori 	int act_len;
1155ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11561da177e4SLinus Torvalds 
1157072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11581da177e4SLinus Torvalds 		return 0;
1159ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1160773642d9SDouglas Gilbert 		return DID_ERROR << 16;
116121a61829SFUJITA Tomonori 
116221a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
116321a61829SFUJITA Tomonori 				      arr, arr_len);
116442d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
116521a61829SFUJITA Tomonori 
11661da177e4SLinus Torvalds 	return 0;
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds 
1169fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1170fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1171fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1172fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1173fb0cc8d1SDouglas Gilbert  */
1174fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1175fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1176fb0cc8d1SDouglas Gilbert {
11779237f04eSDamien Le Moal 	unsigned int act_len, n;
1178ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1179fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1180fb0cc8d1SDouglas Gilbert 
1181fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1182fb0cc8d1SDouglas Gilbert 		return 0;
1183ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1184fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1185fb0cc8d1SDouglas Gilbert 
1186fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1187fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1188fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
118942d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
119042d387beSBart Van Assche 		 scsi_get_resid(scp));
11919237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
119287c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1193fb0cc8d1SDouglas Gilbert 	return 0;
1194fb0cc8d1SDouglas Gilbert }
1195fb0cc8d1SDouglas Gilbert 
1196fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1197fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1198fb0cc8d1SDouglas Gilbert  */
11991da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
120021a61829SFUJITA Tomonori 			       int arr_len)
12011da177e4SLinus Torvalds {
120221a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12031da177e4SLinus Torvalds 		return 0;
1204ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12051da177e4SLinus Torvalds 		return -1;
120621a61829SFUJITA Tomonori 
120721a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12081da177e4SLinus Torvalds }
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds 
1211e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1212e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12139b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12141b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12151b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12161b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12171b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12181da177e4SLinus Torvalds 
1219cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1220760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12215a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
122209ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1223bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12241da177e4SLinus Torvalds {
1225c65b1445SDouglas Gilbert 	int num, port_a;
1226c65b1445SDouglas Gilbert 	char b[32];
12271da177e4SLinus Torvalds 
1228c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12291da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12301da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12311da177e4SLinus Torvalds 	arr[1] = 0x1;
12321da177e4SLinus Torvalds 	arr[2] = 0x0;
1233e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1234e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12351da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12361da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12371da177e4SLinus Torvalds 	arr[3] = num;
12381da177e4SLinus Torvalds 	num += 4;
1239c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
124009ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
124109ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
124209ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
124309ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
124409ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124509ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
124609ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
124709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124809ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
124909ba24c1SDouglas Gilbert 			num += 16;
125009ba24c1SDouglas Gilbert 		} else {
12511b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1252c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1253c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1254c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1255c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12561b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1257773642d9SDouglas Gilbert 			num += 8;
125809ba24c1SDouglas Gilbert 		}
1259c65b1445SDouglas Gilbert 		/* Target relative port number */
1260c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1261c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1262c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1263c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1264c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1265c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1266c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1267c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1268c65b1445SDouglas Gilbert 	}
12691b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1270c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1271c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1272c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1273c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12741b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1275773642d9SDouglas Gilbert 	num += 8;
12761b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12775a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12785a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12795a09e398SHannes Reinecke 	arr[num++] = 0x0;
12805a09e398SHannes Reinecke 	arr[num++] = 0x4;
12815a09e398SHannes Reinecke 	arr[num++] = 0;
12825a09e398SHannes Reinecke 	arr[num++] = 0;
1283773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1284773642d9SDouglas Gilbert 	num += 2;
12851b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1286c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1287c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1288c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1289c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1291773642d9SDouglas Gilbert 	num += 8;
1292c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1293c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1294c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1295c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1296c65b1445SDouglas Gilbert 	arr[num++] = 24;
12971b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1298c65b1445SDouglas Gilbert 	num += 12;
1299c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1300c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1301c65b1445SDouglas Gilbert 	num += 8;
1302c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1303c65b1445SDouglas Gilbert 	num += 4;
1304c65b1445SDouglas Gilbert 	return num;
1305c65b1445SDouglas Gilbert }
1306c65b1445SDouglas Gilbert 
1307c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1308c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1309c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1310c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1311c65b1445SDouglas Gilbert };
1312c65b1445SDouglas Gilbert 
1313cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1314760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1315c65b1445SDouglas Gilbert {
1316c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1317c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1318c65b1445SDouglas Gilbert }
1319c65b1445SDouglas Gilbert 
1320cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1321760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1322c65b1445SDouglas Gilbert {
1323c65b1445SDouglas Gilbert 	int num = 0;
1324c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1325c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1326c65b1445SDouglas Gilbert 	int plen, olen;
1327c65b1445SDouglas Gilbert 
1328c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1329c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1330c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1331c65b1445SDouglas Gilbert 	olen = strlen(na1);
1332c65b1445SDouglas Gilbert 	plen = olen + 1;
1333c65b1445SDouglas Gilbert 	if (plen % 4)
1334c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1335c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1336c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1337c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1338c65b1445SDouglas Gilbert 	num += plen;
1339c65b1445SDouglas Gilbert 
1340c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1341c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1342c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1343c65b1445SDouglas Gilbert 	olen = strlen(na2);
1344c65b1445SDouglas Gilbert 	plen = olen + 1;
1345c65b1445SDouglas Gilbert 	if (plen % 4)
1346c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1347c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1348c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1349c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1350c65b1445SDouglas Gilbert 	num += plen;
1351c65b1445SDouglas Gilbert 
1352c65b1445SDouglas Gilbert 	return num;
1353c65b1445SDouglas Gilbert }
1354c65b1445SDouglas Gilbert 
1355c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1356760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1357c65b1445SDouglas Gilbert {
1358c65b1445SDouglas Gilbert 	int num = 0;
1359c65b1445SDouglas Gilbert 	int port_a, port_b;
1360c65b1445SDouglas Gilbert 
1361c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1362c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1363c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1364c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1365c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1366c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1367c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1368c65b1445SDouglas Gilbert 	num += 6;
1369c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1370c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1371c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1372c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1374c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1375c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13761b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1377773642d9SDouglas Gilbert 	num += 8;
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1380c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1381c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1382c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1383c65b1445SDouglas Gilbert 	num += 6;
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1385c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1386c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1387c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1389c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1390c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13911b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1392773642d9SDouglas Gilbert 	num += 8;
1393c65b1445SDouglas Gilbert 
1394c65b1445SDouglas Gilbert 	return num;
1395c65b1445SDouglas Gilbert }
1396c65b1445SDouglas Gilbert 
1397c65b1445SDouglas Gilbert 
1398c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1399c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1400c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1401c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1402c65b1445SDouglas Gilbert '1','2','3','4',
1403c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1404c65b1445SDouglas Gilbert 0xec,0,0,0,
1405c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1406c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1407c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1408c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1409c65b1445SDouglas Gilbert 0x53,0x41,
1410c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1411c65b1445SDouglas Gilbert 0x20,0x20,
1412c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1413c65b1445SDouglas Gilbert 0x10,0x80,
1414c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1415c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1416c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1417c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1418c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1419c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1420c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1421c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1422c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1423c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1424c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1425c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1426c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1427c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1428c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1429c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1430c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1440c65b1445SDouglas Gilbert };
1441c65b1445SDouglas Gilbert 
1442cbf67842SDouglas Gilbert /* ATA Information VPD page */
1443760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1444c65b1445SDouglas Gilbert {
1445c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1446c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1447c65b1445SDouglas Gilbert }
1448c65b1445SDouglas Gilbert 
1449c65b1445SDouglas Gilbert 
1450c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14511e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14521e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14531e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14541e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1455c65b1445SDouglas Gilbert };
1456c65b1445SDouglas Gilbert 
1457cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1458760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1459c65b1445SDouglas Gilbert {
1460ea61fca5SMartin K. Petersen 	unsigned int gran;
1461ea61fca5SMartin K. Petersen 
1462c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1463e308b3d1SMartin K. Petersen 
1464e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
146586e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
146686e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
146786e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
146886e6828aSLukas Herbolt 	else
1469773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1470773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1471e308b3d1SMartin K. Petersen 
1472e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1473773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1474773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
147544d92694SMartin K. Petersen 
1476e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1477773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1478e308b3d1SMartin K. Petersen 
1479773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1480e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1481773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1482e308b3d1SMartin K. Petersen 
1483e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1484773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
148544d92694SMartin K. Petersen 	}
148644d92694SMartin K. Petersen 
1487e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1488773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1489773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
149044d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
149144d92694SMartin K. Petersen 	}
149244d92694SMartin K. Petersen 
1493e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1494773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14956014759cSMartin K. Petersen 
14965b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1497773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
14985b94e232SMartin K. Petersen 
14995b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
150044d92694SMartin K. Petersen 
1501c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15021da177e4SLinus Torvalds }
15031da177e4SLinus Torvalds 
15041e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
150564e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1506eac6e8e4SMatthew Wilcox {
1507eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1508eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15091e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15101e49f785SDouglas Gilbert 	arr[2] = 0;
15111e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
151264e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
151364e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1514eac6e8e4SMatthew Wilcox 
1515eac6e8e4SMatthew Wilcox 	return 0x3c;
1516eac6e8e4SMatthew Wilcox }
15171da177e4SLinus Torvalds 
1518760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1519760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15206014759cSMartin K. Petersen {
15213f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15226014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1523773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15246014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1525773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15266014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1527773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15285b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1529760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1530760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1531760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1532760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1533760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15343f0bc3b3SMartin K. Petersen 	return 0x4;
15356014759cSMartin K. Petersen }
15366014759cSMartin K. Petersen 
1537d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1538f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1539d36da305SDouglas Gilbert {
1540d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1541d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1542d36da305SDouglas Gilbert 	/*
1543d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1544d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1545f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1546f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1547d36da305SDouglas Gilbert 	 */
1548d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1549d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
155064e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1551f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1552f0d1cf93SDouglas Gilbert 	else
1553d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1554d36da305SDouglas Gilbert 	return 0x3c;
1555d36da305SDouglas Gilbert }
1556d36da305SDouglas Gilbert 
15571da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1558c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15591da177e4SLinus Torvalds 
1560c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15611da177e4SLinus Torvalds {
15621da177e4SLinus Torvalds 	unsigned char pq_pdt;
15635a09e398SHannes Reinecke 	unsigned char *arr;
156401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15655a09e398SHannes Reinecke 	int alloc_len, n, ret;
1566d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15671da177e4SLinus Torvalds 
1568773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15696f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15706f3cbf55SDouglas Gilbert 	if (! arr)
15716f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1572760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
157364e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1574d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1575b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1576c2248fc9SDouglas Gilbert 	if (have_wlun)
1577b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1578b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1579b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1580c65b1445SDouglas Gilbert 	else
1581773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15821da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15831da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
158422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15855a09e398SHannes Reinecke 		kfree(arr);
15861da177e4SLinus Torvalds 		return check_condition_result;
15871da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15885a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1589c65b1445SDouglas Gilbert 		char lu_id_str[6];
1590c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
15911da177e4SLinus Torvalds 
15925a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
15935a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1594b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
159523183910SDouglas Gilbert 			host_no = 0;
1596c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1597c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1598c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1599c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1600c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16011da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1602c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1603c65b1445SDouglas Gilbert 			n = 4;
1604c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1605c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1606c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1607c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1608c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1609c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1610c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1611c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1612d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1613c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1614760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1615760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1616d36da305SDouglas Gilbert 				if (is_disk)
1617d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
161864e14eceSDamien Le Moal 				if (is_zbc)
1619d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1620760f3b03SDouglas Gilbert 			}
1621c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16221da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1623c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16241da177e4SLinus Torvalds 			arr[3] = len;
1625c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16261da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1627c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1628760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16295a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
163009ba24c1SDouglas Gilbert 						lu_id_str, len,
163109ba24c1SDouglas Gilbert 						&devip->lu_name);
1632c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1633c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1634760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1635c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1636c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1637760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1638c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1639c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1640c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16418475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1642c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1643760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1644c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1645c6a44287SMartin K. Petersen 			else
1646c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1647c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1648c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1649c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1650c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1651c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1652c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1653c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1654c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1655c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1656c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1657760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1658d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1659c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1660760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1661773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1662d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1663c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1664760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1665d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1666eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
166764e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1668760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16696014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1670760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1671d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1672d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1673f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16741da177e4SLinus Torvalds 		} else {
167522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16765a09e398SHannes Reinecke 			kfree(arr);
16771da177e4SLinus Torvalds 			return check_condition_result;
16781da177e4SLinus Torvalds 		}
1679773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
16805a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1681c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
16825a09e398SHannes Reinecke 		kfree(arr);
16835a09e398SHannes Reinecke 		return ret;
16841da177e4SLinus Torvalds 	}
16851da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1686773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1687773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16881da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16891da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1690f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1691b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
169270bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1693c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
16941da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1695c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1696e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1697e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1698e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
16999b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17009b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17011da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1702760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1703760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1704c65b1445SDouglas Gilbert 	n = 62;
1705760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1706760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1707760f3b03SDouglas Gilbert 		n += 2;
1708760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1709760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1710760f3b03SDouglas Gilbert 		n += 2;
1711d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1712d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1713d36da305SDouglas Gilbert 		n += 2;
17141da177e4SLinus Torvalds 	}
1715760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17165a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
171787c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
17185a09e398SHannes Reinecke 	kfree(arr);
17195a09e398SHannes Reinecke 	return ret;
17201da177e4SLinus Torvalds }
17211da177e4SLinus Torvalds 
172284905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1723fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1724fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1725fd32119bSDouglas Gilbert 
17261da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17271da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17281da177e4SLinus Torvalds {
172901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
173084905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
173184905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
173284905d34SDouglas Gilbert 	int alloc_len = cmd[4];
17331da177e4SLinus Torvalds 	int len = 18;
173484905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17351da177e4SLinus Torvalds 
1736c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
173784905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
173884905d34SDouglas Gilbert 		if (dsense) {
173984905d34SDouglas Gilbert 			arr[0] = 0x72;
174084905d34SDouglas Gilbert 			arr[1] = NOT_READY;
174184905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
174284905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
174384905d34SDouglas Gilbert 			len = 8;
174484905d34SDouglas Gilbert 		} else {
174584905d34SDouglas Gilbert 			arr[0] = 0x70;
174684905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
174784905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
174884905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
174984905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
175084905d34SDouglas Gilbert 		}
175184905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
175284905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1753c2248fc9SDouglas Gilbert 		if (dsense) {
1754c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1755c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1756c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
175784905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1758c2248fc9SDouglas Gilbert 			len = 8;
1759c65b1445SDouglas Gilbert 		} else {
1760c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1761c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1762c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1763c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
176484905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1765c65b1445SDouglas Gilbert 		}
176684905d34SDouglas Gilbert 	} else {	/* nothing to report */
1767c2248fc9SDouglas Gilbert 		if (dsense) {
1768c2248fc9SDouglas Gilbert 			len = 8;
176984905d34SDouglas Gilbert 			memset(arr, 0, len);
177084905d34SDouglas Gilbert 			arr[0] = 0x72;
1771c2248fc9SDouglas Gilbert 		} else {
177284905d34SDouglas Gilbert 			memset(arr, 0, len);
1773c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1774c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1775c2248fc9SDouglas Gilbert 		}
1776c65b1445SDouglas Gilbert 	}
177784905d34SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
17781da177e4SLinus Torvalds }
17791da177e4SLinus Torvalds 
1780fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1781c65b1445SDouglas Gilbert {
178201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1783fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
17844f2c8bf6SDouglas Gilbert 	bool changing;
1785c65b1445SDouglas Gilbert 
1786c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1787c65b1445SDouglas Gilbert 	if (power_cond) {
178822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1789c65b1445SDouglas Gilbert 		return check_condition_result;
1790c65b1445SDouglas Gilbert 	}
1791fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1792fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1793fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1794fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1795fc13638aSDouglas Gilbert 
1796fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1797fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1798fc13638aSDouglas Gilbert 
1799fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1800fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1801fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1802fc13638aSDouglas Gilbert 				stopped_state = 0;
1803fc13638aSDouglas Gilbert 			}
1804fc13638aSDouglas Gilbert 		}
1805fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1806fc13638aSDouglas Gilbert 			if (want_stop) {
1807fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1808fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1809fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1810fc13638aSDouglas Gilbert 				return check_condition_result;
1811fc13638aSDouglas Gilbert 			}
1812fc13638aSDouglas Gilbert 		}
1813fc13638aSDouglas Gilbert 	}
1814fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1815fc13638aSDouglas Gilbert 	if (changing)
1816fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1817fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18184f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18194f2c8bf6SDouglas Gilbert 	else
18204f2c8bf6SDouglas Gilbert 		return 0;
1821c65b1445SDouglas Gilbert }
1822c65b1445SDouglas Gilbert 
182328898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
182428898873SFUJITA Tomonori {
1825773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1826773642d9SDouglas Gilbert 
1827773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1828773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1829773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
183028898873SFUJITA Tomonori 	else
183128898873SFUJITA Tomonori 		return sdebug_store_sectors;
183228898873SFUJITA Tomonori }
183328898873SFUJITA Tomonori 
18341da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18351da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18361da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18371da177e4SLinus Torvalds {
18381da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1839c65b1445SDouglas Gilbert 	unsigned int capac;
18401da177e4SLinus Torvalds 
1841c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
184228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18431da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1844c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1845c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1846773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1847773642d9SDouglas Gilbert 	} else
1848773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1849773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18501da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18511da177e4SLinus Torvalds }
18521da177e4SLinus Torvalds 
1853c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1854c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1855c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1856c65b1445SDouglas Gilbert {
185701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1858c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18594e3ace00SYe Bin 	u32 alloc_len;
1860c65b1445SDouglas Gilbert 
1861773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1862c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1864c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1865773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1866773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1867773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1868773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
186944d92694SMartin K. Petersen 
1870be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18715b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1872760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1873760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1874760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1875760f3b03SDouglas Gilbert 		 */
1876760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1877760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1878be1dd78dSEric Sandeen 	}
187944d92694SMartin K. Petersen 
1880773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1881c6a44287SMartin K. Petersen 
1882760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1883773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1884c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1885c6a44287SMartin K. Petersen 	}
1886c6a44287SMartin K. Petersen 
1887c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
18884e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1889c65b1445SDouglas Gilbert }
1890c65b1445SDouglas Gilbert 
18915a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18925a09e398SHannes Reinecke 
18935a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18945a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18955a09e398SHannes Reinecke {
189601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
18975a09e398SHannes Reinecke 	unsigned char *arr;
18985a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
18995a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1900f347c268SYe Bin 	u32 alen, n, rlen;
1901f347c268SYe Bin 	int ret;
19025a09e398SHannes Reinecke 
1903773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19046f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19056f3cbf55SDouglas Gilbert 	if (! arr)
19066f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19075a09e398SHannes Reinecke 	/*
19085a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19095a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19105a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19115a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19125a09e398SHannes Reinecke 	 */
19135a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19145a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19155a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19165a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19175a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19185a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19195a09e398SHannes Reinecke 
19205a09e398SHannes Reinecke 	/*
19215a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19225a09e398SHannes Reinecke 	 */
19235a09e398SHannes Reinecke 	n = 4;
1924b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19255a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19265a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19275a09e398SHannes Reinecke 	} else {
19285a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1929773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19305a09e398SHannes Reinecke 	}
1931773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1932773642d9SDouglas Gilbert 	n += 2;
19335a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19345a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19365a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1939773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1940773642d9SDouglas Gilbert 	n += 2;
19415a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19425a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1943773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1944773642d9SDouglas Gilbert 	n += 2;
19455a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19465a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19485a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19505a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1951773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1952773642d9SDouglas Gilbert 	n += 2;
19535a09e398SHannes Reinecke 
19545a09e398SHannes Reinecke 	rlen = n - 4;
1955773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19565a09e398SHannes Reinecke 
19575a09e398SHannes Reinecke 	/*
19585a09e398SHannes Reinecke 	 * Return the smallest value of either
19595a09e398SHannes Reinecke 	 * - The allocated length
19605a09e398SHannes Reinecke 	 * - The constructed command length
19615a09e398SHannes Reinecke 	 * - The maximum array size
19625a09e398SHannes Reinecke 	 */
1963f347c268SYe Bin 	rlen = min(alen, n);
19645a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1965f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19665a09e398SHannes Reinecke 	kfree(arr);
19675a09e398SHannes Reinecke 	return ret;
19685a09e398SHannes Reinecke }
19695a09e398SHannes Reinecke 
1970fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1971fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
197238d5c833SDouglas Gilbert {
197338d5c833SDouglas Gilbert 	bool rctd;
197438d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
197538d5c833SDouglas Gilbert 	u16 req_sa, u;
197638d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
197738d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
197838d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
197938d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
198038d5c833SDouglas Gilbert 	u8 *arr;
198138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
198238d5c833SDouglas Gilbert 
198338d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
198438d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
198538d5c833SDouglas Gilbert 	req_opcode = cmd[3];
198638d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
198738d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19886d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
198938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
199038d5c833SDouglas Gilbert 		return check_condition_result;
199138d5c833SDouglas Gilbert 	}
199238d5c833SDouglas Gilbert 	if (alloc_len > 8192)
199338d5c833SDouglas Gilbert 		a_len = 8192;
199438d5c833SDouglas Gilbert 	else
199538d5c833SDouglas Gilbert 		a_len = alloc_len;
199699531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
199738d5c833SDouglas Gilbert 	if (NULL == arr) {
199838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
199938d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
200038d5c833SDouglas Gilbert 		return check_condition_result;
200138d5c833SDouglas Gilbert 	}
200238d5c833SDouglas Gilbert 	switch (reporting_opts) {
200338d5c833SDouglas Gilbert 	case 0:	/* all commands */
200438d5c833SDouglas Gilbert 		/* count number of commands */
200538d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
200638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
200738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
200838d5c833SDouglas Gilbert 				continue;
200938d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
201038d5c833SDouglas Gilbert 		}
201138d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
201238d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
201338d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
201438d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
201538d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
201638d5c833SDouglas Gilbert 				continue;
201738d5c833SDouglas Gilbert 			na = oip->num_attached;
201838d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
201938d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
202038d5c833SDouglas Gilbert 			if (rctd)
202138d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
202238d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
202338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
202438d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
202538d5c833SDouglas Gilbert 			if (rctd)
202638d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
202738d5c833SDouglas Gilbert 			r_oip = oip;
202838d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
202938d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
203038d5c833SDouglas Gilbert 					continue;
203138d5c833SDouglas Gilbert 				offset += bump;
203238d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
203338d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
203438d5c833SDouglas Gilbert 				if (rctd)
203538d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
203638d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
203738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
203838d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
203938d5c833SDouglas Gilbert 						   arr + offset + 6);
204038d5c833SDouglas Gilbert 				if (rctd)
204138d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
204238d5c833SDouglas Gilbert 							   arr + offset + 8);
204338d5c833SDouglas Gilbert 			}
204438d5c833SDouglas Gilbert 			oip = r_oip;
204538d5c833SDouglas Gilbert 			offset += bump;
204638d5c833SDouglas Gilbert 		}
204738d5c833SDouglas Gilbert 		break;
204838d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
204938d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
205038d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
205138d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
205238d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
205338d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
205438d5c833SDouglas Gilbert 			supp = 1;
205538d5c833SDouglas Gilbert 			offset = 4;
205638d5c833SDouglas Gilbert 		} else {
205738d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
205838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
205938d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
206038d5c833SDouglas Gilbert 							     2, 2);
206138d5c833SDouglas Gilbert 					kfree(arr);
206238d5c833SDouglas Gilbert 					return check_condition_result;
206338d5c833SDouglas Gilbert 				}
206438d5c833SDouglas Gilbert 				req_sa = 0;
206538d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
206638d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
206738d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
206838d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
206938d5c833SDouglas Gilbert 				return check_condition_result;
207038d5c833SDouglas Gilbert 			}
207138d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
207238d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
207338d5c833SDouglas Gilbert 				supp = 3;
207438d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
207538d5c833SDouglas Gilbert 				na = oip->num_attached;
207638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
207738d5c833SDouglas Gilbert 				     ++k, ++oip) {
207838d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
207938d5c833SDouglas Gilbert 						break;
208038d5c833SDouglas Gilbert 				}
208138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208238d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
208338d5c833SDouglas Gilbert 				na = oip->num_attached;
208438d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
208538d5c833SDouglas Gilbert 				     ++k, ++oip) {
208638d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
208738d5c833SDouglas Gilbert 						break;
208838d5c833SDouglas Gilbert 				}
208938d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
209038d5c833SDouglas Gilbert 			} else
209138d5c833SDouglas Gilbert 				supp = 3;
209238d5c833SDouglas Gilbert 			if (3 == supp) {
209338d5c833SDouglas Gilbert 				u = oip->len_mask[0];
209438d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
209538d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
209638d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
209738d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
209838d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
209938d5c833SDouglas Gilbert 				offset = 4 + u;
210038d5c833SDouglas Gilbert 			} else
210138d5c833SDouglas Gilbert 				offset = 4;
210238d5c833SDouglas Gilbert 		}
210338d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
210438d5c833SDouglas Gilbert 		if (rctd) {
210538d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
210638d5c833SDouglas Gilbert 			offset += 12;
210738d5c833SDouglas Gilbert 		}
210838d5c833SDouglas Gilbert 		break;
210938d5c833SDouglas Gilbert 	default:
211038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
211138d5c833SDouglas Gilbert 		kfree(arr);
211238d5c833SDouglas Gilbert 		return check_condition_result;
211338d5c833SDouglas Gilbert 	}
211438d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
211538d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
211638d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
211738d5c833SDouglas Gilbert 	kfree(arr);
211838d5c833SDouglas Gilbert 	return errsts;
211938d5c833SDouglas Gilbert }
212038d5c833SDouglas Gilbert 
2121fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2122fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
212338d5c833SDouglas Gilbert {
212438d5c833SDouglas Gilbert 	bool repd;
212538d5c833SDouglas Gilbert 	u32 alloc_len, len;
212638d5c833SDouglas Gilbert 	u8 arr[16];
212738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
212838d5c833SDouglas Gilbert 
212938d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
213038d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
213138d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
213238d5c833SDouglas Gilbert 	if (alloc_len < 4) {
213338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
213438d5c833SDouglas Gilbert 		return check_condition_result;
213538d5c833SDouglas Gilbert 	}
213638d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
213738d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
213838d5c833SDouglas Gilbert 	if (repd) {
213938d5c833SDouglas Gilbert 		arr[3] = 0xc;
214038d5c833SDouglas Gilbert 		len = 16;
214138d5c833SDouglas Gilbert 	} else
214238d5c833SDouglas Gilbert 		len = 4;
214338d5c833SDouglas Gilbert 
214438d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
214538d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
214638d5c833SDouglas Gilbert }
214738d5c833SDouglas Gilbert 
21481da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21491da177e4SLinus Torvalds 
21501da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21511da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21521da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21531da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21541da177e4SLinus Torvalds 
21551da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21561da177e4SLinus Torvalds 	if (1 == pcontrol)
21571da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21581da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21591da177e4SLinus Torvalds }
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21621da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21631da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21641da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21651da177e4SLinus Torvalds 
21661da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21671da177e4SLinus Torvalds 	if (1 == pcontrol)
21681da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21691da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21701da177e4SLinus Torvalds }
21711da177e4SLinus Torvalds 
21721da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21731da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21741da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21751da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21761da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21771da177e4SLinus Torvalds 
21781da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2179773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2180773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2181773642d9SDouglas Gilbert 	if (sdebug_removable)
21821da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21831da177e4SLinus Torvalds 	if (1 == pcontrol)
21841da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21851da177e4SLinus Torvalds 	return sizeof(format_pg);
21861da177e4SLinus Torvalds }
21871da177e4SLinus Torvalds 
2188fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2189fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2190fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2191fd32119bSDouglas Gilbert 
21921da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21931da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2194cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2195cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2196cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21971da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
21981da177e4SLinus Torvalds 
2199773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2200cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22011da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22021da177e4SLinus Torvalds 	if (1 == pcontrol)
2203cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2204cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2205cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22061da177e4SLinus Torvalds 	return sizeof(caching_pg);
22071da177e4SLinus Torvalds }
22081da177e4SLinus Torvalds 
2209fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2210fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2211fd32119bSDouglas Gilbert 
22121da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22131da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2214c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2215c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2216c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22171da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22181da177e4SLinus Torvalds 
2219773642d9SDouglas Gilbert 	if (sdebug_dsense)
22201da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2221c65b1445SDouglas Gilbert 	else
2222c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2223c6a44287SMartin K. Petersen 
2224773642d9SDouglas Gilbert 	if (sdebug_ato)
2225c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2226c6a44287SMartin K. Petersen 
22271da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22281da177e4SLinus Torvalds 	if (1 == pcontrol)
2229c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2230c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2231c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22321da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22331da177e4SLinus Torvalds }
22341da177e4SLinus Torvalds 
2235c65b1445SDouglas Gilbert 
22361da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22371da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2238c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22391da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2240c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2241c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2242c65b1445SDouglas Gilbert 
22431da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22441da177e4SLinus Torvalds 	if (1 == pcontrol)
2245c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2246c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2247c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22481da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22491da177e4SLinus Torvalds }
22501da177e4SLinus Torvalds 
2251c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2252c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2253c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2254c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2255c65b1445SDouglas Gilbert 
2256c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2257c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2258c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2259c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2260c65b1445SDouglas Gilbert }
2261c65b1445SDouglas Gilbert 
2262c65b1445SDouglas Gilbert 
2263c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2264c65b1445SDouglas Gilbert 			      int target_dev_id)
2265c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2266c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2267c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2268773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2269773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2270c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2271c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2272c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2273c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2274773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2275773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2276c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2277c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2278c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2279c65b1445SDouglas Gilbert 		};
2280c65b1445SDouglas Gilbert 	int port_a, port_b;
2281c65b1445SDouglas Gilbert 
22821b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22831b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22841b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22851b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2286c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2287c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2288c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2289773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2290773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2291c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2292c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2293c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2294c65b1445SDouglas Gilbert }
2295c65b1445SDouglas Gilbert 
2296c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2297c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2298c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2299c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2300c65b1445SDouglas Gilbert 		};
2301c65b1445SDouglas Gilbert 
2302c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2303c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2304c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2305c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2306c65b1445SDouglas Gilbert }
2307c65b1445SDouglas Gilbert 
23081da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23091da177e4SLinus Torvalds 
2310fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2311fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23121da177e4SLinus Torvalds {
231323183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23141da177e4SLinus Torvalds 	unsigned char dev_spec;
2315760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2316c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23171da177e4SLinus Torvalds 	unsigned char *ap;
23181da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
231901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2320d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23211da177e4SLinus Torvalds 
2322760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23231da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23241da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23251da177e4SLinus Torvalds 	subpcode = cmd[3];
23261da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2327760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2328760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
232964e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2330d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
233123183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
233223183910SDouglas Gilbert 	else
233323183910SDouglas Gilbert 		bd_len = 0;
2334773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23351da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23361da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2337cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23381da177e4SLinus Torvalds 		return check_condition_result;
23391da177e4SLinus Torvalds 	}
2340c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2341c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2342d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2343d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2344b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23459447b6ceSMartin K. Petersen 		if (sdebug_wp)
23469447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23479447b6ceSMartin K. Petersen 	} else
234823183910SDouglas Gilbert 		dev_spec = 0x0;
23491da177e4SLinus Torvalds 	if (msense_6) {
23501da177e4SLinus Torvalds 		arr[2] = dev_spec;
235123183910SDouglas Gilbert 		arr[3] = bd_len;
23521da177e4SLinus Torvalds 		offset = 4;
23531da177e4SLinus Torvalds 	} else {
23541da177e4SLinus Torvalds 		arr[3] = dev_spec;
235523183910SDouglas Gilbert 		if (16 == bd_len)
235623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
235723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23581da177e4SLinus Torvalds 		offset = 8;
23591da177e4SLinus Torvalds 	}
23601da177e4SLinus Torvalds 	ap = arr + offset;
236128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
236228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
236328898873SFUJITA Tomonori 
236423183910SDouglas Gilbert 	if (8 == bd_len) {
2365773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2366773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2367773642d9SDouglas Gilbert 		else
2368773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2369773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
237023183910SDouglas Gilbert 		offset += bd_len;
237123183910SDouglas Gilbert 		ap = arr + offset;
237223183910SDouglas Gilbert 	} else if (16 == bd_len) {
2373773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2374773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
237523183910SDouglas Gilbert 		offset += bd_len;
237623183910SDouglas Gilbert 		ap = arr + offset;
237723183910SDouglas Gilbert 	}
23781da177e4SLinus Torvalds 
2379c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2380c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
238122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23821da177e4SLinus Torvalds 		return check_condition_result;
23831da177e4SLinus Torvalds 	}
2384760f3b03SDouglas Gilbert 	bad_pcode = false;
2385760f3b03SDouglas Gilbert 
23861da177e4SLinus Torvalds 	switch (pcode) {
23871da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23881da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23891da177e4SLinus Torvalds 		offset += len;
23901da177e4SLinus Torvalds 		break;
23911da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23921da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23931da177e4SLinus Torvalds 		offset += len;
23941da177e4SLinus Torvalds 		break;
23951da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2396760f3b03SDouglas Gilbert 		if (is_disk) {
23971da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
23981da177e4SLinus Torvalds 			offset += len;
2399760f3b03SDouglas Gilbert 		} else
2400760f3b03SDouglas Gilbert 			bad_pcode = true;
24011da177e4SLinus Torvalds 		break;
24021da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2403d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24041da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24051da177e4SLinus Torvalds 			offset += len;
2406760f3b03SDouglas Gilbert 		} else
2407760f3b03SDouglas Gilbert 			bad_pcode = true;
24081da177e4SLinus Torvalds 		break;
24091da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24101da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24111da177e4SLinus Torvalds 		offset += len;
24121da177e4SLinus Torvalds 		break;
2413c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2414c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
241522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2416c65b1445SDouglas Gilbert 			return check_condition_result;
2417c65b1445SDouglas Gilbert 		}
2418c65b1445SDouglas Gilbert 		len = 0;
2419c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2420c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2421c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2422c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2423c65b1445SDouglas Gilbert 						  target_dev_id);
2424c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2425c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2426c65b1445SDouglas Gilbert 		offset += len;
2427c65b1445SDouglas Gilbert 		break;
24281da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24291da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24301da177e4SLinus Torvalds 		offset += len;
24311da177e4SLinus Torvalds 		break;
24321da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2433c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24341da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24351da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2436760f3b03SDouglas Gilbert 			if (is_disk) {
2437760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2438760f3b03SDouglas Gilbert 						      target);
2439760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2440760f3b03SDouglas Gilbert 						       target);
2441d36da305SDouglas Gilbert 			} else if (is_zbc) {
2442d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2443d36da305SDouglas Gilbert 						       target);
2444760f3b03SDouglas Gilbert 			}
24451da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2446c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2447c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2448c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2449c65b1445SDouglas Gilbert 						  target, target_dev_id);
2450c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2451c65b1445SDouglas Gilbert 			}
24521da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2453760f3b03SDouglas Gilbert 			offset += len;
2454c65b1445SDouglas Gilbert 		} else {
245522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2456c65b1445SDouglas Gilbert 			return check_condition_result;
2457c65b1445SDouglas Gilbert 		}
24581da177e4SLinus Torvalds 		break;
24591da177e4SLinus Torvalds 	default:
2460760f3b03SDouglas Gilbert 		bad_pcode = true;
2461760f3b03SDouglas Gilbert 		break;
2462760f3b03SDouglas Gilbert 	}
2463760f3b03SDouglas Gilbert 	if (bad_pcode) {
246422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24651da177e4SLinus Torvalds 		return check_condition_result;
24661da177e4SLinus Torvalds 	}
24671da177e4SLinus Torvalds 	if (msense_6)
24681da177e4SLinus Torvalds 		arr[0] = offset - 1;
2469773642d9SDouglas Gilbert 	else
2470773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
247187c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24721da177e4SLinus Torvalds }
24731da177e4SLinus Torvalds 
2474c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2475c65b1445SDouglas Gilbert 
2476fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2477fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2478c65b1445SDouglas Gilbert {
2479c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2480c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2481c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
248201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2483c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2484c65b1445SDouglas Gilbert 
2485c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2486c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2487c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2488773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2489c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
249022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2491c65b1445SDouglas Gilbert 		return check_condition_result;
2492c65b1445SDouglas Gilbert 	}
2493c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2494c65b1445SDouglas Gilbert 	if (-1 == res)
2495773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2496773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2497cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2498cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2499cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2500773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2501773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
250223183910SDouglas Gilbert 	if (md_len > 2) {
250322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2504c65b1445SDouglas Gilbert 		return check_condition_result;
2505c65b1445SDouglas Gilbert 	}
2506c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2507c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2508c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2509c65b1445SDouglas Gilbert 	if (ps) {
251022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2511c65b1445SDouglas Gilbert 		return check_condition_result;
2512c65b1445SDouglas Gilbert 	}
2513c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2514773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2515c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2516c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2517cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2518c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2519c65b1445SDouglas Gilbert 		return check_condition_result;
2520c65b1445SDouglas Gilbert 	}
2521c65b1445SDouglas Gilbert 	switch (mpage) {
2522cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2523cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2524cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2525cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2526cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2527cbf67842SDouglas Gilbert 		}
2528cbf67842SDouglas Gilbert 		break;
2529c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2530c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2531c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2532c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25339447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25349447b6ceSMartin K. Petersen 				sdebug_wp = true;
25359447b6ceSMartin K. Petersen 			else
25369447b6ceSMartin K. Petersen 				sdebug_wp = false;
2537773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2538cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2539c65b1445SDouglas Gilbert 		}
2540c65b1445SDouglas Gilbert 		break;
2541c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2542c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2543c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2544c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2545cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2546c65b1445SDouglas Gilbert 		}
2547c65b1445SDouglas Gilbert 		break;
2548c65b1445SDouglas Gilbert 	default:
2549c65b1445SDouglas Gilbert 		break;
2550c65b1445SDouglas Gilbert 	}
255122017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2552c65b1445SDouglas Gilbert 	return check_condition_result;
2553cbf67842SDouglas Gilbert set_mode_changed_ua:
2554cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2555cbf67842SDouglas Gilbert 	return 0;
2556c65b1445SDouglas Gilbert }
2557c65b1445SDouglas Gilbert 
2558c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2559c65b1445SDouglas Gilbert {
2560c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2561c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2562c65b1445SDouglas Gilbert 		};
2563c65b1445SDouglas Gilbert 
2564c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2565c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2566c65b1445SDouglas Gilbert }
2567c65b1445SDouglas Gilbert 
2568c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2569c65b1445SDouglas Gilbert {
2570c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2571c65b1445SDouglas Gilbert 		};
2572c65b1445SDouglas Gilbert 
2573c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2574c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2575c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2576c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2577c65b1445SDouglas Gilbert 	}
2578c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2579c65b1445SDouglas Gilbert }
2580c65b1445SDouglas Gilbert 
2581c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2582c65b1445SDouglas Gilbert 
2583c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2584c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2585c65b1445SDouglas Gilbert {
2586ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2587c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
258801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2589c65b1445SDouglas Gilbert 
2590c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2591c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2592c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2593c65b1445SDouglas Gilbert 	if (ppc || sp) {
259422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2595c65b1445SDouglas Gilbert 		return check_condition_result;
2596c65b1445SDouglas Gilbert 	}
2597c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
259823183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2599773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2600c65b1445SDouglas Gilbert 	arr[0] = pcode;
260123183910SDouglas Gilbert 	if (0 == subpcode) {
2602c65b1445SDouglas Gilbert 		switch (pcode) {
2603c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2604c65b1445SDouglas Gilbert 			n = 4;
2605c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2606c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2607c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2608c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2609c65b1445SDouglas Gilbert 			break;
2610c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2611c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2612c65b1445SDouglas Gilbert 			break;
2613c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2614c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2615c65b1445SDouglas Gilbert 			break;
2616c65b1445SDouglas Gilbert 		default:
261722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2618c65b1445SDouglas Gilbert 			return check_condition_result;
2619c65b1445SDouglas Gilbert 		}
262023183910SDouglas Gilbert 	} else if (0xff == subpcode) {
262123183910SDouglas Gilbert 		arr[0] |= 0x40;
262223183910SDouglas Gilbert 		arr[1] = subpcode;
262323183910SDouglas Gilbert 		switch (pcode) {
262423183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
262523183910SDouglas Gilbert 			n = 4;
262623183910SDouglas Gilbert 			arr[n++] = 0x0;
262723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
262823183910SDouglas Gilbert 			arr[n++] = 0x0;
262923183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
263023183910SDouglas Gilbert 			arr[n++] = 0xd;
263123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
263223183910SDouglas Gilbert 			arr[n++] = 0x2f;
263323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
263423183910SDouglas Gilbert 			arr[3] = n - 4;
263523183910SDouglas Gilbert 			break;
263623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
263723183910SDouglas Gilbert 			n = 4;
263823183910SDouglas Gilbert 			arr[n++] = 0xd;
263923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
264023183910SDouglas Gilbert 			arr[3] = n - 4;
264123183910SDouglas Gilbert 			break;
264223183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
264323183910SDouglas Gilbert 			n = 4;
264423183910SDouglas Gilbert 			arr[n++] = 0x2f;
264523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
264623183910SDouglas Gilbert 			arr[3] = n - 4;
264723183910SDouglas Gilbert 			break;
264823183910SDouglas Gilbert 		default:
264922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
265023183910SDouglas Gilbert 			return check_condition_result;
265123183910SDouglas Gilbert 		}
265223183910SDouglas Gilbert 	} else {
265322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
265423183910SDouglas Gilbert 		return check_condition_result;
265523183910SDouglas Gilbert 	}
265687c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2657c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
265887c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2659c65b1445SDouglas Gilbert }
2660c65b1445SDouglas Gilbert 
2661f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2662f0d1cf93SDouglas Gilbert {
2663f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2664f0d1cf93SDouglas Gilbert }
2665f0d1cf93SDouglas Gilbert 
2666f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2667f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2668f0d1cf93SDouglas Gilbert {
2669108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2670f0d1cf93SDouglas Gilbert }
2671f0d1cf93SDouglas Gilbert 
2672f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2673f0d1cf93SDouglas Gilbert {
267464e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2675f0d1cf93SDouglas Gilbert }
2676f0d1cf93SDouglas Gilbert 
2677f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2678f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2679f0d1cf93SDouglas Gilbert {
2680f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2681f0d1cf93SDouglas Gilbert 
2682f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2683f0d1cf93SDouglas Gilbert 		return;
2684f0d1cf93SDouglas Gilbert 
2685f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2686f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2687f0d1cf93SDouglas Gilbert 		return;
2688f0d1cf93SDouglas Gilbert 
2689f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2690f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2691f0d1cf93SDouglas Gilbert 	else
2692f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2693f0d1cf93SDouglas Gilbert 
2694f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2695f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2696f0d1cf93SDouglas Gilbert 	} else {
2697f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2698f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2699f0d1cf93SDouglas Gilbert 	}
2700f0d1cf93SDouglas Gilbert }
2701f0d1cf93SDouglas Gilbert 
2702f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2703f0d1cf93SDouglas Gilbert {
2704f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2705f0d1cf93SDouglas Gilbert 	unsigned int i;
2706f0d1cf93SDouglas Gilbert 
2707f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2708f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2709f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2710f0d1cf93SDouglas Gilbert 			return;
2711f0d1cf93SDouglas Gilbert 		}
2712f0d1cf93SDouglas Gilbert 	}
2713f0d1cf93SDouglas Gilbert }
2714f0d1cf93SDouglas Gilbert 
2715f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2716f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2717f0d1cf93SDouglas Gilbert {
2718f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2719f0d1cf93SDouglas Gilbert 
2720f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2721f0d1cf93SDouglas Gilbert 		return;
2722f0d1cf93SDouglas Gilbert 
2723f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2724f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2725f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2726f0d1cf93SDouglas Gilbert 		return;
2727f0d1cf93SDouglas Gilbert 
2728f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2729f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2730f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2731f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2732f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2733f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2734f0d1cf93SDouglas Gilbert 
2735f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2736f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2737f0d1cf93SDouglas Gilbert 	if (explicit) {
2738f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2739f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2740f0d1cf93SDouglas Gilbert 	} else {
2741f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2742f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2743f0d1cf93SDouglas Gilbert 	}
2744f0d1cf93SDouglas Gilbert }
2745f0d1cf93SDouglas Gilbert 
2746f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2747f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2748f0d1cf93SDouglas Gilbert {
2749f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
275064e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2751f0d1cf93SDouglas Gilbert 
2752f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2753f0d1cf93SDouglas Gilbert 		return;
2754f0d1cf93SDouglas Gilbert 
275564e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2756f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
275764e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2758f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
275964e14eceSDamien Le Moal 		return;
276064e14eceSDamien Le Moal 	}
276164e14eceSDamien Le Moal 
276264e14eceSDamien Le Moal 	while (num) {
276364e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
276464e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
276564e14eceSDamien Le Moal 
276664e14eceSDamien Le Moal 		end = lba + num;
276764e14eceSDamien Le Moal 		if (end >= zend) {
276864e14eceSDamien Le Moal 			n = zend - lba;
276964e14eceSDamien Le Moal 			zsp->z_wp = zend;
277064e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
277164e14eceSDamien Le Moal 			n = num;
277264e14eceSDamien Le Moal 			zsp->z_wp = end;
277364e14eceSDamien Le Moal 		} else {
277464e14eceSDamien Le Moal 			n = num;
277564e14eceSDamien Le Moal 		}
277664e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
277764e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
277864e14eceSDamien Le Moal 
277964e14eceSDamien Le Moal 		num -= n;
278064e14eceSDamien Le Moal 		lba += n;
278164e14eceSDamien Le Moal 		if (num) {
278264e14eceSDamien Le Moal 			zsp++;
278364e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
278464e14eceSDamien Le Moal 		}
278564e14eceSDamien Le Moal 	}
2786f0d1cf93SDouglas Gilbert }
2787f0d1cf93SDouglas Gilbert 
2788f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27899447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27901da177e4SLinus Torvalds {
2791f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2792f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2793f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2794f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2795f0d1cf93SDouglas Gilbert 
2796f0d1cf93SDouglas Gilbert 	if (!write) {
279764e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
279864e14eceSDamien Le Moal 			return 0;
279964e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2800f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2801f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2802f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2803f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2804f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2805f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2806f0d1cf93SDouglas Gilbert 			return check_condition_result;
2807f0d1cf93SDouglas Gilbert 		}
2808f0d1cf93SDouglas Gilbert 		return 0;
2809f0d1cf93SDouglas Gilbert 	}
2810f0d1cf93SDouglas Gilbert 
2811f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2812f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2813f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2814f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2815f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2816f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2817f0d1cf93SDouglas Gilbert 			return check_condition_result;
2818f0d1cf93SDouglas Gilbert 		}
2819f0d1cf93SDouglas Gilbert 		return 0;
2820f0d1cf93SDouglas Gilbert 	}
2821f0d1cf93SDouglas Gilbert 
282264e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2823f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2824f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2825f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2826f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2827f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2828f0d1cf93SDouglas Gilbert 			return check_condition_result;
2829f0d1cf93SDouglas Gilbert 		}
2830f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2831f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2832f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2833f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2834f0d1cf93SDouglas Gilbert 			return check_condition_result;
2835f0d1cf93SDouglas Gilbert 		}
2836f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2837f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2838f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2839f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2840f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2841f0d1cf93SDouglas Gilbert 			return check_condition_result;
2842f0d1cf93SDouglas Gilbert 		}
284364e14eceSDamien Le Moal 	}
2844f0d1cf93SDouglas Gilbert 
2845f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2846f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2847f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2848f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2849f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2850f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2851f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2852f0d1cf93SDouglas Gilbert 			return check_condition_result;
2853f0d1cf93SDouglas Gilbert 		}
2854f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2855f0d1cf93SDouglas Gilbert 	}
2856f0d1cf93SDouglas Gilbert 
2857f0d1cf93SDouglas Gilbert 	return 0;
2858f0d1cf93SDouglas Gilbert }
2859f0d1cf93SDouglas Gilbert 
2860f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2861f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2862f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2863f0d1cf93SDouglas Gilbert {
2864f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2865f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2866f0d1cf93SDouglas Gilbert 
2867c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
286822017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28691da177e4SLinus Torvalds 		return check_condition_result;
28701da177e4SLinus Torvalds 	}
2871c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2872c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
287322017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2874cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2875c65b1445SDouglas Gilbert 		return check_condition_result;
2876c65b1445SDouglas Gilbert 	}
28779447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28789447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28799447b6ceSMartin K. Petersen 		return check_condition_result;
28809447b6ceSMartin K. Petersen 	}
2881f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2882f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2883f0d1cf93SDouglas Gilbert 
288419789100SFUJITA Tomonori 	return 0;
288519789100SFUJITA Tomonori }
288619789100SFUJITA Tomonori 
2887b6ff8ca7SDouglas Gilbert /*
2888b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2889b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2890b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2891b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2892b6ff8ca7SDouglas Gilbert  */
2893b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2894b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
289587c715dcSDouglas Gilbert {
2896b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2897b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2898b6ff8ca7SDouglas Gilbert 		return NULL;
2899b6ff8ca7SDouglas Gilbert 	}
2900b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
290187c715dcSDouglas Gilbert }
290287c715dcSDouglas Gilbert 
2903a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
290487c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
290587c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
290619789100SFUJITA Tomonori {
290719789100SFUJITA Tomonori 	int ret;
2908c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2909a4517511SAkinobu Mita 	enum dma_data_direction dir;
291087c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
291187c715dcSDouglas Gilbert 	u8 *fsp;
291219789100SFUJITA Tomonori 
2913c2248fc9SDouglas Gilbert 	if (do_write) {
2914a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
29154f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2916a4517511SAkinobu Mita 	} else {
2917a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2918a4517511SAkinobu Mita 	}
2919a4517511SAkinobu Mita 
292087c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2921a4517511SAkinobu Mita 		return 0;
292287c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2923a4517511SAkinobu Mita 		return -1;
292487c715dcSDouglas Gilbert 	fsp = sip->storep;
292519789100SFUJITA Tomonori 
292619789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
292719789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
292819789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
292919789100SFUJITA Tomonori 
2930386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
293187c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29320a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2933773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2934a4517511SAkinobu Mita 		return ret;
2935a4517511SAkinobu Mita 
2936a4517511SAkinobu Mita 	if (rest) {
2937386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
293887c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29390a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29400a7e69c7SDouglas Gilbert 			    do_write);
2941a4517511SAkinobu Mita 	}
294219789100SFUJITA Tomonori 
294319789100SFUJITA Tomonori 	return ret;
294419789100SFUJITA Tomonori }
294519789100SFUJITA Tomonori 
294687c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
294787c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
294887c715dcSDouglas Gilbert {
294987c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
295087c715dcSDouglas Gilbert 
295187c715dcSDouglas Gilbert 	if (!sdb->length)
295287c715dcSDouglas Gilbert 		return 0;
295387c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
295487c715dcSDouglas Gilbert 		return -1;
295587c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
295687c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
295787c715dcSDouglas Gilbert }
295887c715dcSDouglas Gilbert 
295987c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
296087c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
296138d5c833SDouglas Gilbert  * return false. */
296287c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2963c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
296438d5c833SDouglas Gilbert {
296538d5c833SDouglas Gilbert 	bool res;
296638d5c833SDouglas Gilbert 	u64 block, rest = 0;
296738d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2968773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
296987c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
297038d5c833SDouglas Gilbert 
297138d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
297238d5c833SDouglas Gilbert 	if (block + num > store_blks)
297338d5c833SDouglas Gilbert 		rest = block + num - store_blks;
297438d5c833SDouglas Gilbert 
297587c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
297638d5c833SDouglas Gilbert 	if (!res)
297738d5c833SDouglas Gilbert 		return res;
297838d5c833SDouglas Gilbert 	if (rest)
297987c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
298038d5c833SDouglas Gilbert 			     rest * lb_size);
298138d5c833SDouglas Gilbert 	if (!res)
298238d5c833SDouglas Gilbert 		return res;
2983c3e2fe92SDouglas Gilbert 	if (compare_only)
2984c3e2fe92SDouglas Gilbert 		return true;
298538d5c833SDouglas Gilbert 	arr += num * lb_size;
298687c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
298738d5c833SDouglas Gilbert 	if (rest)
298887c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
298938d5c833SDouglas Gilbert 	return res;
299038d5c833SDouglas Gilbert }
299138d5c833SDouglas Gilbert 
299251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2993beb40ea4SAkinobu Mita {
299451d648afSAkinobu Mita 	__be16 csum;
2995beb40ea4SAkinobu Mita 
2996773642d9SDouglas Gilbert 	if (sdebug_guard)
299751d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
299851d648afSAkinobu Mita 	else
2999beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
300051d648afSAkinobu Mita 
3001beb40ea4SAkinobu Mita 	return csum;
3002beb40ea4SAkinobu Mita }
3003beb40ea4SAkinobu Mita 
30046ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3005beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3006beb40ea4SAkinobu Mita {
3007773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3008beb40ea4SAkinobu Mita 
3009beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3010c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3011beb40ea4SAkinobu Mita 			(unsigned long)sector,
3012beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3013beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3014beb40ea4SAkinobu Mita 		return 0x01;
3015beb40ea4SAkinobu Mita 	}
30168475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3017beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3018c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3019c1287970STomas Winkler 			(unsigned long)sector);
3020beb40ea4SAkinobu Mita 		return 0x03;
3021beb40ea4SAkinobu Mita 	}
30228475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3023beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3024c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3025c1287970STomas Winkler 			(unsigned long)sector);
3026beb40ea4SAkinobu Mita 		return 0x03;
3027beb40ea4SAkinobu Mita 	}
3028beb40ea4SAkinobu Mita 	return 0;
3029beb40ea4SAkinobu Mita }
3030beb40ea4SAkinobu Mita 
303187c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
303265f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3033c6a44287SMartin K. Petersen {
3034be4e11beSAkinobu Mita 	size_t resid;
3035c6a44287SMartin K. Petersen 	void *paddr;
303687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3037b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
303887c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
303914faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3040be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3041c6a44287SMartin K. Petersen 
3042e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3043e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3044c6a44287SMartin K. Petersen 
304587c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
304687c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3047be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3048be4e11beSAkinobu Mita 
3049be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
305087c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
305187c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3052be4e11beSAkinobu Mita 		size_t rest = 0;
305314faa944SAkinobu Mita 
305414faa944SAkinobu Mita 		if (dif_store_end < start + len)
305514faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3056c6a44287SMartin K. Petersen 
3057be4e11beSAkinobu Mita 		paddr = miter.addr;
305814faa944SAkinobu Mita 
305965f72f2aSAkinobu Mita 		if (read)
306065f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
306165f72f2aSAkinobu Mita 		else
306265f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
306365f72f2aSAkinobu Mita 
306465f72f2aSAkinobu Mita 		if (rest) {
306565f72f2aSAkinobu Mita 			if (read)
306614faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
306765f72f2aSAkinobu Mita 			else
306865f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
306965f72f2aSAkinobu Mita 		}
3070c6a44287SMartin K. Petersen 
3071e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3072c6a44287SMartin K. Petersen 		resid -= len;
3073c6a44287SMartin K. Petersen 	}
3074be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3075bb8c063cSAkinobu Mita }
3076c6a44287SMartin K. Petersen 
307787c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3078bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3079bb8c063cSAkinobu Mita {
3080f7be6772SMartin K. Petersen 	int ret = 0;
3081bb8c063cSAkinobu Mita 	unsigned int i;
3082bb8c063cSAkinobu Mita 	sector_t sector;
308387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3084b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
308587c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3086bb8c063cSAkinobu Mita 
3087c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3088bb8c063cSAkinobu Mita 		sector = start_sec + i;
308987c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3090bb8c063cSAkinobu Mita 
309151d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3092bb8c063cSAkinobu Mita 			continue;
3093bb8c063cSAkinobu Mita 
3094f7be6772SMartin K. Petersen 		/*
3095f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3096f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3097f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3098f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3099f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3100f7be6772SMartin K. Petersen 		 */
3101f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3102f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3103f7be6772SMartin K. Petersen 					 sector, ei_lba);
3104bb8c063cSAkinobu Mita 			if (ret) {
3105bb8c063cSAkinobu Mita 				dif_errors++;
3106f7be6772SMartin K. Petersen 				break;
3107f7be6772SMartin K. Petersen 			}
3108bb8c063cSAkinobu Mita 		}
3109bb8c063cSAkinobu Mita 	}
3110bb8c063cSAkinobu Mita 
311187c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3112c6a44287SMartin K. Petersen 	dix_reads++;
3113c6a44287SMartin K. Petersen 
3114f7be6772SMartin K. Petersen 	return ret;
3115c6a44287SMartin K. Petersen }
3116c6a44287SMartin K. Petersen 
3117fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
311819789100SFUJITA Tomonori {
311987c715dcSDouglas Gilbert 	bool check_prot;
3120c2248fc9SDouglas Gilbert 	u32 num;
3121c2248fc9SDouglas Gilbert 	u32 ei_lba;
312219789100SFUJITA Tomonori 	int ret;
312387c715dcSDouglas Gilbert 	u64 lba;
3124b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
312587c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
312687c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
312719789100SFUJITA Tomonori 
3128c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3129c2248fc9SDouglas Gilbert 	case READ_16:
3130c2248fc9SDouglas Gilbert 		ei_lba = 0;
3131c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3132c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3133c2248fc9SDouglas Gilbert 		check_prot = true;
3134c2248fc9SDouglas Gilbert 		break;
3135c2248fc9SDouglas Gilbert 	case READ_10:
3136c2248fc9SDouglas Gilbert 		ei_lba = 0;
3137c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3138c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3139c2248fc9SDouglas Gilbert 		check_prot = true;
3140c2248fc9SDouglas Gilbert 		break;
3141c2248fc9SDouglas Gilbert 	case READ_6:
3142c2248fc9SDouglas Gilbert 		ei_lba = 0;
3143c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3144c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3145c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3146c2248fc9SDouglas Gilbert 		check_prot = true;
3147c2248fc9SDouglas Gilbert 		break;
3148c2248fc9SDouglas Gilbert 	case READ_12:
3149c2248fc9SDouglas Gilbert 		ei_lba = 0;
3150c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3151c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3152c2248fc9SDouglas Gilbert 		check_prot = true;
3153c2248fc9SDouglas Gilbert 		break;
3154c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3155c2248fc9SDouglas Gilbert 		ei_lba = 0;
3156c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3157c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3158c2248fc9SDouglas Gilbert 		check_prot = false;
3159c2248fc9SDouglas Gilbert 		break;
3160c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3161c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3162c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3163c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3164c2248fc9SDouglas Gilbert 		check_prot = false;
3165c2248fc9SDouglas Gilbert 		break;
3166c2248fc9SDouglas Gilbert 	}
3167f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31688475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3169c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3170c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3171c2248fc9SDouglas Gilbert 			return check_condition_result;
3172c2248fc9SDouglas Gilbert 		}
31738475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31748475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3175c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3176c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3177c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3178c2248fc9SDouglas Gilbert 	}
31793a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
31803a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3181c2248fc9SDouglas Gilbert 		num /= 2;
31823a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3183c2248fc9SDouglas Gilbert 	}
3184c2248fc9SDouglas Gilbert 
31859447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31869447b6ceSMartin K. Petersen 	if (ret)
31879447b6ceSMartin K. Petersen 		return ret;
3188f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3189d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3190d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3191c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3192c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3193c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3194c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3195c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
319632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
319732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3198c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3199c65b1445SDouglas Gilbert 		}
3200c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
32011da177e4SLinus Torvalds 		return check_condition_result;
32021da177e4SLinus Torvalds 	}
3203c6a44287SMartin K. Petersen 
320467da413fSDouglas Gilbert 	read_lock(macc_lckp);
32056c78cc06SAkinobu Mita 
3206c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3207f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3208f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3209f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3210f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
321167da413fSDouglas Gilbert 				read_unlock(macc_lckp);
3212f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3213f7be6772SMartin K. Petersen 				return check_condition_result;
3214f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
3215f7be6772SMartin K. Petersen 				read_unlock(macc_lckp);
3216f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3217c6a44287SMartin K. Petersen 				return illegal_condition_result;
3218c6a44287SMartin K. Petersen 			}
3219f7be6772SMartin K. Petersen 			break;
3220f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3221f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
3222f7be6772SMartin K. Petersen 				read_unlock(macc_lckp);
3223f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3224f7be6772SMartin K. Petersen 				return check_condition_result;
3225f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
3226f7be6772SMartin K. Petersen 				read_unlock(macc_lckp);
3227f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3228f7be6772SMartin K. Petersen 				return illegal_condition_result;
3229f7be6772SMartin K. Petersen 			}
3230f7be6772SMartin K. Petersen 			break;
3231f7be6772SMartin K. Petersen 		}
3232c6a44287SMartin K. Petersen 	}
3233c6a44287SMartin K. Petersen 
323487c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
323567da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3236f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3237a4517511SAkinobu Mita 		return DID_ERROR << 16;
3238a4517511SAkinobu Mita 
323942d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3240a4517511SAkinobu Mita 
32413a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
32423a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
32433a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
32443a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
32453a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3246c2248fc9SDouglas Gilbert 			return check_condition_result;
32473a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3248c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3249c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
32503a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3251c2248fc9SDouglas Gilbert 			return illegal_condition_result;
32523a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3253c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
32543a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3255c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3256c2248fc9SDouglas Gilbert 		}
3257c2248fc9SDouglas Gilbert 	}
3258a4517511SAkinobu Mita 	return 0;
32591da177e4SLinus Torvalds }
32601da177e4SLinus Torvalds 
3261c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3262395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3263c6a44287SMartin K. Petersen {
3264be4e11beSAkinobu Mita 	int ret;
32656ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3266be4e11beSAkinobu Mita 	void *daddr;
326765f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3268c6a44287SMartin K. Petersen 	int ppage_offset;
3269be4e11beSAkinobu Mita 	int dpage_offset;
3270be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3271be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3272c6a44287SMartin K. Petersen 
3273c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3274c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3275c6a44287SMartin K. Petersen 
3276be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3277be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3278be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3279be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3280be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3281c6a44287SMartin K. Petersen 
3282be4e11beSAkinobu Mita 	/* For each protection page */
3283be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3284be4e11beSAkinobu Mita 		dpage_offset = 0;
3285be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3286be4e11beSAkinobu Mita 			ret = 0x01;
3287be4e11beSAkinobu Mita 			goto out;
3288c6a44287SMartin K. Petersen 		}
3289c6a44287SMartin K. Petersen 
3290be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32916ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3292be4e11beSAkinobu Mita 			/* If we're at the end of the current
3293be4e11beSAkinobu Mita 			 * data page advance to the next one
3294be4e11beSAkinobu Mita 			 */
3295be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3296be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3297be4e11beSAkinobu Mita 					ret = 0x01;
3298be4e11beSAkinobu Mita 					goto out;
3299be4e11beSAkinobu Mita 				}
3300be4e11beSAkinobu Mita 				dpage_offset = 0;
3301be4e11beSAkinobu Mita 			}
3302c6a44287SMartin K. Petersen 
3303be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3304be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3305be4e11beSAkinobu Mita 
3306f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3307be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3308c78be80dSMartin K. Petersen 				if (ret)
3309395cef03SMartin K. Petersen 					goto out;
3310395cef03SMartin K. Petersen 			}
3311395cef03SMartin K. Petersen 
3312c6a44287SMartin K. Petersen 			sector++;
3313395cef03SMartin K. Petersen 			ei_lba++;
3314773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3315c6a44287SMartin K. Petersen 		}
3316be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3317be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3318c6a44287SMartin K. Petersen 	}
3319be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3320c6a44287SMartin K. Petersen 
332165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3322c6a44287SMartin K. Petersen 	dix_writes++;
3323c6a44287SMartin K. Petersen 
3324c6a44287SMartin K. Petersen 	return 0;
3325c6a44287SMartin K. Petersen 
3326c6a44287SMartin K. Petersen out:
3327c6a44287SMartin K. Petersen 	dif_errors++;
3328be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3329be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3330c6a44287SMartin K. Petersen 	return ret;
3331c6a44287SMartin K. Petersen }
3332c6a44287SMartin K. Petersen 
3333b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3334b90ebc3dSAkinobu Mita {
3335773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3336773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3337773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3338b90ebc3dSAkinobu Mita 	return lba;
3339b90ebc3dSAkinobu Mita }
3340b90ebc3dSAkinobu Mita 
3341b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3342b90ebc3dSAkinobu Mita {
3343773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3344a027b5b9SAkinobu Mita 
3345773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3346773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3347a027b5b9SAkinobu Mita 	return lba;
3348a027b5b9SAkinobu Mita }
3349a027b5b9SAkinobu Mita 
335087c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
335187c715dcSDouglas Gilbert 			      unsigned int *num)
335244d92694SMartin K. Petersen {
3353b90ebc3dSAkinobu Mita 	sector_t end;
3354b90ebc3dSAkinobu Mita 	unsigned int mapped;
3355b90ebc3dSAkinobu Mita 	unsigned long index;
3356b90ebc3dSAkinobu Mita 	unsigned long next;
335744d92694SMartin K. Petersen 
3358b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
335987c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
336044d92694SMartin K. Petersen 
336144d92694SMartin K. Petersen 	if (mapped)
336287c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
336344d92694SMartin K. Petersen 	else
336487c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
336544d92694SMartin K. Petersen 
3366b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
336744d92694SMartin K. Petersen 	*num = end - lba;
336844d92694SMartin K. Petersen 	return mapped;
336944d92694SMartin K. Petersen }
337044d92694SMartin K. Petersen 
337187c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
337287c715dcSDouglas Gilbert 		       unsigned int len)
337344d92694SMartin K. Petersen {
337444d92694SMartin K. Petersen 	sector_t end = lba + len;
337544d92694SMartin K. Petersen 
337644d92694SMartin K. Petersen 	while (lba < end) {
3377b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
337844d92694SMartin K. Petersen 
3379b90ebc3dSAkinobu Mita 		if (index < map_size)
338087c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
338144d92694SMartin K. Petersen 
3382b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
338344d92694SMartin K. Petersen 	}
338444d92694SMartin K. Petersen }
338544d92694SMartin K. Petersen 
338687c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
338787c715dcSDouglas Gilbert 			 unsigned int len)
338844d92694SMartin K. Petersen {
338944d92694SMartin K. Petersen 	sector_t end = lba + len;
339087c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
339144d92694SMartin K. Petersen 
339244d92694SMartin K. Petersen 	while (lba < end) {
3393b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
339444d92694SMartin K. Petersen 
3395b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3396773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3397b90ebc3dSAkinobu Mita 		    index < map_size) {
339887c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3399760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
340087c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3401760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3402773642d9SDouglas Gilbert 				       sdebug_sector_size *
3403773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3404be1dd78dSEric Sandeen 			}
340587c715dcSDouglas Gilbert 			if (sip->dif_storep) {
340687c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
340787c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3408773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3409e9926b43SAkinobu Mita 			}
3410b90ebc3dSAkinobu Mita 		}
3411b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
341244d92694SMartin K. Petersen 	}
341344d92694SMartin K. Petersen }
341444d92694SMartin K. Petersen 
3415fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34161da177e4SLinus Torvalds {
341787c715dcSDouglas Gilbert 	bool check_prot;
3418c2248fc9SDouglas Gilbert 	u32 num;
3419c2248fc9SDouglas Gilbert 	u32 ei_lba;
342019789100SFUJITA Tomonori 	int ret;
342187c715dcSDouglas Gilbert 	u64 lba;
3422b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3423b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
342487c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
34251da177e4SLinus Torvalds 
3426c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3427c2248fc9SDouglas Gilbert 	case WRITE_16:
3428c2248fc9SDouglas Gilbert 		ei_lba = 0;
3429c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3430c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3431c2248fc9SDouglas Gilbert 		check_prot = true;
3432c2248fc9SDouglas Gilbert 		break;
3433c2248fc9SDouglas Gilbert 	case WRITE_10:
3434c2248fc9SDouglas Gilbert 		ei_lba = 0;
3435c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3436c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3437c2248fc9SDouglas Gilbert 		check_prot = true;
3438c2248fc9SDouglas Gilbert 		break;
3439c2248fc9SDouglas Gilbert 	case WRITE_6:
3440c2248fc9SDouglas Gilbert 		ei_lba = 0;
3441c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3442c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3443c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3444c2248fc9SDouglas Gilbert 		check_prot = true;
3445c2248fc9SDouglas Gilbert 		break;
3446c2248fc9SDouglas Gilbert 	case WRITE_12:
3447c2248fc9SDouglas Gilbert 		ei_lba = 0;
3448c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3449c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3450c2248fc9SDouglas Gilbert 		check_prot = true;
3451c2248fc9SDouglas Gilbert 		break;
3452c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3453c2248fc9SDouglas Gilbert 		ei_lba = 0;
3454c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3455c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3456c2248fc9SDouglas Gilbert 		check_prot = false;
3457c2248fc9SDouglas Gilbert 		break;
3458c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3459c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3460c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3461c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3462c2248fc9SDouglas Gilbert 		check_prot = false;
3463c2248fc9SDouglas Gilbert 		break;
3464c2248fc9SDouglas Gilbert 	}
3465f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34668475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3467c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3468c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3469c2248fc9SDouglas Gilbert 			return check_condition_result;
3470c2248fc9SDouglas Gilbert 		}
34718475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34728475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3473c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3474c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3475c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3476c2248fc9SDouglas Gilbert 	}
3477f0d1cf93SDouglas Gilbert 
347867da413fSDouglas Gilbert 	write_lock(macc_lckp);
3479f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3480f0d1cf93SDouglas Gilbert 	if (ret) {
3481f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3482f0d1cf93SDouglas Gilbert 		return ret;
3483f0d1cf93SDouglas Gilbert 	}
34846c78cc06SAkinobu Mita 
3485c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3486f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3487f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3488f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3489f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
349067da413fSDouglas Gilbert 				write_unlock(macc_lckp);
3491f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3492c6a44287SMartin K. Petersen 				return illegal_condition_result;
3493f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
3494f7be6772SMartin K. Petersen 				write_unlock(macc_lckp);
3495f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3496f7be6772SMartin K. Petersen 				return check_condition_result;
3497f7be6772SMartin K. Petersen 			}
3498f7be6772SMartin K. Petersen 			break;
3499f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3500f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
3501f7be6772SMartin K. Petersen 				write_unlock(macc_lckp);
3502f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3503f7be6772SMartin K. Petersen 				return illegal_condition_result;
3504f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
3505f7be6772SMartin K. Petersen 				write_unlock(macc_lckp);
3506f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3507f7be6772SMartin K. Petersen 				return check_condition_result;
3508f7be6772SMartin K. Petersen 			}
3509f7be6772SMartin K. Petersen 			break;
3510c6a44287SMartin K. Petersen 		}
3511c6a44287SMartin K. Petersen 	}
3512c6a44287SMartin K. Petersen 
351387c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3514f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
351587c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3516f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3517f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3518f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
351967da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3520f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3521773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3522c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3523c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3524c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3525cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3526773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
352744d92694SMartin K. Petersen 
35283a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
35293a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
35303a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
35313a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
35323a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3533c2248fc9SDouglas Gilbert 			return check_condition_result;
35343a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3535c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3536c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
35373a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3538c2248fc9SDouglas Gilbert 			return illegal_condition_result;
35393a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3540c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
35413a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3542c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3543c2248fc9SDouglas Gilbert 		}
3544c2248fc9SDouglas Gilbert 	}
35451da177e4SLinus Torvalds 	return 0;
35461da177e4SLinus Torvalds }
35471da177e4SLinus Torvalds 
3548481b5e5cSDouglas Gilbert /*
3549481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3550481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3551481b5e5cSDouglas Gilbert  */
3552481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3553481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3554481b5e5cSDouglas Gilbert {
3555481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3556481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3557481b5e5cSDouglas Gilbert 	u8 *up;
3558b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3559b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
3560481b5e5cSDouglas Gilbert 	u8 wrprotect;
3561481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3562481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3563481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3564481b5e5cSDouglas Gilbert 	u32 ei_lba;
3565481b5e5cSDouglas Gilbert 	u64 lba;
3566481b5e5cSDouglas Gilbert 	int ret, res;
3567481b5e5cSDouglas Gilbert 	bool is_16;
3568481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3569481b5e5cSDouglas Gilbert 
3570481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3571481b5e5cSDouglas Gilbert 		is_16 = false;
3572481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3573481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3574481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3575481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3576481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3577481b5e5cSDouglas Gilbert 		is_16 = true;
3578481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3579481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3580481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3581481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3582481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3583481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3584481b5e5cSDouglas Gilbert 			    wrprotect) {
3585481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3586481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3587481b5e5cSDouglas Gilbert 			}
3588481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3589481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3590481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3591481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3592481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3593481b5e5cSDouglas Gilbert 		}
3594481b5e5cSDouglas Gilbert 	}
3595481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3596481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3597481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3598481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3599481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3600481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3601481b5e5cSDouglas Gilbert 				my_name, __func__);
3602481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3603481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3604481b5e5cSDouglas Gilbert 	}
3605481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3606481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3607481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3608481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3609481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3610481b5e5cSDouglas Gilbert 				my_name, __func__);
3611481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3612481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3613481b5e5cSDouglas Gilbert 	}
3614481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3615481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3616481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3617481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3618481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3619481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3620481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3621481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3622481b5e5cSDouglas Gilbert 	if (res == -1) {
3623481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3624481b5e5cSDouglas Gilbert 		goto err_out;
3625481b5e5cSDouglas Gilbert 	}
3626481b5e5cSDouglas Gilbert 
362767da413fSDouglas Gilbert 	write_lock(macc_lckp);
3628481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3629481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3630481b5e5cSDouglas Gilbert 	cum_lb = 0;
3631481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3632481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3633481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3634481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3635481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3636481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3637481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3638481b5e5cSDouglas Gilbert 		if (num == 0)
3639481b5e5cSDouglas Gilbert 			continue;
36409447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3641481b5e5cSDouglas Gilbert 		if (ret)
3642481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3643481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3644481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3645481b5e5cSDouglas Gilbert 
3646481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3647481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3648481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3649481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3650481b5e5cSDouglas Gilbert 				    my_name, __func__);
3651481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3652481b5e5cSDouglas Gilbert 					0);
3653481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3654481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3655481b5e5cSDouglas Gilbert 		}
3656481b5e5cSDouglas Gilbert 
3657481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3658481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3659481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3660481b5e5cSDouglas Gilbert 							 ei_lba);
3661481b5e5cSDouglas Gilbert 
3662481b5e5cSDouglas Gilbert 			if (prot_ret) {
3663481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3664481b5e5cSDouglas Gilbert 						prot_ret);
3665481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3666481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3667481b5e5cSDouglas Gilbert 			}
3668481b5e5cSDouglas Gilbert 		}
3669481b5e5cSDouglas Gilbert 
367087c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3671f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3672f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3673f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3674481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
367587c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3676481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3677481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3678481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3679481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3680481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3681481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3682481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3683481b5e5cSDouglas Gilbert 
36843a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36853a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
36863a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36873a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36883a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
36893a90a63dSDouglas Gilbert 				ret = check_condition_result;
3690481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36913a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3692481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
36933a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
36943a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3695481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3696481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36973a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
36983a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
36993a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3700481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3701481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3702481b5e5cSDouglas Gilbert 			}
3703481b5e5cSDouglas Gilbert 		}
3704481b5e5cSDouglas Gilbert 		sg_off += num_by;
3705481b5e5cSDouglas Gilbert 		cum_lb += num;
3706481b5e5cSDouglas Gilbert 	}
3707481b5e5cSDouglas Gilbert 	ret = 0;
3708481b5e5cSDouglas Gilbert err_out_unlock:
370967da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3710481b5e5cSDouglas Gilbert err_out:
3711481b5e5cSDouglas Gilbert 	kfree(lrdp);
3712481b5e5cSDouglas Gilbert 	return ret;
3713481b5e5cSDouglas Gilbert }
3714481b5e5cSDouglas Gilbert 
3715fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3716fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
371744d92694SMartin K. Petersen {
3718f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3719f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
372044d92694SMartin K. Petersen 	unsigned long long i;
372140d07b52SDouglas Gilbert 	u64 block, lbaa;
372287c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
372387c715dcSDouglas Gilbert 	int ret;
372487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3725b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
3726b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
372740d07b52SDouglas Gilbert 	u8 *fs1p;
372887c715dcSDouglas Gilbert 	u8 *fsp;
372944d92694SMartin K. Petersen 
373067da413fSDouglas Gilbert 	write_lock(macc_lckp);
373144d92694SMartin K. Petersen 
3732f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3733f0d1cf93SDouglas Gilbert 	if (ret) {
3734f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3735f0d1cf93SDouglas Gilbert 		return ret;
3736f0d1cf93SDouglas Gilbert 	}
3737f0d1cf93SDouglas Gilbert 
37389ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
373987c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
374044d92694SMartin K. Petersen 		goto out;
374144d92694SMartin K. Petersen 	}
374240d07b52SDouglas Gilbert 	lbaa = lba;
374340d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3744c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
374587c715dcSDouglas Gilbert 	fsp = sip->storep;
374687c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3747c2248fc9SDouglas Gilbert 	if (ndob) {
374840d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3749c2248fc9SDouglas Gilbert 		ret = 0;
3750c2248fc9SDouglas Gilbert 	} else
375140d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
375244d92694SMartin K. Petersen 
375344d92694SMartin K. Petersen 	if (-1 == ret) {
375467da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3755773642d9SDouglas Gilbert 		return DID_ERROR << 16;
375640d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3757c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3758e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
375940d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
376044d92694SMartin K. Petersen 
376144d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
376240d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
376340d07b52SDouglas Gilbert 		lbaa = lba + i;
376440d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
376587c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
376640d07b52SDouglas Gilbert 	}
37679ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
376887c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3769f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3770f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3771f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
377244d92694SMartin K. Petersen out:
377367da413fSDouglas Gilbert 	write_unlock(macc_lckp);
377444d92694SMartin K. Petersen 
377544d92694SMartin K. Petersen 	return 0;
377644d92694SMartin K. Petersen }
377744d92694SMartin K. Petersen 
3778fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3779fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3780c2248fc9SDouglas Gilbert {
3781c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3782c2248fc9SDouglas Gilbert 	u32 lba;
3783c2248fc9SDouglas Gilbert 	u16 num;
3784c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3785c2248fc9SDouglas Gilbert 	bool unmap = false;
3786c2248fc9SDouglas Gilbert 
3787c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3788773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3789c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3790c2248fc9SDouglas Gilbert 			return check_condition_result;
3791c2248fc9SDouglas Gilbert 		} else
3792c2248fc9SDouglas Gilbert 			unmap = true;
3793c2248fc9SDouglas Gilbert 	}
3794c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3795c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3796773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3797c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3798c2248fc9SDouglas Gilbert 		return check_condition_result;
3799c2248fc9SDouglas Gilbert 	}
3800c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3801c2248fc9SDouglas Gilbert }
3802c2248fc9SDouglas Gilbert 
3803fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3804fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3805c2248fc9SDouglas Gilbert {
3806c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3807c2248fc9SDouglas Gilbert 	u64 lba;
3808c2248fc9SDouglas Gilbert 	u32 num;
3809c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3810c2248fc9SDouglas Gilbert 	bool unmap = false;
3811c2248fc9SDouglas Gilbert 	bool ndob = false;
3812c2248fc9SDouglas Gilbert 
3813c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3814773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3815c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3816c2248fc9SDouglas Gilbert 			return check_condition_result;
3817c2248fc9SDouglas Gilbert 		} else
3818c2248fc9SDouglas Gilbert 			unmap = true;
3819c2248fc9SDouglas Gilbert 	}
3820c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3821c2248fc9SDouglas Gilbert 		ndob = true;
3822c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3823c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3824773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3825c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3826c2248fc9SDouglas Gilbert 		return check_condition_result;
3827c2248fc9SDouglas Gilbert 	}
3828c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3829c2248fc9SDouglas Gilbert }
3830c2248fc9SDouglas Gilbert 
3831acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3832acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3833acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3834fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3835fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3836acafd0b9SEwan D. Milne {
3837acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3838acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3839acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3840acafd0b9SEwan D. Milne 	u8 mode;
3841acafd0b9SEwan D. Milne 
3842acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3843acafd0b9SEwan D. Milne 	switch (mode) {
3844acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3845acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3846acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3847acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3848acafd0b9SEwan D. Milne 		break;
3849acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3850acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3851acafd0b9SEwan D. Milne 		break;
3852acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3853acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3854acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3855acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3856acafd0b9SEwan D. Milne 				    dev_list)
3857acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3858acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3859acafd0b9SEwan D. Milne 				if (devip != dp)
3860acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3861acafd0b9SEwan D. Milne 						dp->uas_bm);
3862acafd0b9SEwan D. Milne 			}
3863acafd0b9SEwan D. Milne 		break;
3864acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3865acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3866acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3867acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3868acafd0b9SEwan D. Milne 				    dev_list)
3869acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3870acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3871acafd0b9SEwan D. Milne 					dp->uas_bm);
3872acafd0b9SEwan D. Milne 		break;
3873acafd0b9SEwan D. Milne 	default:
3874acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3875acafd0b9SEwan D. Milne 		break;
3876acafd0b9SEwan D. Milne 	}
3877acafd0b9SEwan D. Milne 	return 0;
3878acafd0b9SEwan D. Milne }
3879acafd0b9SEwan D. Milne 
3880fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3881fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
388238d5c833SDouglas Gilbert {
388338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
388438d5c833SDouglas Gilbert 	u8 *arr;
3885b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3886b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
388738d5c833SDouglas Gilbert 	u64 lba;
388838d5c833SDouglas Gilbert 	u32 dnum;
3889773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
389038d5c833SDouglas Gilbert 	u8 num;
389138d5c833SDouglas Gilbert 	int ret;
3892d467d31fSDouglas Gilbert 	int retval = 0;
389338d5c833SDouglas Gilbert 
3894d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
389538d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
389638d5c833SDouglas Gilbert 	if (0 == num)
389738d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38988475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
389938d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
390038d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
390138d5c833SDouglas Gilbert 		return check_condition_result;
390238d5c833SDouglas Gilbert 	}
39038475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
39048475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
390538d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
390638d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
390738d5c833SDouglas Gilbert 			    "to DIF device\n");
39089447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
39099447b6ceSMartin K. Petersen 	if (ret)
39109447b6ceSMartin K. Petersen 		return ret;
3911d467d31fSDouglas Gilbert 	dnum = 2 * num;
39126396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3913d467d31fSDouglas Gilbert 	if (NULL == arr) {
3914d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3915d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3916d467d31fSDouglas Gilbert 		return check_condition_result;
3917d467d31fSDouglas Gilbert 	}
391838d5c833SDouglas Gilbert 
391967da413fSDouglas Gilbert 	write_lock(macc_lckp);
392038d5c833SDouglas Gilbert 
392187c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
392238d5c833SDouglas Gilbert 	if (ret == -1) {
3923d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3924d467d31fSDouglas Gilbert 		goto cleanup;
3925773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
392638d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
392738d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
392838d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3929c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
393038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3931d467d31fSDouglas Gilbert 		retval = check_condition_result;
3932d467d31fSDouglas Gilbert 		goto cleanup;
393338d5c833SDouglas Gilbert 	}
393438d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
393587c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3936d467d31fSDouglas Gilbert cleanup:
393767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3938d467d31fSDouglas Gilbert 	kfree(arr);
3939d467d31fSDouglas Gilbert 	return retval;
394038d5c833SDouglas Gilbert }
394138d5c833SDouglas Gilbert 
394244d92694SMartin K. Petersen struct unmap_block_desc {
394344d92694SMartin K. Petersen 	__be64	lba;
394444d92694SMartin K. Petersen 	__be32	blocks;
394544d92694SMartin K. Petersen 	__be32	__reserved;
394644d92694SMartin K. Petersen };
394744d92694SMartin K. Petersen 
3948fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
394944d92694SMartin K. Petersen {
395044d92694SMartin K. Petersen 	unsigned char *buf;
395144d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
3952b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3953b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
395444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
395544d92694SMartin K. Petersen 	int ret;
395644d92694SMartin K. Petersen 
3957c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3958c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3959c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3960c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
396144d92694SMartin K. Petersen 
396244d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3963773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3964c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
396544d92694SMartin K. Petersen 		return check_condition_result;
3966c2248fc9SDouglas Gilbert 	}
396744d92694SMartin K. Petersen 
3968b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3969c2248fc9SDouglas Gilbert 	if (!buf) {
3970c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3971c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3972c2248fc9SDouglas Gilbert 		return check_condition_result;
3973c2248fc9SDouglas Gilbert 	}
3974c2248fc9SDouglas Gilbert 
3975c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
397644d92694SMartin K. Petersen 
397744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
397844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
397944d92694SMartin K. Petersen 
398044d92694SMartin K. Petersen 	desc = (void *)&buf[8];
398144d92694SMartin K. Petersen 
398267da413fSDouglas Gilbert 	write_lock(macc_lckp);
39836c78cc06SAkinobu Mita 
398444d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
398544d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
398644d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
398744d92694SMartin K. Petersen 
39889447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
398944d92694SMartin K. Petersen 		if (ret)
399044d92694SMartin K. Petersen 			goto out;
399144d92694SMartin K. Petersen 
399287c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
399344d92694SMartin K. Petersen 	}
399444d92694SMartin K. Petersen 
399544d92694SMartin K. Petersen 	ret = 0;
399644d92694SMartin K. Petersen 
399744d92694SMartin K. Petersen out:
399867da413fSDouglas Gilbert 	write_unlock(macc_lckp);
399944d92694SMartin K. Petersen 	kfree(buf);
400044d92694SMartin K. Petersen 
400144d92694SMartin K. Petersen 	return ret;
400244d92694SMartin K. Petersen }
400344d92694SMartin K. Petersen 
400444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
400544d92694SMartin K. Petersen 
4006fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4007fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
400844d92694SMartin K. Petersen {
4009c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4010c2248fc9SDouglas Gilbert 	u64 lba;
4011c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
401244d92694SMartin K. Petersen 	int ret;
401387c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
401444d92694SMartin K. Petersen 
4015c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4016c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
401744d92694SMartin K. Petersen 
401844d92694SMartin K. Petersen 	if (alloc_len < 24)
401944d92694SMartin K. Petersen 		return 0;
402044d92694SMartin K. Petersen 
40219447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
402244d92694SMartin K. Petersen 	if (ret)
402344d92694SMartin K. Petersen 		return ret;
402444d92694SMartin K. Petersen 
4025b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4026b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4027b6ff8ca7SDouglas Gilbert 
402887c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4029b6ff8ca7SDouglas Gilbert 	} else {
4030c2248fc9SDouglas Gilbert 		mapped = 1;
4031c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4032c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4033c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4034c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4035c2248fc9SDouglas Gilbert 		else
4036c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4037c2248fc9SDouglas Gilbert 	}
403844d92694SMartin K. Petersen 
403944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4040c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4041c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4042c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4043c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
404444d92694SMartin K. Petersen 
4045c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
404644d92694SMartin K. Petersen }
404744d92694SMartin K. Petersen 
404880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
404980c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
405080c49563SDouglas Gilbert {
40514f2c8bf6SDouglas Gilbert 	int res = 0;
405280c49563SDouglas Gilbert 	u64 lba;
405380c49563SDouglas Gilbert 	u32 num_blocks;
405480c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
405580c49563SDouglas Gilbert 
405680c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
405780c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
405880c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
405980c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
406080c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
406180c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
406280c49563SDouglas Gilbert 	}
406380c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
406480c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
406580c49563SDouglas Gilbert 		return check_condition_result;
406680c49563SDouglas Gilbert 	}
4067fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
40684f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40694f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40704f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40714f2c8bf6SDouglas Gilbert 	return res;
407280c49563SDouglas Gilbert }
407380c49563SDouglas Gilbert 
4074ed9f3e25SDouglas Gilbert /*
4075ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4076ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4077ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4078ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4079ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4080ed9f3e25SDouglas Gilbert  */
4081ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4082ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4083ed9f3e25SDouglas Gilbert {
4084ed9f3e25SDouglas Gilbert 	int res = 0;
4085ed9f3e25SDouglas Gilbert 	u64 lba;
4086ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4087ed9f3e25SDouglas Gilbert 	u32 nblks;
4088ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4089b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4090b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4091b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4092ed9f3e25SDouglas Gilbert 
4093ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4094ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4095ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4096ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4097ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4098ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4099ed9f3e25SDouglas Gilbert 	}
4100ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4101ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4102ed9f3e25SDouglas Gilbert 		return check_condition_result;
4103ed9f3e25SDouglas Gilbert 	}
4104ed9f3e25SDouglas Gilbert 	if (!fsp)
4105ed9f3e25SDouglas Gilbert 		goto fini;
4106ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4107ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4108ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4109ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4110ed9f3e25SDouglas Gilbert 
4111ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4112ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4113ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4114ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4115ed9f3e25SDouglas Gilbert 	if (rest)
4116ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4117ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4118ed9f3e25SDouglas Gilbert fini:
4119ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4120ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4121ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4122ed9f3e25SDouglas Gilbert }
4123ed9f3e25SDouglas Gilbert 
4124fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4125fb0cc8d1SDouglas Gilbert 
41268d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
41278d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
41288d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
41298d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41308d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
41318d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
41328d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
41338d039e22SDouglas Gilbert  */
41341da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
41351da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
41361da177e4SLinus Torvalds {
413701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
41388d039e22SDouglas Gilbert 	unsigned int alloc_len;
41398d039e22SDouglas Gilbert 	unsigned char select_report;
41408d039e22SDouglas Gilbert 	u64 lun;
41418d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4142fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41438d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41448d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
41458d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
41468d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4147fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4148fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4149fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41501da177e4SLinus Torvalds 
415119c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41528d039e22SDouglas Gilbert 
41538d039e22SDouglas Gilbert 	select_report = cmd[2];
41548d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41558d039e22SDouglas Gilbert 
41568d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41578d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41588d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41591da177e4SLinus Torvalds 		return check_condition_result;
41601da177e4SLinus Torvalds 	}
41618d039e22SDouglas Gilbert 
41628d039e22SDouglas Gilbert 	switch (select_report) {
41638d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4164773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41658d039e22SDouglas Gilbert 		wlun_cnt = 0;
41668d039e22SDouglas Gilbert 		break;
41678d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4168c65b1445SDouglas Gilbert 		lun_cnt = 0;
41698d039e22SDouglas Gilbert 		wlun_cnt = 1;
41708d039e22SDouglas Gilbert 		break;
41718d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41728d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41738d039e22SDouglas Gilbert 		wlun_cnt = 1;
41748d039e22SDouglas Gilbert 		break;
41758d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41768d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41778d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41788d039e22SDouglas Gilbert 	default:
41798d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41808d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41818d039e22SDouglas Gilbert 		return check_condition_result;
41828d039e22SDouglas Gilbert 	}
41838d039e22SDouglas Gilbert 
41848d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4185c65b1445SDouglas Gilbert 		--lun_cnt;
41868d039e22SDouglas Gilbert 
41878d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4188fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4189fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41908d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41918d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41928d039e22SDouglas Gilbert 
4193fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41948d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4195fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4196fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4197fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4198fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4199fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4200fb0cc8d1SDouglas Gilbert 			++lun_p;
4201fb0cc8d1SDouglas Gilbert 			j = 1;
4202fb0cc8d1SDouglas Gilbert 		}
4203fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4204fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4205fb0cc8d1SDouglas Gilbert 				break;
4206fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4207ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4208ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4209fb0cc8d1SDouglas Gilbert 		}
4210fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4211fb0cc8d1SDouglas Gilbert 			break;
4212fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4213fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4214fb0cc8d1SDouglas Gilbert 		if (res)
4215fb0cc8d1SDouglas Gilbert 			return res;
4216fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4217fb0cc8d1SDouglas Gilbert 	}
4218fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4219fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4220fb0cc8d1SDouglas Gilbert 		++j;
4221fb0cc8d1SDouglas Gilbert 	}
4222fb0cc8d1SDouglas Gilbert 	if (j > 0)
4223fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
42248d039e22SDouglas Gilbert 	return res;
42251da177e4SLinus Torvalds }
42261da177e4SLinus Torvalds 
4227c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4228c3e2fe92SDouglas Gilbert {
4229c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4230c3e2fe92SDouglas Gilbert 	u8 bytchk;
4231c3e2fe92SDouglas Gilbert 	int ret, j;
4232c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4233c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4234c3e2fe92SDouglas Gilbert 	u64 lba;
4235c3e2fe92SDouglas Gilbert 	u8 *arr;
4236c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4237b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4238b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4239c3e2fe92SDouglas Gilbert 
4240c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4241c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4242c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4243c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4244c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4245c3e2fe92SDouglas Gilbert 		return check_condition_result;
4246c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4247c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4248c3e2fe92SDouglas Gilbert 	}
4249c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4250c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4251c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4252c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4253c3e2fe92SDouglas Gilbert 		break;
4254c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4255c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4256c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4257c3e2fe92SDouglas Gilbert 		break;
4258c3e2fe92SDouglas Gilbert 	default:
4259c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4260c3e2fe92SDouglas Gilbert 		return check_condition_result;
4261c3e2fe92SDouglas Gilbert 	}
4262*3344b58bSGeorge Kennedy 	if (vnum == 0)
4263*3344b58bSGeorge Kennedy 		return 0;	/* not an error */
4264c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4265c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4266c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4267c3e2fe92SDouglas Gilbert 	if (ret)
4268c3e2fe92SDouglas Gilbert 		return ret;
4269c3e2fe92SDouglas Gilbert 
4270c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4271c3e2fe92SDouglas Gilbert 	if (!arr) {
4272c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4273c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4274c3e2fe92SDouglas Gilbert 		return check_condition_result;
4275c3e2fe92SDouglas Gilbert 	}
4276c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
427767da413fSDouglas Gilbert 	read_lock(macc_lckp);
4278c3e2fe92SDouglas Gilbert 
4279c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4280c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4281c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4282c3e2fe92SDouglas Gilbert 		goto cleanup;
4283c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4284c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4285c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4286c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4287c3e2fe92SDouglas Gilbert 	}
4288c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4289c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4290c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4291c3e2fe92SDouglas Gilbert 	}
4292c3e2fe92SDouglas Gilbert 	ret = 0;
4293c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4294c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4295c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4296c3e2fe92SDouglas Gilbert 		goto cleanup;
4297c3e2fe92SDouglas Gilbert 	}
4298c3e2fe92SDouglas Gilbert cleanup:
429967da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4300c3e2fe92SDouglas Gilbert 	kfree(arr);
4301c3e2fe92SDouglas Gilbert 	return ret;
4302c3e2fe92SDouglas Gilbert }
4303c3e2fe92SDouglas Gilbert 
4304f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4305f0d1cf93SDouglas Gilbert 
4306f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4307f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4308f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4309f0d1cf93SDouglas Gilbert {
4310f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4311f0d1cf93SDouglas Gilbert 	int ret = 0;
4312f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4313f0d1cf93SDouglas Gilbert 	bool partial;
4314f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4315f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4316f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4317f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4318b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4319f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4320f0d1cf93SDouglas Gilbert 
4321f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4322f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4323f0d1cf93SDouglas Gilbert 		return check_condition_result;
4324f0d1cf93SDouglas Gilbert 	}
4325f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4326f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4327*3344b58bSGeorge Kennedy 	if (alloc_len == 0)
4328*3344b58bSGeorge Kennedy 		return 0;	/* not an error */
4329f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4330f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4331f0d1cf93SDouglas Gilbert 
4332f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4333f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4334f0d1cf93SDouglas Gilbert 		return check_condition_result;
4335f0d1cf93SDouglas Gilbert 	}
4336f0d1cf93SDouglas Gilbert 
4337108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4338f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4339f0d1cf93SDouglas Gilbert 			    max_zones);
4340f0d1cf93SDouglas Gilbert 
4341f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4342f0d1cf93SDouglas Gilbert 	if (!arr) {
4343f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4344f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4345f0d1cf93SDouglas Gilbert 		return check_condition_result;
4346f0d1cf93SDouglas Gilbert 	}
4347f0d1cf93SDouglas Gilbert 
4348f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4349f0d1cf93SDouglas Gilbert 
4350f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4351f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4352f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4353f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4354f0d1cf93SDouglas Gilbert 			break;
4355f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4356f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4357f0d1cf93SDouglas Gilbert 		case 0x00:
4358f0d1cf93SDouglas Gilbert 			/* All zones */
4359f0d1cf93SDouglas Gilbert 			break;
4360f0d1cf93SDouglas Gilbert 		case 0x01:
4361f0d1cf93SDouglas Gilbert 			/* Empty zones */
4362f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4363f0d1cf93SDouglas Gilbert 				continue;
4364f0d1cf93SDouglas Gilbert 			break;
4365f0d1cf93SDouglas Gilbert 		case 0x02:
4366f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4367f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4368f0d1cf93SDouglas Gilbert 				continue;
4369f0d1cf93SDouglas Gilbert 			break;
4370f0d1cf93SDouglas Gilbert 		case 0x03:
4371f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4372f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4373f0d1cf93SDouglas Gilbert 				continue;
4374f0d1cf93SDouglas Gilbert 			break;
4375f0d1cf93SDouglas Gilbert 		case 0x04:
4376f0d1cf93SDouglas Gilbert 			/* Closed zones */
4377f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4378f0d1cf93SDouglas Gilbert 				continue;
4379f0d1cf93SDouglas Gilbert 			break;
4380f0d1cf93SDouglas Gilbert 		case 0x05:
4381f0d1cf93SDouglas Gilbert 			/* Full zones */
4382f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4383f0d1cf93SDouglas Gilbert 				continue;
4384f0d1cf93SDouglas Gilbert 			break;
4385f0d1cf93SDouglas Gilbert 		case 0x06:
4386f0d1cf93SDouglas Gilbert 		case 0x07:
4387f0d1cf93SDouglas Gilbert 		case 0x10:
4388f0d1cf93SDouglas Gilbert 			/*
438964e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
439064e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4391f0d1cf93SDouglas Gilbert 			 */
4392f0d1cf93SDouglas Gilbert 			continue;
439364e14eceSDamien Le Moal 		case 0x11:
439464e14eceSDamien Le Moal 			/* non-seq-resource set */
439564e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
439664e14eceSDamien Le Moal 				continue;
439764e14eceSDamien Le Moal 			break;
4398f0d1cf93SDouglas Gilbert 		case 0x3f:
4399f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4400f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4401f0d1cf93SDouglas Gilbert 				continue;
4402f0d1cf93SDouglas Gilbert 			break;
4403f0d1cf93SDouglas Gilbert 		default:
4404f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4405f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4406f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4407f0d1cf93SDouglas Gilbert 			goto fini;
4408f0d1cf93SDouglas Gilbert 		}
4409f0d1cf93SDouglas Gilbert 
4410f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4411f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
441264e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4413f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
441464e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
441564e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4416f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4417f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4418f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4419f0d1cf93SDouglas Gilbert 			desc += 64;
4420f0d1cf93SDouglas Gilbert 		}
4421f0d1cf93SDouglas Gilbert 
4422f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4423f0d1cf93SDouglas Gilbert 			break;
4424f0d1cf93SDouglas Gilbert 
4425f0d1cf93SDouglas Gilbert 		nrz++;
4426f0d1cf93SDouglas Gilbert 	}
4427f0d1cf93SDouglas Gilbert 
4428f0d1cf93SDouglas Gilbert 	/* Report header */
4429f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4430f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4431f0d1cf93SDouglas Gilbert 
4432f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4433f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4434f0d1cf93SDouglas Gilbert 
4435f0d1cf93SDouglas Gilbert fini:
4436f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4437f0d1cf93SDouglas Gilbert 	kfree(arr);
4438f0d1cf93SDouglas Gilbert 	return ret;
4439f0d1cf93SDouglas Gilbert }
4440f0d1cf93SDouglas Gilbert 
4441f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4442f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4443f0d1cf93SDouglas Gilbert {
4444f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4445f0d1cf93SDouglas Gilbert 	unsigned int i;
4446f0d1cf93SDouglas Gilbert 
4447f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4448f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4449f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4450f0d1cf93SDouglas Gilbert 	}
4451f0d1cf93SDouglas Gilbert }
4452f0d1cf93SDouglas Gilbert 
4453f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4454f0d1cf93SDouglas Gilbert {
4455f0d1cf93SDouglas Gilbert 	int res = 0;
4456f0d1cf93SDouglas Gilbert 	u64 z_id;
4457f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4458f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4459f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4460f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4461b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4462f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4463f0d1cf93SDouglas Gilbert 
4464f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4465f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4466f0d1cf93SDouglas Gilbert 		return check_condition_result;
4467f0d1cf93SDouglas Gilbert 	}
4468f0d1cf93SDouglas Gilbert 
4469f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4470f0d1cf93SDouglas Gilbert 
4471f0d1cf93SDouglas Gilbert 	if (all) {
4472f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4473f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4474f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4475f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4476f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4477f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4478f0d1cf93SDouglas Gilbert 			goto fini;
4479f0d1cf93SDouglas Gilbert 		}
4480f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4481f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4482f0d1cf93SDouglas Gilbert 		goto fini;
4483f0d1cf93SDouglas Gilbert 	}
4484f0d1cf93SDouglas Gilbert 
4485f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4486f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4487f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4488f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4489f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4490f0d1cf93SDouglas Gilbert 		goto fini;
4491f0d1cf93SDouglas Gilbert 	}
4492f0d1cf93SDouglas Gilbert 
4493f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4494f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4495f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4496f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4497f0d1cf93SDouglas Gilbert 		goto fini;
4498f0d1cf93SDouglas Gilbert 	}
4499f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4500f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4501f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4502f0d1cf93SDouglas Gilbert 		goto fini;
4503f0d1cf93SDouglas Gilbert 	}
4504f0d1cf93SDouglas Gilbert 
4505f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4506f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4507f0d1cf93SDouglas Gilbert 		goto fini;
4508f0d1cf93SDouglas Gilbert 
4509f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4510f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4511f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4512f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4513f0d1cf93SDouglas Gilbert 		goto fini;
4514f0d1cf93SDouglas Gilbert 	}
4515f0d1cf93SDouglas Gilbert 
4516f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4517f0d1cf93SDouglas Gilbert fini:
4518f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4519f0d1cf93SDouglas Gilbert 	return res;
4520f0d1cf93SDouglas Gilbert }
4521f0d1cf93SDouglas Gilbert 
4522f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4523f0d1cf93SDouglas Gilbert {
4524f0d1cf93SDouglas Gilbert 	unsigned int i;
4525f0d1cf93SDouglas Gilbert 
4526f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4527f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4528f0d1cf93SDouglas Gilbert }
4529f0d1cf93SDouglas Gilbert 
4530f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4531f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4532f0d1cf93SDouglas Gilbert {
4533f0d1cf93SDouglas Gilbert 	int res = 0;
4534f0d1cf93SDouglas Gilbert 	u64 z_id;
4535f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4536f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4537f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4538b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4539f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4540f0d1cf93SDouglas Gilbert 
4541f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4542f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4543f0d1cf93SDouglas Gilbert 		return check_condition_result;
4544f0d1cf93SDouglas Gilbert 	}
4545f0d1cf93SDouglas Gilbert 
4546f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4547f0d1cf93SDouglas Gilbert 
4548f0d1cf93SDouglas Gilbert 	if (all) {
4549f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4550f0d1cf93SDouglas Gilbert 		goto fini;
4551f0d1cf93SDouglas Gilbert 	}
4552f0d1cf93SDouglas Gilbert 
4553f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4554f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4555f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4556f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4557f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4558f0d1cf93SDouglas Gilbert 		goto fini;
4559f0d1cf93SDouglas Gilbert 	}
4560f0d1cf93SDouglas Gilbert 
4561f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4562f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4563f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4564f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4565f0d1cf93SDouglas Gilbert 		goto fini;
4566f0d1cf93SDouglas Gilbert 	}
4567f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4568f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4569f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4570f0d1cf93SDouglas Gilbert 		goto fini;
4571f0d1cf93SDouglas Gilbert 	}
4572f0d1cf93SDouglas Gilbert 
4573f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4574f0d1cf93SDouglas Gilbert fini:
4575f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4576f0d1cf93SDouglas Gilbert 	return res;
4577f0d1cf93SDouglas Gilbert }
4578f0d1cf93SDouglas Gilbert 
4579f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4580f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4581f0d1cf93SDouglas Gilbert {
4582f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4583f0d1cf93SDouglas Gilbert 
4584f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4585f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4586f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4587f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4588f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4589f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4590f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4591f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4592f0d1cf93SDouglas Gilbert 	}
4593f0d1cf93SDouglas Gilbert }
4594f0d1cf93SDouglas Gilbert 
4595f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4596f0d1cf93SDouglas Gilbert {
4597f0d1cf93SDouglas Gilbert 	unsigned int i;
4598f0d1cf93SDouglas Gilbert 
4599f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4600f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4601f0d1cf93SDouglas Gilbert }
4602f0d1cf93SDouglas Gilbert 
4603f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4604f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4605f0d1cf93SDouglas Gilbert {
4606f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4607f0d1cf93SDouglas Gilbert 	int res = 0;
4608f0d1cf93SDouglas Gilbert 	u64 z_id;
4609f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4610f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4611b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4612f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4613f0d1cf93SDouglas Gilbert 
4614f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4615f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4616f0d1cf93SDouglas Gilbert 		return check_condition_result;
4617f0d1cf93SDouglas Gilbert 	}
4618f0d1cf93SDouglas Gilbert 
4619f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4620f0d1cf93SDouglas Gilbert 
4621f0d1cf93SDouglas Gilbert 	if (all) {
4622f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4623f0d1cf93SDouglas Gilbert 		goto fini;
4624f0d1cf93SDouglas Gilbert 	}
4625f0d1cf93SDouglas Gilbert 
4626f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4627f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4628f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4629f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4630f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4631f0d1cf93SDouglas Gilbert 		goto fini;
4632f0d1cf93SDouglas Gilbert 	}
4633f0d1cf93SDouglas Gilbert 
4634f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4635f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4636f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4637f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4638f0d1cf93SDouglas Gilbert 		goto fini;
4639f0d1cf93SDouglas Gilbert 	}
4640f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4641f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4642f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4643f0d1cf93SDouglas Gilbert 		goto fini;
4644f0d1cf93SDouglas Gilbert 	}
4645f0d1cf93SDouglas Gilbert 
4646f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4647f0d1cf93SDouglas Gilbert fini:
4648f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4649f0d1cf93SDouglas Gilbert 	return res;
4650f0d1cf93SDouglas Gilbert }
4651f0d1cf93SDouglas Gilbert 
4652f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4653f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4654f0d1cf93SDouglas Gilbert {
4655f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4656f0d1cf93SDouglas Gilbert 
4657f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4658f0d1cf93SDouglas Gilbert 		return;
4659f0d1cf93SDouglas Gilbert 
4660f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4661f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4662f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4663f0d1cf93SDouglas Gilbert 
4664f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4665f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4666f0d1cf93SDouglas Gilbert 
466764e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4668f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4669f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4670f0d1cf93SDouglas Gilbert }
4671f0d1cf93SDouglas Gilbert 
4672f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4673f0d1cf93SDouglas Gilbert {
4674f0d1cf93SDouglas Gilbert 	unsigned int i;
4675f0d1cf93SDouglas Gilbert 
4676f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4677f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4678f0d1cf93SDouglas Gilbert }
4679f0d1cf93SDouglas Gilbert 
4680f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4681f0d1cf93SDouglas Gilbert {
4682f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4683f0d1cf93SDouglas Gilbert 	int res = 0;
4684f0d1cf93SDouglas Gilbert 	u64 z_id;
4685f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4686f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4687b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4688f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4689f0d1cf93SDouglas Gilbert 
4690f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4691f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4692f0d1cf93SDouglas Gilbert 		return check_condition_result;
4693f0d1cf93SDouglas Gilbert 	}
4694f0d1cf93SDouglas Gilbert 
4695f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4696f0d1cf93SDouglas Gilbert 
4697f0d1cf93SDouglas Gilbert 	if (all) {
4698f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4699f0d1cf93SDouglas Gilbert 		goto fini;
4700f0d1cf93SDouglas Gilbert 	}
4701f0d1cf93SDouglas Gilbert 
4702f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4703f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4704f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4705f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4706f0d1cf93SDouglas Gilbert 		goto fini;
4707f0d1cf93SDouglas Gilbert 	}
4708f0d1cf93SDouglas Gilbert 
4709f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4710f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4711f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4712f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4713f0d1cf93SDouglas Gilbert 		goto fini;
4714f0d1cf93SDouglas Gilbert 	}
4715f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4716f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4717f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4718f0d1cf93SDouglas Gilbert 		goto fini;
4719f0d1cf93SDouglas Gilbert 	}
4720f0d1cf93SDouglas Gilbert 
4721f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4722f0d1cf93SDouglas Gilbert fini:
4723f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4724f0d1cf93SDouglas Gilbert 	return res;
4725f0d1cf93SDouglas Gilbert }
4726f0d1cf93SDouglas Gilbert 
4727c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4728c4837394SDouglas Gilbert {
4729c10fa55fSJohn Garry 	u16 hwq;
4730a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4731c10fa55fSJohn Garry 
4732c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4733c4837394SDouglas Gilbert 
4734458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4735458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4736458df78bSBart Van Assche 		hwq = 0;
4737f7c4cdc7SJohn Garry 
4738458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4739c4837394SDouglas Gilbert }
4740c4837394SDouglas Gilbert 
4741c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4742c10fa55fSJohn Garry {
4743a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4744c10fa55fSJohn Garry }
4745c10fa55fSJohn Garry 
4746c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4747fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47481da177e4SLinus Torvalds {
47497382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4750c4837394SDouglas Gilbert 	int qc_idx;
4751cbf67842SDouglas Gilbert 	int retiring = 0;
47521da177e4SLinus Torvalds 	unsigned long iflags;
4753c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4754cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4755cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4756cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47571da177e4SLinus Torvalds 
47587382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47597382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4760c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4761c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4762c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4763cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4764c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4765c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4766c4837394SDouglas Gilbert 	}
4767c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4768c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47691da177e4SLinus Torvalds 		return;
47701da177e4SLinus Torvalds 	}
4771c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
47724a0c6f43SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
4773c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4774cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4775b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4776c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4777c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4778c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
47791da177e4SLinus Torvalds 		return;
47801da177e4SLinus Torvalds 	}
4781cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4782f46eb0e9SDouglas Gilbert 	if (likely(devip))
4783cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4784cbf67842SDouglas Gilbert 	else
4785c1287970STomas Winkler 		pr_err("devip=NULL\n");
4786f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4787cbf67842SDouglas Gilbert 		retiring = 1;
4788cbf67842SDouglas Gilbert 
4789cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4790c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4791c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4792c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4793cbf67842SDouglas Gilbert 		return;
47941da177e4SLinus Torvalds 	}
47951da177e4SLinus Torvalds 
4796cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4797cbf67842SDouglas Gilbert 		int k, retval;
4798cbf67842SDouglas Gilbert 
4799cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4800c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4801c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4802c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4803cbf67842SDouglas Gilbert 			return;
4804cbf67842SDouglas Gilbert 		}
4805c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4806773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4807cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4808cbf67842SDouglas Gilbert 		else
4809cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4810cbf67842SDouglas Gilbert 	}
4811c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
48127382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
48137382f9d8SDouglas Gilbert 		if (sdebug_verbose)
48147382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
48157382f9d8SDouglas Gilbert 		return;
48167382f9d8SDouglas Gilbert 	}
48176c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
4818cbf67842SDouglas Gilbert }
4819cbf67842SDouglas Gilbert 
4820cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4821fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4822cbf67842SDouglas Gilbert {
4823a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4824a10bc12aSDouglas Gilbert 						  hrt);
4825a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4826cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4827cbf67842SDouglas Gilbert }
48281da177e4SLinus Torvalds 
4829a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4830fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4831a10bc12aSDouglas Gilbert {
4832a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4833a10bc12aSDouglas Gilbert 						  ew.work);
4834a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4835a10bc12aSDouglas Gilbert }
4836a10bc12aSDouglas Gilbert 
483709ba24c1SDouglas Gilbert static bool got_shared_uuid;
4838bf476433SChristoph Hellwig static uuid_t shared_uuid;
483909ba24c1SDouglas Gilbert 
4840f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4841f0d1cf93SDouglas Gilbert {
4842f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4843f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4844f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4845f0d1cf93SDouglas Gilbert 	unsigned int i;
4846f0d1cf93SDouglas Gilbert 
4847f0d1cf93SDouglas Gilbert 	/*
484898e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
484998e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4850f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4851f0d1cf93SDouglas Gilbert 	 * created for the device.
4852f0d1cf93SDouglas Gilbert 	 */
485398e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4854f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4855f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4856f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4857f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4858f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4859f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4860f0d1cf93SDouglas Gilbert 			return -EINVAL;
4861f0d1cf93SDouglas Gilbert 		}
4862f0d1cf93SDouglas Gilbert 	} else {
4863108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4864108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4865108e36f0SDamien Le Moal 			return -EINVAL;
4866108e36f0SDamien Le Moal 		}
486798e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4868f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4869f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4870f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4871f0d1cf93SDouglas Gilbert 			return -EINVAL;
4872f0d1cf93SDouglas Gilbert 		}
4873f0d1cf93SDouglas Gilbert 	}
4874f0d1cf93SDouglas Gilbert 
4875f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4876f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4877f0d1cf93SDouglas Gilbert 
4878aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4879aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4880aa8fecf9SDamien Le Moal 		return -EINVAL;
4881aa8fecf9SDamien Le Moal 	}
4882aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4883aa8fecf9SDamien Le Moal 
488464e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
488564e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4886380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4887f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4888f0d1cf93SDouglas Gilbert 		else
4889380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
489064e14eceSDamien Le Moal 	}
4891f0d1cf93SDouglas Gilbert 
4892f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4893f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4894f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4895f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4896f0d1cf93SDouglas Gilbert 
4897f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4898f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4899f0d1cf93SDouglas Gilbert 
4900f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4901f0d1cf93SDouglas Gilbert 
4902aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
490364e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4904f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4905f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4906f0d1cf93SDouglas Gilbert 		} else {
490764e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
490864e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
490964e14eceSDamien Le Moal 			else
491064e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4911f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4912f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4913f0d1cf93SDouglas Gilbert 		}
4914f0d1cf93SDouglas Gilbert 
4915f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4916f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4917f0d1cf93SDouglas Gilbert 		else
4918f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4919f0d1cf93SDouglas Gilbert 
4920f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4921f0d1cf93SDouglas Gilbert 	}
4922f0d1cf93SDouglas Gilbert 
4923f0d1cf93SDouglas Gilbert 	return 0;
4924f0d1cf93SDouglas Gilbert }
4925f0d1cf93SDouglas Gilbert 
4926fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4927fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
49285cb2fc06SFUJITA Tomonori {
49295cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
49305cb2fc06SFUJITA Tomonori 
49315cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
49325cb2fc06SFUJITA Tomonori 	if (devip) {
493309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4934bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
493509ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
493609ba24c1SDouglas Gilbert 			if (got_shared_uuid)
493709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
493809ba24c1SDouglas Gilbert 			else {
4939bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
494009ba24c1SDouglas Gilbert 				got_shared_uuid = true;
494109ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
494209ba24c1SDouglas Gilbert 			}
494309ba24c1SDouglas Gilbert 		}
49445cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4945f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
494664e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4947f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4948f0d1cf93SDouglas Gilbert 				kfree(devip);
4949f0d1cf93SDouglas Gilbert 				return NULL;
4950f0d1cf93SDouglas Gilbert 			}
495164e14eceSDamien Le Moal 		} else {
495264e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4953f0d1cf93SDouglas Gilbert 		}
4954f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
4955fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
4956fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
49575cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49585cb2fc06SFUJITA Tomonori 	}
49595cb2fc06SFUJITA Tomonori 	return devip;
49605cb2fc06SFUJITA Tomonori }
49615cb2fc06SFUJITA Tomonori 
4962f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49631da177e4SLinus Torvalds {
49641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49651da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4966f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49671da177e4SLinus Torvalds 
4968d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49691da177e4SLinus Torvalds 	if (!sdbg_host) {
4970c1287970STomas Winkler 		pr_err("Host info NULL\n");
49711da177e4SLinus Torvalds 		return NULL;
49721da177e4SLinus Torvalds 	}
4973ad0c7775SDouglas Gilbert 
49741da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49751da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49761da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49771da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49781da177e4SLinus Torvalds 			return devip;
49791da177e4SLinus Torvalds 		else {
49801da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49811da177e4SLinus Torvalds 				open_devip = devip;
49821da177e4SLinus Torvalds 		}
49831da177e4SLinus Torvalds 	}
49845cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49855cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49865cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4987c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49881da177e4SLinus Torvalds 			return NULL;
49891da177e4SLinus Torvalds 		}
49901da177e4SLinus Torvalds 	}
4991a75869d1SFUJITA Tomonori 
49921da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
49931da177e4SLinus Torvalds 	open_devip->target = sdev->id;
49941da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
49951da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4996cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4997cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4998c2248fc9SDouglas Gilbert 	open_devip->used = true;
49991da177e4SLinus Torvalds 	return open_devip;
50001da177e4SLinus Torvalds }
50011da177e4SLinus Torvalds 
50028dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
50031da177e4SLinus Torvalds {
5004773642d9SDouglas Gilbert 	if (sdebug_verbose)
5005c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
50068dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50078dea0d02SFUJITA Tomonori 	return 0;
50088dea0d02SFUJITA Tomonori }
50091da177e4SLinus Torvalds 
50108dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
50118dea0d02SFUJITA Tomonori {
5012f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5013f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5014a34c4e98SFUJITA Tomonori 
5015773642d9SDouglas Gilbert 	if (sdebug_verbose)
5016c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
50178dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5018b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5019b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5020b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5021f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5022b01f6f83SDouglas Gilbert 		if (devip == NULL)
50238dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5024f46eb0e9SDouglas Gilbert 	}
5025c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5026773642d9SDouglas Gilbert 	if (sdebug_no_uld)
502778d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
50289b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
50298dea0d02SFUJITA Tomonori 	return 0;
50308dea0d02SFUJITA Tomonori }
50318dea0d02SFUJITA Tomonori 
50328dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
50338dea0d02SFUJITA Tomonori {
50348dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
50358dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
50368dea0d02SFUJITA Tomonori 
5037773642d9SDouglas Gilbert 	if (sdebug_verbose)
5038c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
50398dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50408dea0d02SFUJITA Tomonori 	if (devip) {
504125985edcSLucas De Marchi 		/* make this slot available for re-use */
5042c2248fc9SDouglas Gilbert 		devip->used = false;
50438dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
50448dea0d02SFUJITA Tomonori 	}
50458dea0d02SFUJITA Tomonori }
50468dea0d02SFUJITA Tomonori 
504710bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
504810bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5049c4837394SDouglas Gilbert {
5050c4837394SDouglas Gilbert 	if (!sd_dp)
5051c4837394SDouglas Gilbert 		return;
505210bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5053c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
505410bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5055c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5056c4837394SDouglas Gilbert }
5057c4837394SDouglas Gilbert 
5058a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5059a10bc12aSDouglas Gilbert    returns false */
5060a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50618dea0d02SFUJITA Tomonori {
50628dea0d02SFUJITA Tomonori 	unsigned long iflags;
5063c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
506410bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5065c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50668dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5067cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5068a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50698dea0d02SFUJITA Tomonori 
5070c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5071c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5072773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5073cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5074cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5075cbf67842SDouglas Gilbert 			qmax = r_qmax;
5076cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5077c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5078c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5079a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5080a10bc12aSDouglas Gilbert 					continue;
5081c4837394SDouglas Gilbert 				/* found */
5082db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5083db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5084db525fceSDouglas Gilbert 				if (devip)
5085db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5086db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5087a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
508810bde980SDouglas Gilbert 				if (sd_dp) {
508910bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
509010bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
509110bde980SDouglas Gilbert 				} else
509210bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5093c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
509410bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5095c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5096a10bc12aSDouglas Gilbert 				return true;
50978dea0d02SFUJITA Tomonori 			}
5098cbf67842SDouglas Gilbert 		}
5099c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5100c4837394SDouglas Gilbert 	}
5101a10bc12aSDouglas Gilbert 	return false;
51028dea0d02SFUJITA Tomonori }
51038dea0d02SFUJITA Tomonori 
5104a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
51058dea0d02SFUJITA Tomonori static void stop_all_queued(void)
51068dea0d02SFUJITA Tomonori {
51078dea0d02SFUJITA Tomonori 	unsigned long iflags;
5108c4837394SDouglas Gilbert 	int j, k;
510910bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5110c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
51118dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5112cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5113a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
51148dea0d02SFUJITA Tomonori 
5115c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5116c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5117c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5118c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5119c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5120c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5121a10bc12aSDouglas Gilbert 					continue;
5122db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5123db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5124db525fceSDouglas Gilbert 				if (devip)
5125db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5126db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5127a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
512810bde980SDouglas Gilbert 				if (sd_dp) {
512910bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
513010bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
513110bde980SDouglas Gilbert 				} else
513210bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5133c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
513410bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5135c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5136c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
51378dea0d02SFUJITA Tomonori 			}
51388dea0d02SFUJITA Tomonori 		}
5139c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5140c4837394SDouglas Gilbert 	}
5141cbf67842SDouglas Gilbert }
5142cbf67842SDouglas Gilbert 
5143cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5144cbf67842SDouglas Gilbert static void free_all_queued(void)
5145cbf67842SDouglas Gilbert {
5146c4837394SDouglas Gilbert 	int j, k;
5147c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5148cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5149cbf67842SDouglas Gilbert 
5150c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5151c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5152c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5153a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5154a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5155cbf67842SDouglas Gilbert 		}
51561da177e4SLinus Torvalds 	}
5157c4837394SDouglas Gilbert }
51581da177e4SLinus Torvalds 
51591da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51601da177e4SLinus Torvalds {
5161a10bc12aSDouglas Gilbert 	bool ok;
5162a10bc12aSDouglas Gilbert 
51631da177e4SLinus Torvalds 	++num_aborts;
5164cbf67842SDouglas Gilbert 	if (SCpnt) {
5165a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5166a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5167a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5168a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5169a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5170cbf67842SDouglas Gilbert 	}
51711da177e4SLinus Torvalds 	return SUCCESS;
51721da177e4SLinus Torvalds }
51731da177e4SLinus Torvalds 
51741da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51751da177e4SLinus Torvalds {
51761da177e4SLinus Torvalds 	++num_dev_resets;
5177cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5178cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5179f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5180f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5181cbf67842SDouglas Gilbert 
5182773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5183cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51841da177e4SLinus Torvalds 		if (devip)
5185cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51861da177e4SLinus Torvalds 	}
51871da177e4SLinus Torvalds 	return SUCCESS;
51881da177e4SLinus Torvalds }
51891da177e4SLinus Torvalds 
5190cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5191cbf67842SDouglas Gilbert {
5192cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5193cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5194cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5195cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5196cbf67842SDouglas Gilbert 	int k = 0;
5197cbf67842SDouglas Gilbert 
5198cbf67842SDouglas Gilbert 	++num_target_resets;
5199cbf67842SDouglas Gilbert 	if (!SCpnt)
5200cbf67842SDouglas Gilbert 		goto lie;
5201cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5202cbf67842SDouglas Gilbert 	if (!sdp)
5203cbf67842SDouglas Gilbert 		goto lie;
5204773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5205cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5206cbf67842SDouglas Gilbert 	hp = sdp->host;
5207cbf67842SDouglas Gilbert 	if (!hp)
5208cbf67842SDouglas Gilbert 		goto lie;
5209cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5210cbf67842SDouglas Gilbert 	if (sdbg_host) {
5211cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5212cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5213cbf67842SDouglas Gilbert 				    dev_list)
5214cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5215cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5216cbf67842SDouglas Gilbert 				++k;
5217cbf67842SDouglas Gilbert 			}
5218cbf67842SDouglas Gilbert 	}
5219773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5220cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5221cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5222cbf67842SDouglas Gilbert lie:
5223cbf67842SDouglas Gilbert 	return SUCCESS;
5224cbf67842SDouglas Gilbert }
5225cbf67842SDouglas Gilbert 
52261da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
52271da177e4SLinus Torvalds {
52281da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5229cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
52301da177e4SLinus Torvalds 	struct scsi_device *sdp;
52311da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5232cbf67842SDouglas Gilbert 	int k = 0;
52331da177e4SLinus Torvalds 
52341da177e4SLinus Torvalds 	++num_bus_resets;
5235cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5236cbf67842SDouglas Gilbert 		goto lie;
5237cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5238773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5239cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5240cbf67842SDouglas Gilbert 	hp = sdp->host;
5241cbf67842SDouglas Gilbert 	if (hp) {
5242d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52431da177e4SLinus Torvalds 		if (sdbg_host) {
5244cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
52451da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5246cbf67842SDouglas Gilbert 					    dev_list) {
5247cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5248cbf67842SDouglas Gilbert 				++k;
52491da177e4SLinus Torvalds 			}
52501da177e4SLinus Torvalds 		}
5251cbf67842SDouglas Gilbert 	}
5252773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5253cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5254cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5255cbf67842SDouglas Gilbert lie:
52561da177e4SLinus Torvalds 	return SUCCESS;
52571da177e4SLinus Torvalds }
52581da177e4SLinus Torvalds 
52591da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52601da177e4SLinus Torvalds {
52611da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5262cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5263cbf67842SDouglas Gilbert 	int k = 0;
52641da177e4SLinus Torvalds 
52651da177e4SLinus Torvalds 	++num_host_resets;
5266773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5267cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52681da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52691da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5270cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5271cbf67842SDouglas Gilbert 				    dev_list) {
5272cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5273cbf67842SDouglas Gilbert 			++k;
5274cbf67842SDouglas Gilbert 		}
52751da177e4SLinus Torvalds 	}
52761da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52771da177e4SLinus Torvalds 	stop_all_queued();
5278773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5279cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5280cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
52811da177e4SLinus Torvalds 	return SUCCESS;
52821da177e4SLinus Torvalds }
52831da177e4SLinus Torvalds 
528487c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52851da177e4SLinus Torvalds {
52861442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5287979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
52881da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
52891da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
52901da177e4SLinus Torvalds 
52911da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5292773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
52931da177e4SLinus Torvalds 		return;
5294773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5295773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5296c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
52971da177e4SLinus Torvalds 	}
52988c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
52991da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5300773642d9SDouglas Gilbert 			   / sdebug_num_parts;
53011da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
53021da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5303979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5304979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
53051da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
53061da177e4SLinus Torvalds 			    * heads_by_sects;
5307979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5308979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5309979e0dc3SJohn Pittman 	}
5310773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5311773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
53121da177e4SLinus Torvalds 
53131da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
53141da177e4SLinus Torvalds 	ramp[511] = 0xAA;
53151442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
53161da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
53171da177e4SLinus Torvalds 		start_sec = starts[k];
5318979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
53191da177e4SLinus Torvalds 		pp->boot_ind = 0;
53201da177e4SLinus Torvalds 
53211da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
53221da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
53231da177e4SLinus Torvalds 			   / sdebug_sectors_per;
53241da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
53251da177e4SLinus Torvalds 
53261da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
53271da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
53281da177e4SLinus Torvalds 			       / sdebug_sectors_per;
53291da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
53301da177e4SLinus Torvalds 
5331150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5332150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
53331da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
53341da177e4SLinus Torvalds 	}
53351da177e4SLinus Torvalds }
53361da177e4SLinus Torvalds 
5337c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5338c4837394SDouglas Gilbert {
5339c4837394SDouglas Gilbert 	int j;
5340c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5341c4837394SDouglas Gilbert 
5342c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5343c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5344c4837394SDouglas Gilbert }
5345c4837394SDouglas Gilbert 
5346c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5347c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5348c4837394SDouglas Gilbert  */
5349c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5350c4837394SDouglas Gilbert {
5351c4837394SDouglas Gilbert 	int count, modulo;
5352c4837394SDouglas Gilbert 
5353c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5354c4837394SDouglas Gilbert 	if (modulo < 2)
5355c4837394SDouglas Gilbert 		return;
5356c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5357c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5358c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5359c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5360c4837394SDouglas Gilbert }
5361c4837394SDouglas Gilbert 
5362c4837394SDouglas Gilbert static void clear_queue_stats(void)
5363c4837394SDouglas Gilbert {
5364c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5365c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5366c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5367c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5368c4837394SDouglas Gilbert }
5369c4837394SDouglas Gilbert 
53703a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5371c4837394SDouglas Gilbert {
53723a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
53733a90a63dSDouglas Gilbert 		return false;
53743a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5375c4837394SDouglas Gilbert }
5376c4837394SDouglas Gilbert 
5377a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5378a2aede97SDouglas Gilbert 
5379c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5380c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5381c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5382c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5383c4837394SDouglas Gilbert  */
5384fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5385f66b8517SMartin Wilck 			 int scsi_result,
5386f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5387f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5388f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
53891da177e4SLinus Torvalds {
5390a2aede97SDouglas Gilbert 	bool new_sd_dp;
53913a90a63dSDouglas Gilbert 	bool inject = false;
5392a6e76e6fSBart Van Assche 	bool hipri = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_HIPRI;
53933a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5394a2aede97SDouglas Gilbert 	unsigned long iflags;
5395a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5396c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5397c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5398299b6c07STomas Winkler 	struct scsi_device *sdp;
5399a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
54001da177e4SLinus Torvalds 
5401b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5402b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5403f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5404f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
54051da177e4SLinus Torvalds 	}
5406299b6c07STomas Winkler 	sdp = cmnd->device;
5407299b6c07STomas Winkler 
5408cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5409cd62b7daSDouglas Gilbert 		goto respond_in_thread;
54101da177e4SLinus Torvalds 
5411c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5412c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5413c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5414c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5415c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5416c4837394SDouglas Gilbert 	}
5417cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5418cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5419f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5420cd62b7daSDouglas Gilbert 		if (scsi_result) {
5421c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5422cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5423cd62b7daSDouglas Gilbert 		} else
5424cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5425c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5426773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5427f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5428cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5429cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5430773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5431cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
54323a90a63dSDouglas Gilbert 			inject = true;
5433cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
54341da177e4SLinus Torvalds 		}
5435cbf67842SDouglas Gilbert 	}
5436cbf67842SDouglas Gilbert 
5437c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5438f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5439c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5440cd62b7daSDouglas Gilbert 		if (scsi_result)
5441cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5442773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5443cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5444773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5445cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5446cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5447773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5448cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5449cbf67842SDouglas Gilbert 						    "report: host busy"));
5450cd62b7daSDouglas Gilbert 		if (scsi_result)
5451cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5452cd62b7daSDouglas Gilbert 		else
5453cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
54541da177e4SLinus Torvalds 	}
545574595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5456cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5457c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
54581da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5459c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5460a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5461c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5462c4b57d89SKashyap Desai 
546374595c04SDouglas Gilbert 	if (!sd_dp) {
546410bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
546574595c04SDouglas Gilbert 		if (!sd_dp) {
546674595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
546774595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
546810bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
546974595c04SDouglas Gilbert 		}
5470a2aede97SDouglas Gilbert 		new_sd_dp = true;
5471a2aede97SDouglas Gilbert 	} else {
5472a2aede97SDouglas Gilbert 		new_sd_dp = false;
547310bde980SDouglas Gilbert 	}
5474f66b8517SMartin Wilck 
5475c10fa55fSJohn Garry 	/* Set the hostwide tag */
5476c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5477c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5478c10fa55fSJohn Garry 
5479771f712bSDouglas Gilbert 	if (hipri)
5480a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5481a2aede97SDouglas Gilbert 
5482a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
54833a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5484f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5485f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5486f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5487f66b8517SMartin Wilck 	}
5488f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5489f66b8517SMartin Wilck 		cmnd->result = scsi_result;
54903a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
54913a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
54923a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
54933a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
54943a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
54953a90a63dSDouglas Gilbert 		}
54963a90a63dSDouglas Gilbert 	}
5497f66b8517SMartin Wilck 
5498f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5499f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5500f66b8517SMartin Wilck 			    __func__, cmnd->result);
5501f66b8517SMartin Wilck 
550210bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5503b333a819SDouglas Gilbert 		ktime_t kt;
5504cbf67842SDouglas Gilbert 
5505b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
55060c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
55070c4bc91dSDouglas Gilbert 
55080c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
55090c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
55100c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
55110c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
55120c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
55130c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
55140c4bc91dSDouglas Gilbert 				ns <<= 12;
55150c4bc91dSDouglas Gilbert 			}
55160c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
55170c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
55180c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
55190c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5520a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5521a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5522a2aede97SDouglas Gilbert 
5523a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5524223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5525a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5526a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5527a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5528223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5529a2aede97SDouglas Gilbert 					if (new_sd_dp)
5530a2aede97SDouglas Gilbert 						kfree(sd_dp);
5531a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
55326c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5533a2aede97SDouglas Gilbert 					return 0;
5534a2aede97SDouglas Gilbert 				}
5535a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5536a2aede97SDouglas Gilbert 				kt -= d;
5537a2aede97SDouglas Gilbert 			}
55380c4bc91dSDouglas Gilbert 		}
5539771f712bSDouglas Gilbert 		if (hipri) {
55404a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
55414a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
55424a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
55434a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
55444a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
55454a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
55464a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
55474a0c6f43SDouglas Gilbert 			}
55484a0c6f43SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_POLL;
55494a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
55504a0c6f43SDouglas Gilbert 		} else {
555110bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
555210bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5553a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5554a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5555c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5556a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5557c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5558c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5559cbf67842SDouglas Gilbert 			}
556010bde980SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_HRT;
5561a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5562c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
55634a0c6f43SDouglas Gilbert 		}
55644a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
55654a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5566c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
55674a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55684a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
55694a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
5570771f712bSDouglas Gilbert 		if (hipri) {
55714a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
55724a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
55734a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
55744a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
55754a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
55764a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
55774a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
55784a0c6f43SDouglas Gilbert 			}
55794a0c6f43SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_POLL;
55804a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
55814a0c6f43SDouglas Gilbert 		} else {
558210bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
558310bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5584a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5585c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5586c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5587a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5588cbf67842SDouglas Gilbert 			}
55894a0c6f43SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_WQ;
55904a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
55914a0c6f43SDouglas Gilbert 		}
5592c4837394SDouglas Gilbert 		if (sdebug_statistics)
5593c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
55944a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
5595a6e76e6fSBart Van Assche 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5596a6e76e6fSBart Van Assche 				    scsi_cmd_to_rq(cmnd)->tag);
5597a6e76e6fSBart Van Assche 			blk_abort_request(scsi_cmd_to_rq(cmnd));
55983a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
55994a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
56007382f9d8SDouglas Gilbert 		}
5601cbf67842SDouglas Gilbert 	}
56023a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
56033a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
56043a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
56051da177e4SLinus Torvalds 	return 0;
5606cd62b7daSDouglas Gilbert 
5607cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5608f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5609f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5610f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5611cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
56126c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5613cd62b7daSDouglas Gilbert 	return 0;
56141da177e4SLinus Torvalds }
5615cbf67842SDouglas Gilbert 
561623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
561723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
561823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
561923183910SDouglas Gilbert    as it can when the corresponding attribute in the
562023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
562123183910SDouglas Gilbert  */
5622773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5623773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
56249b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5625773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5626c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5627773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5628773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5629773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5630773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5631773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5632773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5633773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5634773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5635c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5636e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5637e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5638e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5639e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
56405d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
56415d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
56425d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5643773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5644773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5645773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5646773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5647ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5648773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5649773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
56505d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
56515d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56525d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
56535d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5654773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5655773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5656773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5657773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5658773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5659773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
56605d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5661773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
566287c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
566387c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5664773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5665773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
56660c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5667773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5668773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5669773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5670c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5671773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5672c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5673c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5674fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5675773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5676773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5677773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5678773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
567909ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
56805d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5681773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
568223183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56839447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5684773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
56855b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
56869267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5687380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5688aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
568998e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56901da177e4SLinus Torvalds 
56911da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56921da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
56931da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5694b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
56951da177e4SLinus Torvalds 
56965d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56975b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56989b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56990759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5700cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5701c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
57025b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
57035b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5704c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5705beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
570623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
57075b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5708185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5709c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5710c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5711e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
57129b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
57139b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
57145d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
57155d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
57165d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
57175b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
57185b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
57195b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
57205b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5721ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5722fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5723cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5724d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
57255d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5726cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5727c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
572878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
57291da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5730c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
573132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
573286e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
57335d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
57345d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
57355d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5736fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
57371da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
57380c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5739d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5740760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5741ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5742c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5743c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5744c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5745fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
57465b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
57475b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
57486014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
57496014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
575009ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
575109ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5752c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
57535b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
57549447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
57555b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
57569267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5757380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5758aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
575998e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
57601da177e4SLinus Torvalds 
5761760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5762760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
57631da177e4SLinus Torvalds 
57641da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
57651da177e4SLinus Torvalds {
5766c4837394SDouglas Gilbert 	int k;
5767c4837394SDouglas Gilbert 
5768760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5769760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5770760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5771c4837394SDouglas Gilbert 		return sdebug_info;
5772760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5773760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5774760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5775760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
57761da177e4SLinus Torvalds 	return sdebug_info;
57771da177e4SLinus Torvalds }
57781da177e4SLinus Torvalds 
5779cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5780fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5781fd32119bSDouglas Gilbert 				 int length)
57821da177e4SLinus Torvalds {
57831da177e4SLinus Torvalds 	char arr[16];
5784c8ed555aSAl Viro 	int opts;
57851da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
57861da177e4SLinus Torvalds 
57871da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
57881da177e4SLinus Torvalds 		return -EACCES;
57891da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
57901da177e4SLinus Torvalds 	arr[minLen] = '\0';
5791c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
57921da177e4SLinus Torvalds 		return -EINVAL;
5793773642d9SDouglas Gilbert 	sdebug_opts = opts;
5794773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5795773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5796773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5797c4837394SDouglas Gilbert 		tweak_cmnd_count();
57981da177e4SLinus Torvalds 	return length;
57991da177e4SLinus Torvalds }
5800c8ed555aSAl Viro 
5801cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5802cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5803cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5804c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5805c8ed555aSAl Viro {
5806c4837394SDouglas Gilbert 	int f, j, l;
5807c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
580887c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5809cbf67842SDouglas Gilbert 
5810c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5811c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5812c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5813c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5814c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5815c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5816c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5817c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5818c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5819c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5820c4837394SDouglas Gilbert 		   num_aborts);
5821c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5822c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5823c4837394SDouglas Gilbert 		   num_host_resets);
5824c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5825c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5826458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5827458df78bSBart Van Assche 		   sdebug_statistics);
58284a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
5829c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5830c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5831c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
58324a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
58334a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
5834cbf67842SDouglas Gilbert 
5835c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5836c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5837c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5838c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5839773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5840c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5841c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5842c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5843c4837394SDouglas Gilbert 		}
5844cbf67842SDouglas Gilbert 	}
584587c715dcSDouglas Gilbert 
584687c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
584787c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
584887c715dcSDouglas Gilbert 		bool niu;
584987c715dcSDouglas Gilbert 		int idx;
585087c715dcSDouglas Gilbert 		unsigned long l_idx;
585187c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
585287c715dcSDouglas Gilbert 
585387c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
585487c715dcSDouglas Gilbert 		j = 0;
585587c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
585687c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
585787c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
585887c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
585987c715dcSDouglas Gilbert 			++j;
586087c715dcSDouglas Gilbert 		}
586187c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
586287c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
586387c715dcSDouglas Gilbert 		j = 0;
586487c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
586587c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
586687c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
586787c715dcSDouglas Gilbert 			idx = (int)l_idx;
586887c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
586987c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
587087c715dcSDouglas Gilbert 			++j;
587187c715dcSDouglas Gilbert 		}
587287c715dcSDouglas Gilbert 	}
5873c8ed555aSAl Viro 	return 0;
58741da177e4SLinus Torvalds }
58751da177e4SLinus Torvalds 
587682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
58771da177e4SLinus Torvalds {
5878c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
58791da177e4SLinus Torvalds }
5880c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5881c4837394SDouglas Gilbert  * of delay is jiffies.
5882c4837394SDouglas Gilbert  */
588382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
588482069379SAkinobu Mita 			   size_t count)
58851da177e4SLinus Torvalds {
5886c2206098SDouglas Gilbert 	int jdelay, res;
58871da177e4SLinus Torvalds 
5888b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5889cbf67842SDouglas Gilbert 		res = count;
5890c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5891c4837394SDouglas Gilbert 			int j, k;
5892c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5893cbf67842SDouglas Gilbert 
5894c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5895c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5896c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5897c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5898c4837394SDouglas Gilbert 						   sdebug_max_queue);
5899c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5900c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5901c4837394SDouglas Gilbert 					break;
5902c4837394SDouglas Gilbert 				}
5903c4837394SDouglas Gilbert 			}
5904c4837394SDouglas Gilbert 			if (res > 0) {
5905c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5906773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
59071da177e4SLinus Torvalds 			}
5908c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5909cbf67842SDouglas Gilbert 		}
5910cbf67842SDouglas Gilbert 		return res;
59111da177e4SLinus Torvalds 	}
59121da177e4SLinus Torvalds 	return -EINVAL;
59131da177e4SLinus Torvalds }
591482069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
59151da177e4SLinus Torvalds 
5916cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5917cbf67842SDouglas Gilbert {
5918773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5919cbf67842SDouglas Gilbert }
5920cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5921c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5922cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5923cbf67842SDouglas Gilbert 			    size_t count)
5924cbf67842SDouglas Gilbert {
5925c4837394SDouglas Gilbert 	int ndelay, res;
5926cbf67842SDouglas Gilbert 
5927cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5928c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5929cbf67842SDouglas Gilbert 		res = count;
5930773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5931c4837394SDouglas Gilbert 			int j, k;
5932c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5933c4837394SDouglas Gilbert 
5934c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5935c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5936c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5937c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5938c4837394SDouglas Gilbert 						   sdebug_max_queue);
5939c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5940c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5941c4837394SDouglas Gilbert 					break;
5942c4837394SDouglas Gilbert 				}
5943c4837394SDouglas Gilbert 			}
5944c4837394SDouglas Gilbert 			if (res > 0) {
5945773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5946c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5947c2206098SDouglas Gilbert 							: DEF_JDELAY;
5948cbf67842SDouglas Gilbert 			}
5949c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5950cbf67842SDouglas Gilbert 		}
5951cbf67842SDouglas Gilbert 		return res;
5952cbf67842SDouglas Gilbert 	}
5953cbf67842SDouglas Gilbert 	return -EINVAL;
5954cbf67842SDouglas Gilbert }
5955cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5956cbf67842SDouglas Gilbert 
595782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
59581da177e4SLinus Torvalds {
5959773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
59601da177e4SLinus Torvalds }
59611da177e4SLinus Torvalds 
596282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
596382069379SAkinobu Mita 			  size_t count)
59641da177e4SLinus Torvalds {
59651da177e4SLinus Torvalds 	int opts;
59661da177e4SLinus Torvalds 	char work[20];
59671da177e4SLinus Torvalds 
59689a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
59699a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
59709a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
59711da177e4SLinus Torvalds 				goto opts_done;
59721da177e4SLinus Torvalds 		} else {
59739a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
59741da177e4SLinus Torvalds 				goto opts_done;
59751da177e4SLinus Torvalds 		}
59761da177e4SLinus Torvalds 	}
59771da177e4SLinus Torvalds 	return -EINVAL;
59781da177e4SLinus Torvalds opts_done:
5979773642d9SDouglas Gilbert 	sdebug_opts = opts;
5980773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5981773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5982c4837394SDouglas Gilbert 	tweak_cmnd_count();
59831da177e4SLinus Torvalds 	return count;
59841da177e4SLinus Torvalds }
598582069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
59861da177e4SLinus Torvalds 
598782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
59881da177e4SLinus Torvalds {
5989773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
59901da177e4SLinus Torvalds }
599182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
599282069379SAkinobu Mita 			   size_t count)
59931da177e4SLinus Torvalds {
59941da177e4SLinus Torvalds 	int n;
59951da177e4SLinus Torvalds 
5996f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5997f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5998f0d1cf93SDouglas Gilbert 		return -EINVAL;
5999f0d1cf93SDouglas Gilbert 
60001da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6001f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6002f0d1cf93SDouglas Gilbert 			return -EINVAL;
6003773642d9SDouglas Gilbert 		sdebug_ptype = n;
60041da177e4SLinus Torvalds 		return count;
60051da177e4SLinus Torvalds 	}
60061da177e4SLinus Torvalds 	return -EINVAL;
60071da177e4SLinus Torvalds }
600882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
60091da177e4SLinus Torvalds 
601082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
60111da177e4SLinus Torvalds {
6012773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
60131da177e4SLinus Torvalds }
601482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
601582069379SAkinobu Mita 			    size_t count)
60161da177e4SLinus Torvalds {
60171da177e4SLinus Torvalds 	int n;
60181da177e4SLinus Torvalds 
60191da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6020773642d9SDouglas Gilbert 		sdebug_dsense = n;
60211da177e4SLinus Torvalds 		return count;
60221da177e4SLinus Torvalds 	}
60231da177e4SLinus Torvalds 	return -EINVAL;
60241da177e4SLinus Torvalds }
602582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
60261da177e4SLinus Torvalds 
602782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
602823183910SDouglas Gilbert {
6029773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
603023183910SDouglas Gilbert }
603182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
603282069379SAkinobu Mita 			     size_t count)
603323183910SDouglas Gilbert {
603487c715dcSDouglas Gilbert 	int n, idx;
603523183910SDouglas Gilbert 
603623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
603787c715dcSDouglas Gilbert 		bool want_store = (n == 0);
603887c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
603987c715dcSDouglas Gilbert 
6040cbf67842SDouglas Gilbert 		n = (n > 0);
6041773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
604287c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
604387c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6044cbf67842SDouglas Gilbert 
604587c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
604687c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
604787c715dcSDouglas Gilbert 				idx = sdebug_add_store();
604887c715dcSDouglas Gilbert 				if (idx < 0)
604987c715dcSDouglas Gilbert 					return idx;
605087c715dcSDouglas Gilbert 			} else {
605187c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
605287c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
605387c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6054cbf67842SDouglas Gilbert 			}
605587c715dcSDouglas Gilbert 			/* make all hosts use same store */
605687c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
605787c715dcSDouglas Gilbert 					    host_list) {
605887c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
605987c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
606087c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
606187c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
606287c715dcSDouglas Gilbert 				}
606387c715dcSDouglas Gilbert 			}
606487c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
606587c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
606687c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6067cbf67842SDouglas Gilbert 		}
6068773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
606923183910SDouglas Gilbert 		return count;
607023183910SDouglas Gilbert 	}
607123183910SDouglas Gilbert 	return -EINVAL;
607223183910SDouglas Gilbert }
607382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
607423183910SDouglas Gilbert 
607582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6076c65b1445SDouglas Gilbert {
6077773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6078c65b1445SDouglas Gilbert }
607982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
608082069379SAkinobu Mita 			      size_t count)
6081c65b1445SDouglas Gilbert {
6082c65b1445SDouglas Gilbert 	int n;
6083c65b1445SDouglas Gilbert 
6084c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6085773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6086c65b1445SDouglas Gilbert 		return count;
6087c65b1445SDouglas Gilbert 	}
6088c65b1445SDouglas Gilbert 	return -EINVAL;
6089c65b1445SDouglas Gilbert }
609082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6091c65b1445SDouglas Gilbert 
609282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
60931da177e4SLinus Torvalds {
6094773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60951da177e4SLinus Torvalds }
609682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
609782069379SAkinobu Mita 			      size_t count)
60981da177e4SLinus Torvalds {
60991da177e4SLinus Torvalds 	int n;
61001da177e4SLinus Torvalds 
61011da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6102773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
61031da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
61041da177e4SLinus Torvalds 		return count;
61051da177e4SLinus Torvalds 	}
61061da177e4SLinus Torvalds 	return -EINVAL;
61071da177e4SLinus Torvalds }
610882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
61091da177e4SLinus Torvalds 
611082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
61111da177e4SLinus Torvalds {
6112773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
61131da177e4SLinus Torvalds }
611482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
61151da177e4SLinus Torvalds 
611687c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
611787c715dcSDouglas Gilbert {
611887c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
611987c715dcSDouglas Gilbert }
612087c715dcSDouglas Gilbert 
612187c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
612287c715dcSDouglas Gilbert 				    size_t count)
612387c715dcSDouglas Gilbert {
612487c715dcSDouglas Gilbert 	bool v;
612587c715dcSDouglas Gilbert 
612687c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
612787c715dcSDouglas Gilbert 		return -EINVAL;
612887c715dcSDouglas Gilbert 
612987c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
613087c715dcSDouglas Gilbert 	return count;
613187c715dcSDouglas Gilbert }
613287c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
613387c715dcSDouglas Gilbert 
613482069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
61351da177e4SLinus Torvalds {
6136773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
61371da177e4SLinus Torvalds }
613882069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
61391da177e4SLinus Torvalds 
614082069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
61411da177e4SLinus Torvalds {
6142773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
61431da177e4SLinus Torvalds }
614482069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
614582069379SAkinobu Mita 			       size_t count)
61461da177e4SLinus Torvalds {
61471da177e4SLinus Torvalds 	int nth;
61483a90a63dSDouglas Gilbert 	char work[20];
61491da177e4SLinus Torvalds 
61503a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61513a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61523a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
61533a90a63dSDouglas Gilbert 				goto every_nth_done;
61543a90a63dSDouglas Gilbert 		} else {
61553a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
61563a90a63dSDouglas Gilbert 				goto every_nth_done;
61573a90a63dSDouglas Gilbert 		}
61583a90a63dSDouglas Gilbert 	}
61593a90a63dSDouglas Gilbert 	return -EINVAL;
61603a90a63dSDouglas Gilbert 
61613a90a63dSDouglas Gilbert every_nth_done:
6162773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6163c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6164c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6165c4837394SDouglas Gilbert 		sdebug_statistics = true;
6166c4837394SDouglas Gilbert 	}
6167c4837394SDouglas Gilbert 	tweak_cmnd_count();
61681da177e4SLinus Torvalds 	return count;
61691da177e4SLinus Torvalds }
617082069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
61711da177e4SLinus Torvalds 
6172ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6173ad0c7775SDouglas Gilbert {
6174ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6175ad0c7775SDouglas Gilbert }
6176ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6177ad0c7775SDouglas Gilbert 				size_t count)
6178ad0c7775SDouglas Gilbert {
6179ad0c7775SDouglas Gilbert 	int n;
6180ad0c7775SDouglas Gilbert 	bool changed;
6181ad0c7775SDouglas Gilbert 
6182ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6183ad0c7775SDouglas Gilbert 		return -EINVAL;
6184ad0c7775SDouglas Gilbert 	if (n >= 0) {
6185ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6186ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6187ad0c7775SDouglas Gilbert 			return -EINVAL;
6188ad0c7775SDouglas Gilbert 		}
6189ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6190ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6191ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6192ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6193ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6194ad0c7775SDouglas Gilbert 
6195ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6196ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6197ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6198ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6199ad0c7775SDouglas Gilbert 				}
6200ad0c7775SDouglas Gilbert 			}
6201ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6202ad0c7775SDouglas Gilbert 		}
6203ad0c7775SDouglas Gilbert 		return count;
6204ad0c7775SDouglas Gilbert 	}
6205ad0c7775SDouglas Gilbert 	return -EINVAL;
6206ad0c7775SDouglas Gilbert }
6207ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6208ad0c7775SDouglas Gilbert 
620982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
62101da177e4SLinus Torvalds {
6211773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
62121da177e4SLinus Torvalds }
621382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
621482069379SAkinobu Mita 			      size_t count)
62151da177e4SLinus Torvalds {
62161da177e4SLinus Torvalds 	int n;
621719c8ead7SEwan D. Milne 	bool changed;
62181da177e4SLinus Torvalds 
62191da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
62208d039e22SDouglas Gilbert 		if (n > 256) {
62218d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
62228d039e22SDouglas Gilbert 			return -EINVAL;
62238d039e22SDouglas Gilbert 		}
6224773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6225773642d9SDouglas Gilbert 		sdebug_max_luns = n;
62261da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6227773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
622819c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
622919c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
623019c8ead7SEwan D. Milne 
623119c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
623219c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
623319c8ead7SEwan D. Milne 					    host_list) {
623419c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
623519c8ead7SEwan D. Milne 						    dev_list) {
623619c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
623719c8ead7SEwan D. Milne 						dp->uas_bm);
623819c8ead7SEwan D. Milne 				}
623919c8ead7SEwan D. Milne 			}
624019c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
624119c8ead7SEwan D. Milne 		}
62421da177e4SLinus Torvalds 		return count;
62431da177e4SLinus Torvalds 	}
62441da177e4SLinus Torvalds 	return -EINVAL;
62451da177e4SLinus Torvalds }
624682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
62471da177e4SLinus Torvalds 
624882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
624978d4e5a0SDouglas Gilbert {
6250773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
625178d4e5a0SDouglas Gilbert }
6252cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6253cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
625482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
625582069379SAkinobu Mita 			       size_t count)
625678d4e5a0SDouglas Gilbert {
6257c4837394SDouglas Gilbert 	int j, n, k, a;
6258c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
625978d4e5a0SDouglas Gilbert 
626078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6261c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6262c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6263c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6264c4837394SDouglas Gilbert 		k = 0;
6265c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6266c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6267c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6268c4837394SDouglas Gilbert 			if (a > k)
6269c4837394SDouglas Gilbert 				k = a;
6270c4837394SDouglas Gilbert 		}
6271773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6272c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6273cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6274cbf67842SDouglas Gilbert 		else if (k >= n)
6275cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6276cbf67842SDouglas Gilbert 		else
6277cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6278c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
627978d4e5a0SDouglas Gilbert 		return count;
628078d4e5a0SDouglas Gilbert 	}
628178d4e5a0SDouglas Gilbert 	return -EINVAL;
628278d4e5a0SDouglas Gilbert }
628382069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
628478d4e5a0SDouglas Gilbert 
6285c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6286c10fa55fSJohn Garry {
6287c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6288c10fa55fSJohn Garry }
6289c10fa55fSJohn Garry 
6290c10fa55fSJohn Garry /*
6291c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6292c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6293c10fa55fSJohn Garry  */
6294c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6295c10fa55fSJohn Garry 
629682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
629778d4e5a0SDouglas Gilbert {
6298773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
629978d4e5a0SDouglas Gilbert }
630082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
630178d4e5a0SDouglas Gilbert 
630282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
63031da177e4SLinus Torvalds {
6304773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
63051da177e4SLinus Torvalds }
630682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
63071da177e4SLinus Torvalds 
630882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6309c65b1445SDouglas Gilbert {
6310773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6311c65b1445SDouglas Gilbert }
631282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
631382069379SAkinobu Mita 				size_t count)
6314c65b1445SDouglas Gilbert {
6315c65b1445SDouglas Gilbert 	int n;
63160d01c5dfSDouglas Gilbert 	bool changed;
6317c65b1445SDouglas Gilbert 
6318f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6319f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6320f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6321f0d1cf93SDouglas Gilbert 
6322c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6323773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6324773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
632528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
63260d01c5dfSDouglas Gilbert 		if (changed) {
63270d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
63280d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
632928898873SFUJITA Tomonori 
63304bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
63310d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
63320d01c5dfSDouglas Gilbert 					    host_list) {
63330d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
63340d01c5dfSDouglas Gilbert 						    dev_list) {
63350d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
63360d01c5dfSDouglas Gilbert 						dp->uas_bm);
63370d01c5dfSDouglas Gilbert 				}
63380d01c5dfSDouglas Gilbert 			}
63394bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
63400d01c5dfSDouglas Gilbert 		}
6341c65b1445SDouglas Gilbert 		return count;
6342c65b1445SDouglas Gilbert 	}
6343c65b1445SDouglas Gilbert 	return -EINVAL;
6344c65b1445SDouglas Gilbert }
634582069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6346c65b1445SDouglas Gilbert 
634782069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
63481da177e4SLinus Torvalds {
634987c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
635087c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
63511da177e4SLinus Torvalds }
63521da177e4SLinus Torvalds 
635382069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
635482069379SAkinobu Mita 			      size_t count)
63551da177e4SLinus Torvalds {
635687c715dcSDouglas Gilbert 	bool found;
635787c715dcSDouglas Gilbert 	unsigned long idx;
635887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
635987c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
63601da177e4SLinus Torvalds 	int delta_hosts;
63611da177e4SLinus Torvalds 
6362f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
63631da177e4SLinus Torvalds 		return -EINVAL;
63641da177e4SLinus Torvalds 	if (delta_hosts > 0) {
63651da177e4SLinus Torvalds 		do {
636687c715dcSDouglas Gilbert 			found = false;
636787c715dcSDouglas Gilbert 			if (want_phs) {
636887c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
636987c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
637087c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
637187c715dcSDouglas Gilbert 					found = true;
637287c715dcSDouglas Gilbert 					break;
637387c715dcSDouglas Gilbert 				}
637487c715dcSDouglas Gilbert 				if (found)	/* re-use case */
637587c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
637687c715dcSDouglas Gilbert 				else
637787c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
637887c715dcSDouglas Gilbert 			} else {
637987c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
638087c715dcSDouglas Gilbert 			}
63811da177e4SLinus Torvalds 		} while (--delta_hosts);
63821da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
63831da177e4SLinus Torvalds 		do {
638487c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
63851da177e4SLinus Torvalds 		} while (++delta_hosts);
63861da177e4SLinus Torvalds 	}
63871da177e4SLinus Torvalds 	return count;
63881da177e4SLinus Torvalds }
638982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
63901da177e4SLinus Torvalds 
639182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
639223183910SDouglas Gilbert {
6393773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
639423183910SDouglas Gilbert }
639582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
639682069379SAkinobu Mita 				    size_t count)
639723183910SDouglas Gilbert {
639823183910SDouglas Gilbert 	int n;
639923183910SDouglas Gilbert 
640023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6401773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
640223183910SDouglas Gilbert 		return count;
640323183910SDouglas Gilbert 	}
640423183910SDouglas Gilbert 	return -EINVAL;
640523183910SDouglas Gilbert }
640682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
640723183910SDouglas Gilbert 
6408c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6409c4837394SDouglas Gilbert {
6410c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6411c4837394SDouglas Gilbert }
6412c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6413c4837394SDouglas Gilbert 				size_t count)
6414c4837394SDouglas Gilbert {
6415c4837394SDouglas Gilbert 	int n;
6416c4837394SDouglas Gilbert 
6417c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6418c4837394SDouglas Gilbert 		if (n > 0)
6419c4837394SDouglas Gilbert 			sdebug_statistics = true;
6420c4837394SDouglas Gilbert 		else {
6421c4837394SDouglas Gilbert 			clear_queue_stats();
6422c4837394SDouglas Gilbert 			sdebug_statistics = false;
6423c4837394SDouglas Gilbert 		}
6424c4837394SDouglas Gilbert 		return count;
6425c4837394SDouglas Gilbert 	}
6426c4837394SDouglas Gilbert 	return -EINVAL;
6427c4837394SDouglas Gilbert }
6428c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6429c4837394SDouglas Gilbert 
643082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6431597136abSMartin K. Petersen {
6432773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6433597136abSMartin K. Petersen }
643482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6435597136abSMartin K. Petersen 
6436c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6437c4837394SDouglas Gilbert {
6438c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6439c4837394SDouglas Gilbert }
6440c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6441c4837394SDouglas Gilbert 
644282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6443c6a44287SMartin K. Petersen {
6444773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6445c6a44287SMartin K. Petersen }
644682069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6447c6a44287SMartin K. Petersen 
644882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6449c6a44287SMartin K. Petersen {
6450773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6451c6a44287SMartin K. Petersen }
645282069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6453c6a44287SMartin K. Petersen 
645482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6455c6a44287SMartin K. Petersen {
6456773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6457c6a44287SMartin K. Petersen }
645882069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6459c6a44287SMartin K. Petersen 
646082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6461c6a44287SMartin K. Petersen {
6462773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6463c6a44287SMartin K. Petersen }
646482069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6465c6a44287SMartin K. Petersen 
646682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
646744d92694SMartin K. Petersen {
646887c715dcSDouglas Gilbert 	ssize_t count = 0;
646944d92694SMartin K. Petersen 
64705b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
647144d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
647244d92694SMartin K. Petersen 				 sdebug_store_sectors);
647344d92694SMartin K. Petersen 
647487c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
647587c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
647687c715dcSDouglas Gilbert 
647787c715dcSDouglas Gilbert 		if (sip)
6478c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
647987c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
648087c715dcSDouglas Gilbert 	}
648144d92694SMartin K. Petersen 	buf[count++] = '\n';
6482c7badc90STejun Heo 	buf[count] = '\0';
648344d92694SMartin K. Petersen 
648444d92694SMartin K. Petersen 	return count;
648544d92694SMartin K. Petersen }
648682069379SAkinobu Mita static DRIVER_ATTR_RO(map);
648744d92694SMartin K. Petersen 
64880c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
64890c4bc91dSDouglas Gilbert {
64900c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
64910c4bc91dSDouglas Gilbert }
64920c4bc91dSDouglas Gilbert 
64930c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
64940c4bc91dSDouglas Gilbert 			    size_t count)
64950c4bc91dSDouglas Gilbert {
64960c4bc91dSDouglas Gilbert 	bool v;
64970c4bc91dSDouglas Gilbert 
64980c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
64990c4bc91dSDouglas Gilbert 		return -EINVAL;
65000c4bc91dSDouglas Gilbert 
65010c4bc91dSDouglas Gilbert 	sdebug_random = v;
65020c4bc91dSDouglas Gilbert 	return count;
65030c4bc91dSDouglas Gilbert }
65040c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
65050c4bc91dSDouglas Gilbert 
650682069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6507d986788bSMartin Pitt {
6508773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6509d986788bSMartin Pitt }
651082069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
651182069379SAkinobu Mita 			       size_t count)
6512d986788bSMartin Pitt {
6513d986788bSMartin Pitt 	int n;
6514d986788bSMartin Pitt 
6515d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6516773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6517d986788bSMartin Pitt 		return count;
6518d986788bSMartin Pitt 	}
6519d986788bSMartin Pitt 	return -EINVAL;
6520d986788bSMartin Pitt }
652182069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6522d986788bSMartin Pitt 
6523cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6524cbf67842SDouglas Gilbert {
6525773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6526cbf67842SDouglas Gilbert }
6527185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6528cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6529cbf67842SDouglas Gilbert 			       size_t count)
6530cbf67842SDouglas Gilbert {
6531185dd232SDouglas Gilbert 	int n;
6532cbf67842SDouglas Gilbert 
6533cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6534185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6535185dd232SDouglas Gilbert 		return count;
6536cbf67842SDouglas Gilbert 	}
6537cbf67842SDouglas Gilbert 	return -EINVAL;
6538cbf67842SDouglas Gilbert }
6539cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6540cbf67842SDouglas Gilbert 
6541c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6542c2248fc9SDouglas Gilbert {
6543773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6544c2248fc9SDouglas Gilbert }
6545c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6546c2248fc9SDouglas Gilbert 			    size_t count)
6547c2248fc9SDouglas Gilbert {
6548c2248fc9SDouglas Gilbert 	int n;
6549c2248fc9SDouglas Gilbert 
6550c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6551773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6552c2248fc9SDouglas Gilbert 		return count;
6553c2248fc9SDouglas Gilbert 	}
6554c2248fc9SDouglas Gilbert 	return -EINVAL;
6555c2248fc9SDouglas Gilbert }
6556c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6557c2248fc9SDouglas Gilbert 
655809ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
655909ba24c1SDouglas Gilbert {
656009ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
656109ba24c1SDouglas Gilbert }
656209ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
656309ba24c1SDouglas Gilbert 
65649b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
65659b760fd8SDouglas Gilbert {
65669b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
65679b760fd8SDouglas Gilbert }
65689b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
65699b760fd8SDouglas Gilbert 			     size_t count)
65709b760fd8SDouglas Gilbert {
65719b760fd8SDouglas Gilbert 	int ret, n;
65729b760fd8SDouglas Gilbert 
65739b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
65749b760fd8SDouglas Gilbert 	if (ret)
65759b760fd8SDouglas Gilbert 		return ret;
65769b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
65779b760fd8SDouglas Gilbert 	all_config_cdb_len();
65789b760fd8SDouglas Gilbert 	return count;
65799b760fd8SDouglas Gilbert }
65809b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
65819b760fd8SDouglas Gilbert 
65829267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
65839267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
65849267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
65859267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
65869267e0ebSDouglas Gilbert };
65879267e0ebSDouglas Gilbert 
65889267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
65899267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
65909267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
65919267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
65929267e0ebSDouglas Gilbert };
65939267e0ebSDouglas Gilbert 
65949267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
65959267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
65969267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
65979267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
65989267e0ebSDouglas Gilbert };
65999267e0ebSDouglas Gilbert 
66009267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
66019267e0ebSDouglas Gilbert {
66029267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
66039267e0ebSDouglas Gilbert 
66049267e0ebSDouglas Gilbert 	if (res < 0) {
66059267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
66069267e0ebSDouglas Gilbert 		if (res < 0) {
66079267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
660847742bdeSDan Carpenter 			if (res < 0)
66099267e0ebSDouglas Gilbert 				return -EINVAL;
66109267e0ebSDouglas Gilbert 		}
66119267e0ebSDouglas Gilbert 	}
66129267e0ebSDouglas Gilbert 	return res;
66139267e0ebSDouglas Gilbert }
66149267e0ebSDouglas Gilbert 
66159267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
66169267e0ebSDouglas Gilbert {
66179267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
66189267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
66199267e0ebSDouglas Gilbert }
66209267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6621cbf67842SDouglas Gilbert 
6622fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6623fc13638aSDouglas Gilbert {
6624fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6625fc13638aSDouglas Gilbert }
6626fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6627fc13638aSDouglas Gilbert 
662882069379SAkinobu Mita /* Note: The following array creates attribute files in the
662923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
663023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
663123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
663287c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
663323183910SDouglas Gilbert  */
66346ecaff7fSRandy Dunlap 
663582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
663682069379SAkinobu Mita 	&driver_attr_delay.attr,
663782069379SAkinobu Mita 	&driver_attr_opts.attr,
663882069379SAkinobu Mita 	&driver_attr_ptype.attr,
663982069379SAkinobu Mita 	&driver_attr_dsense.attr,
664082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6641c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
664282069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
664382069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
664482069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
664582069379SAkinobu Mita 	&driver_attr_num_parts.attr,
664682069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6647ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
664882069379SAkinobu Mita 	&driver_attr_max_luns.attr,
664982069379SAkinobu Mita 	&driver_attr_max_queue.attr,
665082069379SAkinobu Mita 	&driver_attr_no_uld.attr,
665182069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
665282069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
665382069379SAkinobu Mita 	&driver_attr_add_host.attr,
665487c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
665582069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
665682069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6657c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6658c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
665982069379SAkinobu Mita 	&driver_attr_dix.attr,
666082069379SAkinobu Mita 	&driver_attr_dif.attr,
666182069379SAkinobu Mita 	&driver_attr_guard.attr,
666282069379SAkinobu Mita 	&driver_attr_ato.attr,
666382069379SAkinobu Mita 	&driver_attr_map.attr,
66640c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
666582069379SAkinobu Mita 	&driver_attr_removable.attr,
6666cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6667cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6668c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
666909ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
66709b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6671fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
66729267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
667382069379SAkinobu Mita 	NULL,
667482069379SAkinobu Mita };
667582069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
66761da177e4SLinus Torvalds 
667711ddcecaSAkinobu Mita static struct device *pseudo_primary;
66788dea0d02SFUJITA Tomonori 
66791da177e4SLinus Torvalds static int __init scsi_debug_init(void)
66801da177e4SLinus Torvalds {
668187c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
66825f2578e5SFUJITA Tomonori 	unsigned long sz;
668387c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
668487c715dcSDouglas Gilbert 	int idx = -1;
66851da177e4SLinus Torvalds 
668687c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
668787c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6688cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6689cbf67842SDouglas Gilbert 
6690773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6691c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6692773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6693773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6694c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6695cbf67842SDouglas Gilbert 
6696773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6697597136abSMartin K. Petersen 	case  512:
6698597136abSMartin K. Petersen 	case 1024:
6699597136abSMartin K. Petersen 	case 2048:
6700597136abSMartin K. Petersen 	case 4096:
6701597136abSMartin K. Petersen 		break;
6702597136abSMartin K. Petersen 	default:
6703773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6704597136abSMartin K. Petersen 		return -EINVAL;
6705597136abSMartin K. Petersen 	}
6706597136abSMartin K. Petersen 
6707773642d9SDouglas Gilbert 	switch (sdebug_dif) {
67088475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6709f46eb0e9SDouglas Gilbert 		break;
67108475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
67118475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
67128475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6713f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6714c6a44287SMartin K. Petersen 		break;
6715c6a44287SMartin K. Petersen 
6716c6a44287SMartin K. Petersen 	default:
6717c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6718c6a44287SMartin K. Petersen 		return -EINVAL;
6719c6a44287SMartin K. Petersen 	}
6720c6a44287SMartin K. Petersen 
6721aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6722aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6723aa5334c4SMaurizio Lombardi 		return -EINVAL;
6724aa5334c4SMaurizio Lombardi 	}
6725aa5334c4SMaurizio Lombardi 
6726773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6727c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6728c6a44287SMartin K. Petersen 		return -EINVAL;
6729c6a44287SMartin K. Petersen 	}
6730c6a44287SMartin K. Petersen 
6731773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6732c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6733c6a44287SMartin K. Petersen 		return -EINVAL;
6734c6a44287SMartin K. Petersen 	}
6735c6a44287SMartin K. Petersen 
6736773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6737773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6738ea61fca5SMartin K. Petersen 		return -EINVAL;
6739ea61fca5SMartin K. Petersen 	}
6740ad0c7775SDouglas Gilbert 
6741ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6742ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6743ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6744ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6745ad0c7775SDouglas Gilbert 	}
6746ad0c7775SDouglas Gilbert 
67478d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6748ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6749ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
67508d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
67518d039e22SDouglas Gilbert 		}
6752ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6753ad0c7775SDouglas Gilbert 	}
6754ea61fca5SMartin K. Petersen 
6755773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6756773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6757ea61fca5SMartin K. Petersen 		return -EINVAL;
6758ea61fca5SMartin K. Petersen 	}
6759ea61fca5SMartin K. Petersen 
6760c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6761c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6762c4837394SDouglas Gilbert 		return -EINVAL;
6763c4837394SDouglas Gilbert 	}
6764c87bf24cSJohn Garry 
6765c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6766c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6767c87bf24cSJohn Garry 		return -EINVAL;
6768c87bf24cSJohn Garry 	}
6769c87bf24cSJohn Garry 
6770c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6771c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6772c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6773c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6774c10fa55fSJohn Garry 		return -EINVAL;
6775c10fa55fSJohn Garry 	}
6776c10fa55fSJohn Garry 
6777c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6778c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6779c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6780c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6781c10fa55fSJohn Garry 			sdebug_max_queue);
6782c10fa55fSJohn Garry 	}
6783c10fa55fSJohn Garry 
6784c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6785c4837394SDouglas Gilbert 			       GFP_KERNEL);
6786c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6787c4837394SDouglas Gilbert 		return -ENOMEM;
6788c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6789c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6790c4837394SDouglas Gilbert 
6791f0d1cf93SDouglas Gilbert 	/*
67929267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
67939267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6794f0d1cf93SDouglas Gilbert 	 */
67959267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
67969267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
67979267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
67989267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
67999267e0ebSDouglas Gilbert 		if (k < 0) {
68009267e0ebSDouglas Gilbert 			ret = k;
68013b01d7eaSDinghao Liu 			goto free_q_arr;
68029267e0ebSDouglas Gilbert 		}
68039267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
68049267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
68059267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
680664e14eceSDamien Le Moal 		case BLK_ZONED_HA:
68079267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
68089267e0ebSDouglas Gilbert 			break;
68099267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
68109267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
68119267e0ebSDouglas Gilbert 			break;
68129267e0ebSDouglas Gilbert 		default:
68139267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
68143b01d7eaSDinghao Liu 			ret = -EINVAL;
68153b01d7eaSDinghao Liu 			goto free_q_arr;
68169267e0ebSDouglas Gilbert 		}
68179267e0ebSDouglas Gilbert 	}
68189267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6819f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
68209267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
68219267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
68229267e0ebSDouglas Gilbert 	}
6823f0d1cf93SDouglas Gilbert 
68249267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
68259267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6826773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6827773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6828773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6829773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
683028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
68311da177e4SLinus Torvalds 
68321da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
68331da177e4SLinus Torvalds 	sdebug_heads = 8;
68341da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6835773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
68361da177e4SLinus Torvalds 		sdebug_heads = 64;
6837773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6838fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
68391da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
68401da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
68411da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
68421da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
68431da177e4SLinus Torvalds 		sdebug_heads = 255;
68441da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
68451da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
68461da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
68471da177e4SLinus Torvalds 	}
68485b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6849773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6850773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
68516014759cSMartin K. Petersen 
6852773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6853773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
68546014759cSMartin K. Petersen 
6855773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6856773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
68576014759cSMartin K. Petersen 
6858773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6859773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6860773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6861c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6862c4837394SDouglas Gilbert 			ret = -EINVAL;
686387c715dcSDouglas Gilbert 			goto free_q_arr;
686444d92694SMartin K. Petersen 		}
686544d92694SMartin K. Petersen 	}
686687c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
686787c715dcSDouglas Gilbert 	if (want_store) {
686887c715dcSDouglas Gilbert 		idx = sdebug_add_store();
686987c715dcSDouglas Gilbert 		if (idx < 0) {
687087c715dcSDouglas Gilbert 			ret = idx;
687187c715dcSDouglas Gilbert 			goto free_q_arr;
687287c715dcSDouglas Gilbert 		}
687344d92694SMartin K. Petersen 	}
687444d92694SMartin K. Petersen 
68759b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
68769b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6877c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
68789b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
68796ecaff7fSRandy Dunlap 		goto free_vm;
68806ecaff7fSRandy Dunlap 	}
68816ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
68826ecaff7fSRandy Dunlap 	if (ret < 0) {
6883c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
68846ecaff7fSRandy Dunlap 		goto dev_unreg;
68856ecaff7fSRandy Dunlap 	}
68866ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
68876ecaff7fSRandy Dunlap 	if (ret < 0) {
6888c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
68896ecaff7fSRandy Dunlap 		goto bus_unreg;
68906ecaff7fSRandy Dunlap 	}
68911da177e4SLinus Torvalds 
689287c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6893773642d9SDouglas Gilbert 	sdebug_add_host = 0;
68941da177e4SLinus Torvalds 
689587c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
689687c715dcSDouglas Gilbert 		if (want_store && k == 0) {
689787c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
689887c715dcSDouglas Gilbert 			if (ret < 0) {
689987c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
690087c715dcSDouglas Gilbert 				       k, -ret);
690187c715dcSDouglas Gilbert 				break;
690287c715dcSDouglas Gilbert 			}
690387c715dcSDouglas Gilbert 		} else {
690487c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
690587c715dcSDouglas Gilbert 						 sdebug_per_host_store);
690687c715dcSDouglas Gilbert 			if (ret < 0) {
690787c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
69081da177e4SLinus Torvalds 				break;
69091da177e4SLinus Torvalds 			}
69101da177e4SLinus Torvalds 		}
691187c715dcSDouglas Gilbert 	}
6912773642d9SDouglas Gilbert 	if (sdebug_verbose)
691387c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6914c1287970STomas Winkler 
69151da177e4SLinus Torvalds 	return 0;
69166ecaff7fSRandy Dunlap 
69176ecaff7fSRandy Dunlap bus_unreg:
69186ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
69196ecaff7fSRandy Dunlap dev_unreg:
69209b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
69216ecaff7fSRandy Dunlap free_vm:
692287c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6923c4837394SDouglas Gilbert free_q_arr:
6924c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
69256ecaff7fSRandy Dunlap 	return ret;
69261da177e4SLinus Torvalds }
69271da177e4SLinus Torvalds 
69281da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
69291da177e4SLinus Torvalds {
693087c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
69311da177e4SLinus Torvalds 
69321da177e4SLinus Torvalds 	stop_all_queued();
69331da177e4SLinus Torvalds 	for (; k; k--)
693487c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
693552ab9768SLuis Henriques 	free_all_queued();
69361da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
69371da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
69389b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
69391da177e4SLinus Torvalds 
694087c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
694187c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
6942f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
69431da177e4SLinus Torvalds }
69441da177e4SLinus Torvalds 
69451da177e4SLinus Torvalds device_initcall(scsi_debug_init);
69461da177e4SLinus Torvalds module_exit(scsi_debug_exit);
69471da177e4SLinus Torvalds 
69481da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
69491da177e4SLinus Torvalds {
69501da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
69511da177e4SLinus Torvalds 
69521da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
69531da177e4SLinus Torvalds 	kfree(sdbg_host);
69541da177e4SLinus Torvalds }
69551da177e4SLinus Torvalds 
695687c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
695787c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
69581da177e4SLinus Torvalds {
695987c715dcSDouglas Gilbert 	if (idx < 0)
696087c715dcSDouglas Gilbert 		return;
696187c715dcSDouglas Gilbert 	if (!sip) {
696287c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
696387c715dcSDouglas Gilbert 			return;
696487c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
696587c715dcSDouglas Gilbert 		if (!sip)
696687c715dcSDouglas Gilbert 			return;
696787c715dcSDouglas Gilbert 	}
696887c715dcSDouglas Gilbert 	vfree(sip->map_storep);
696987c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
697087c715dcSDouglas Gilbert 	vfree(sip->storep);
697187c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
697287c715dcSDouglas Gilbert 	kfree(sip);
697387c715dcSDouglas Gilbert }
697487c715dcSDouglas Gilbert 
697587c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
697687c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
697787c715dcSDouglas Gilbert {
697887c715dcSDouglas Gilbert 	unsigned long idx;
697987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
698087c715dcSDouglas Gilbert 
698187c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
698287c715dcSDouglas Gilbert 		if (apart_from_first)
698387c715dcSDouglas Gilbert 			apart_from_first = false;
698487c715dcSDouglas Gilbert 		else
698587c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
698687c715dcSDouglas Gilbert 	}
698787c715dcSDouglas Gilbert 	if (apart_from_first)
698887c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
698987c715dcSDouglas Gilbert }
699087c715dcSDouglas Gilbert 
699187c715dcSDouglas Gilbert /*
699287c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
699387c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
699487c715dcSDouglas Gilbert  */
699587c715dcSDouglas Gilbert static int sdebug_add_store(void)
699687c715dcSDouglas Gilbert {
699787c715dcSDouglas Gilbert 	int res;
699887c715dcSDouglas Gilbert 	u32 n_idx;
699987c715dcSDouglas Gilbert 	unsigned long iflags;
700087c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
700187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
700287c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
700387c715dcSDouglas Gilbert 
700487c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
700587c715dcSDouglas Gilbert 	if (!sip)
700687c715dcSDouglas Gilbert 		return -ENOMEM;
700787c715dcSDouglas Gilbert 
700887c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
700987c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
701087c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
701187c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
701287c715dcSDouglas Gilbert 		kfree(sip);
701387c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
701487c715dcSDouglas Gilbert 		return res;
701587c715dcSDouglas Gilbert 	}
701687c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
701787c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
701887c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
701987c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
702087c715dcSDouglas Gilbert 
702187c715dcSDouglas Gilbert 	res = -ENOMEM;
702287c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
702387c715dcSDouglas Gilbert 	if (!sip->storep) {
702487c715dcSDouglas Gilbert 		pr_err("user data oom\n");
702587c715dcSDouglas Gilbert 		goto err;
702687c715dcSDouglas Gilbert 	}
702787c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
702887c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
702987c715dcSDouglas Gilbert 
703087c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
703187c715dcSDouglas Gilbert 	if (sdebug_dix) {
703287c715dcSDouglas Gilbert 		int dif_size;
703387c715dcSDouglas Gilbert 
703487c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
703587c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
703687c715dcSDouglas Gilbert 
703787c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
703887c715dcSDouglas Gilbert 			sip->dif_storep);
703987c715dcSDouglas Gilbert 
704087c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
704187c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
704287c715dcSDouglas Gilbert 			goto err;
704387c715dcSDouglas Gilbert 		}
704487c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
704587c715dcSDouglas Gilbert 	}
704687c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
704787c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
704887c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
704987c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
705087c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
705187c715dcSDouglas Gilbert 
705287c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
705387c715dcSDouglas Gilbert 
705487c715dcSDouglas Gilbert 		if (!sip->map_storep) {
705587c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
705687c715dcSDouglas Gilbert 			goto err;
705787c715dcSDouglas Gilbert 		}
705887c715dcSDouglas Gilbert 
705987c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
706087c715dcSDouglas Gilbert 
706187c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
706287c715dcSDouglas Gilbert 		if (sdebug_num_parts)
706387c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
706487c715dcSDouglas Gilbert 	}
706587c715dcSDouglas Gilbert 
706687c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
706787c715dcSDouglas Gilbert 	return (int)n_idx;
706887c715dcSDouglas Gilbert err:
706987c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
707087c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
707187c715dcSDouglas Gilbert 	return res;
707287c715dcSDouglas Gilbert }
707387c715dcSDouglas Gilbert 
707487c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
707587c715dcSDouglas Gilbert {
707687c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
707787c715dcSDouglas Gilbert 	int error = -ENOMEM;
70781da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
70798b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
70801da177e4SLinus Torvalds 
708124669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
708287c715dcSDouglas Gilbert 	if (!sdbg_host)
70831da177e4SLinus Torvalds 		return -ENOMEM;
708487c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
708587c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
708687c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
708787c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
70881da177e4SLinus Torvalds 
70891da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
70901da177e4SLinus Torvalds 
7091773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
70921da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
70935cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
709487c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
70951da177e4SLinus Torvalds 			goto clean;
70961da177e4SLinus Torvalds 	}
70971da177e4SLinus Torvalds 
70981da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
70991da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
71001da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
71011da177e4SLinus Torvalds 
71021da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
71039b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
71041da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
710587c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
71061da177e4SLinus Torvalds 
71071da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
71081da177e4SLinus Torvalds 	if (error)
71091da177e4SLinus Torvalds 		goto clean;
71101da177e4SLinus Torvalds 
711187c715dcSDouglas Gilbert 	++sdebug_num_hosts;
711287c715dcSDouglas Gilbert 	return 0;
71131da177e4SLinus Torvalds 
71141da177e4SLinus Torvalds clean:
71158b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
71168b40228fSFUJITA Tomonori 				 dev_list) {
71171da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7118f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
71191da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
71201da177e4SLinus Torvalds 	}
71211da177e4SLinus Torvalds 	kfree(sdbg_host);
712287c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
71231da177e4SLinus Torvalds 	return error;
71241da177e4SLinus Torvalds }
71251da177e4SLinus Torvalds 
712687c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
71271da177e4SLinus Torvalds {
712887c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
712987c715dcSDouglas Gilbert 
713087c715dcSDouglas Gilbert 	if (mk_new_store) {
713187c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
713287c715dcSDouglas Gilbert 		if (ph_idx < 0)
713387c715dcSDouglas Gilbert 			return ph_idx;
713487c715dcSDouglas Gilbert 	}
713587c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
713687c715dcSDouglas Gilbert }
713787c715dcSDouglas Gilbert 
713887c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
713987c715dcSDouglas Gilbert {
714087c715dcSDouglas Gilbert 	int idx = -1;
71411da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
714287c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
71431da177e4SLinus Torvalds 
71441da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
71451da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
71461da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
71471da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
714887c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
71491da177e4SLinus Torvalds 	}
715087c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
715187c715dcSDouglas Gilbert 		bool unique = true;
715287c715dcSDouglas Gilbert 
715387c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
715487c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
715587c715dcSDouglas Gilbert 				continue;
715687c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
715787c715dcSDouglas Gilbert 				unique = false;
715887c715dcSDouglas Gilbert 				break;
715987c715dcSDouglas Gilbert 			}
716087c715dcSDouglas Gilbert 		}
716187c715dcSDouglas Gilbert 		if (unique) {
716287c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
716387c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
716487c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
716587c715dcSDouglas Gilbert 		}
716687c715dcSDouglas Gilbert 	}
716787c715dcSDouglas Gilbert 	if (sdbg_host)
716887c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
71691da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
71701da177e4SLinus Torvalds 
71711da177e4SLinus Torvalds 	if (!sdbg_host)
71721da177e4SLinus Torvalds 		return;
71731da177e4SLinus Torvalds 
71741da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
717587c715dcSDouglas Gilbert 	--sdebug_num_hosts;
71761da177e4SLinus Torvalds }
71771da177e4SLinus Torvalds 
7178fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7179cbf67842SDouglas Gilbert {
7180cbf67842SDouglas Gilbert 	int num_in_q = 0;
7181cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7182cbf67842SDouglas Gilbert 
7183c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
7184cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7185cbf67842SDouglas Gilbert 	if (NULL == devip) {
7186c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
7187cbf67842SDouglas Gilbert 		return	-ENODEV;
7188cbf67842SDouglas Gilbert 	}
7189cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7190c40ecc12SChristoph Hellwig 
7191fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7192fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7193fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7194fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7195fc09acb7SDouglas Gilbert 	}
7196cbf67842SDouglas Gilbert 	if (qdepth < 1)
7197cbf67842SDouglas Gilbert 		qdepth = 1;
7198fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7199db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7200cbf67842SDouglas Gilbert 
7201773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7202c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7203c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7204cbf67842SDouglas Gilbert 	}
7205c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
7206cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7207cbf67842SDouglas Gilbert }
7208cbf67842SDouglas Gilbert 
7209c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7210817fd66bSDouglas Gilbert {
7211c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7212773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7213773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7214773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7215c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7216773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7217817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7218c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7219817fd66bSDouglas Gilbert 	}
7220c4837394SDouglas Gilbert 	return false;
7221817fd66bSDouglas Gilbert }
7222817fd66bSDouglas Gilbert 
7223fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7224fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7225fc13638aSDouglas Gilbert {
7226fc13638aSDouglas Gilbert 	int stopped_state;
7227fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7228fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7229fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7230fc13638aSDouglas Gilbert 
7231fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7232fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7233fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7234fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7235fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7236fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7237fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7238fc13638aSDouglas Gilbert 				return 0;
7239fc13638aSDouglas Gilbert 			}
7240fc13638aSDouglas Gilbert 		}
7241fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7242fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7243fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7244fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7245fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7246fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7247fc13638aSDouglas Gilbert 
7248fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7249fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7250fc13638aSDouglas Gilbert 			else
7251fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7252fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7253fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7254fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7255fc13638aSDouglas Gilbert 						   diff_ns);
7256fc13638aSDouglas Gilbert 			return check_condition_result;
7257fc13638aSDouglas Gilbert 		}
7258fc13638aSDouglas Gilbert 	}
7259fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7260fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7261fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7262fc13638aSDouglas Gilbert 			    my_name);
7263fc13638aSDouglas Gilbert 	return check_condition_result;
7264fc13638aSDouglas Gilbert }
7265fc13638aSDouglas Gilbert 
7266c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost)
7267c4b57d89SKashyap Desai {
7268c4b57d89SKashyap Desai 	int i, qoff;
7269c4b57d89SKashyap Desai 
7270c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7271c4b57d89SKashyap Desai 		return 0;
7272c4b57d89SKashyap Desai 
7273c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7274c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7275c4b57d89SKashyap Desai 
7276c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7277c4b57d89SKashyap Desai 
7278c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7279c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7280c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7281c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7282c4b57d89SKashyap Desai 
7283c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7284c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7285c4b57d89SKashyap Desai 			continue;
7286c4b57d89SKashyap Desai 		}
7287c4b57d89SKashyap Desai 
7288c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7289c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7290c4b57d89SKashyap Desai 
7291c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7292c4b57d89SKashyap Desai 	}
7293c4b57d89SKashyap Desai 
7294c4b57d89SKashyap Desai 	return 0;
7295c4b57d89SKashyap Desai 
7296c4b57d89SKashyap Desai }
7297c4b57d89SKashyap Desai 
7298c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7299c4b57d89SKashyap Desai {
73004a0c6f43SDouglas Gilbert 	bool first;
73014a0c6f43SDouglas Gilbert 	bool retiring = false;
73024a0c6f43SDouglas Gilbert 	int num_entries = 0;
73034a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7304c4b57d89SKashyap Desai 	unsigned long iflags;
73054a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7306c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7307c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7308c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7309c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
73104a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7311c4b57d89SKashyap Desai 
7312c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
7313c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
73144a0c6f43SDouglas Gilbert 
73154a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
73164a0c6f43SDouglas Gilbert 		if (first) {
7317c4b57d89SKashyap Desai 			qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
73184a0c6f43SDouglas Gilbert 			first = false;
73194a0c6f43SDouglas Gilbert 		} else {
73204a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
73214a0c6f43SDouglas Gilbert 		}
73224a0c6f43SDouglas Gilbert 		if (unlikely(qc_idx >= sdebug_max_queue))
73234a0c6f43SDouglas Gilbert 			break;
7324c4b57d89SKashyap Desai 
7325c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
73264a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
73274a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
73284a0c6f43SDouglas Gilbert 			continue;
7329c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7330c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
73314a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7332c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
73334a0c6f43SDouglas Gilbert 			break;
7334c4b57d89SKashyap Desai 		}
73354a0c6f43SDouglas Gilbert 		if (sd_dp->defer_t == SDEB_DEFER_POLL) {
73364a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
73374a0c6f43SDouglas Gilbert 				continue;
73384a0c6f43SDouglas Gilbert 
73394a0c6f43SDouglas Gilbert 		} else		/* ignoring non REQ_HIPRI requests */
73404a0c6f43SDouglas Gilbert 			continue;
7341c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7342c4b57d89SKashyap Desai 		if (likely(devip))
7343c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7344c4b57d89SKashyap Desai 		else
7345c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7346c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
73474a0c6f43SDouglas Gilbert 			retiring = true;
7348c4b57d89SKashyap Desai 
7349c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7350c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
73514a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7352c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
73534a0c6f43SDouglas Gilbert 			break;
7354c4b57d89SKashyap Desai 		}
7355c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7356c4b57d89SKashyap Desai 			int k, retval;
7357c4b57d89SKashyap Desai 
7358c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7359c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7360c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
73614a0c6f43SDouglas Gilbert 				break;
7362c4b57d89SKashyap Desai 			}
7363c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7364c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7365c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7366c4b57d89SKashyap Desai 			else
7367c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7368c4b57d89SKashyap Desai 		}
73694a0c6f43SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_NONE;
7370c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
73716c2c7d6aSBart Van Assche 		scsi_done(scp); /* callback to mid level */
73724a0c6f43SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7373c4b57d89SKashyap Desai 		num_entries++;
73744a0c6f43SDouglas Gilbert 	}
7375c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
73764a0c6f43SDouglas Gilbert 	if (num_entries > 0)
73774a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7378c4b57d89SKashyap Desai 	return num_entries;
7379c4b57d89SKashyap Desai }
7380c4b57d89SKashyap Desai 
7381fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7382fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7383c2248fc9SDouglas Gilbert {
7384c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7385c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7386c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7387c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7388c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7389c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7390c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7391f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7392c2248fc9SDouglas Gilbert 	int k, na;
7393c2248fc9SDouglas Gilbert 	int errsts = 0;
7394ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7395c2248fc9SDouglas Gilbert 	u32 flags;
7396c2248fc9SDouglas Gilbert 	u16 sa;
7397c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7398c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
73993a90a63dSDouglas Gilbert 	bool inject_now;
7400c2248fc9SDouglas Gilbert 
7401c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
74023a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7403c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
74043a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
74053a90a63dSDouglas Gilbert 	} else {
74063a90a63dSDouglas Gilbert 		inject_now = false;
74073a90a63dSDouglas Gilbert 	}
7408f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7409f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7410c2248fc9SDouglas Gilbert 		char b[120];
7411c2248fc9SDouglas Gilbert 		int n, len, sb;
7412c2248fc9SDouglas Gilbert 
7413c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7414c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7415c2248fc9SDouglas Gilbert 		if (len > 32)
7416c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7417c2248fc9SDouglas Gilbert 		else {
7418c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7419c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7420c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7421c2248fc9SDouglas Gilbert 		}
7422458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7423a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7424c2248fc9SDouglas Gilbert 	}
74253a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
74267ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
742734d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7428ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7429f46eb0e9SDouglas Gilbert 		goto err_out;
7430c2248fc9SDouglas Gilbert 
7431c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7432c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7433c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7434f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7435f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7436c2248fc9SDouglas Gilbert 		if (NULL == devip)
7437f46eb0e9SDouglas Gilbert 			goto err_out;
7438c2248fc9SDouglas Gilbert 	}
74393a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
74403a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
74413a90a63dSDouglas Gilbert 
7442c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7443c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7444c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7445c2248fc9SDouglas Gilbert 		r_oip = oip;
7446c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7447c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7448c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7449c2248fc9SDouglas Gilbert 			else
7450c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7451c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7452c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7453c2248fc9SDouglas Gilbert 					break;
7454c2248fc9SDouglas Gilbert 			}
7455c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7456c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7457c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7458c2248fc9SDouglas Gilbert 					break;
7459c2248fc9SDouglas Gilbert 			}
7460c2248fc9SDouglas Gilbert 		}
7461c2248fc9SDouglas Gilbert 		if (k > na) {
7462c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7463c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7464c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7465c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7466c2248fc9SDouglas Gilbert 			else
7467c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7468c2248fc9SDouglas Gilbert 			goto check_cond;
7469c2248fc9SDouglas Gilbert 		}
7470c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7471c2248fc9SDouglas Gilbert 	flags = oip->flags;
7472f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7473c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7474c2248fc9SDouglas Gilbert 		goto check_cond;
7475c2248fc9SDouglas Gilbert 	}
7476f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7477773642d9SDouglas Gilbert 		if (sdebug_verbose)
7478773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7479773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7480c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7481c2248fc9SDouglas Gilbert 		goto check_cond;
7482c2248fc9SDouglas Gilbert 	}
7483f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7484c2248fc9SDouglas Gilbert 		u8 rem;
7485c2248fc9SDouglas Gilbert 		int j;
7486c2248fc9SDouglas Gilbert 
7487c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7488c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7489c2248fc9SDouglas Gilbert 			if (rem) {
7490c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7491c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7492c2248fc9SDouglas Gilbert 						break;
7493c2248fc9SDouglas Gilbert 				}
7494c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7495c2248fc9SDouglas Gilbert 				goto check_cond;
7496c2248fc9SDouglas Gilbert 			}
7497c2248fc9SDouglas Gilbert 		}
7498c2248fc9SDouglas Gilbert 	}
7499f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7500b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7501b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7502f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7503c2248fc9SDouglas Gilbert 		if (errsts)
7504c2248fc9SDouglas Gilbert 			goto check_cond;
7505c2248fc9SDouglas Gilbert 	}
7506fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7507fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7508fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7509fc13638aSDouglas Gilbert 		if (errsts)
7510c2248fc9SDouglas Gilbert 			goto fini;
7511c2248fc9SDouglas Gilbert 	}
7512773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7513c2248fc9SDouglas Gilbert 		goto fini;
7514f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7515c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7516c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7517c2248fc9SDouglas Gilbert 	}
7518f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7519f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7520f66b8517SMartin Wilck 	else
7521f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7522c2248fc9SDouglas Gilbert 
7523c2248fc9SDouglas Gilbert fini:
752467da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7525f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
752675aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
752775aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
752880c49563SDouglas Gilbert 		/*
752975aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
753075aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
753175aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
753275aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
753380c49563SDouglas Gilbert 		 */
753480c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
75354f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
753680c49563SDouglas Gilbert 
75374f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7538f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
753980c49563SDouglas Gilbert 	} else
7540f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
754110bde980SDouglas Gilbert 				     sdebug_ndelay);
7542c2248fc9SDouglas Gilbert check_cond:
7543f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7544f46eb0e9SDouglas Gilbert err_out:
7545f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7546c2248fc9SDouglas Gilbert }
7547c2248fc9SDouglas Gilbert 
75489e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7549c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7550c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
75519e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
75529e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
75539e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
75549e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
75559e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
75569e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
75579e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7558185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7559cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7560c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7561c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
75629e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
75639e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7564cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7565cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
75669e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7567c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
75689e603ca0SFUJITA Tomonori 	.this_id =		7,
756965e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7570cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
75716bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
757250c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
75739e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7574c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
75759e603ca0SFUJITA Tomonori };
75769e603ca0SFUJITA Tomonori 
75771da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
75781da177e4SLinus Torvalds {
75791da177e4SLinus Torvalds 	int error = 0;
75801da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
75811da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7582f46eb0e9SDouglas Gilbert 	int hprot;
75831da177e4SLinus Torvalds 
75841da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
75851da177e4SLinus Torvalds 
7586773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7587fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
75882a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
75894af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
75904af14d11SChristoph Hellwig 
75911da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
75921da177e4SLinus Torvalds 	if (NULL == hpnt) {
7593c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
75941da177e4SLinus Torvalds 		error = -ENODEV;
75951da177e4SLinus Torvalds 		return error;
75961da177e4SLinus Torvalds 	}
7597c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
75989b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7599c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7600c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7601c4837394SDouglas Gilbert 	}
7602c10fa55fSJohn Garry 	/*
7603c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7604f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7605c10fa55fSJohn Garry 	 */
7606c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7607f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7608f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
76091da177e4SLinus Torvalds 
7610c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7611c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7612c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7613c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7614c4b57d89SKashyap Desai 		poll_queues = 0;
7615c4b57d89SKashyap Desai 	}
7616c4b57d89SKashyap Desai 
7617c4b57d89SKashyap Desai 	/*
7618c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7619c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7620c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7621c4b57d89SKashyap Desai 	 */
7622c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7623fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7624c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7625fc09acb7SDouglas Gilbert 		else
7626fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7627fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7628c4b57d89SKashyap Desai 		poll_queues = 1;
7629c4b57d89SKashyap Desai 	}
7630c4b57d89SKashyap Desai 	if (poll_queues)
7631c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7632c4b57d89SKashyap Desai 
76331da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
76341da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7635773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7636773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
76371da177e4SLinus Torvalds 	else
7638773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7639773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7640f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
76411da177e4SLinus Torvalds 
7642f46eb0e9SDouglas Gilbert 	hprot = 0;
7643c6a44287SMartin K. Petersen 
7644773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7645c6a44287SMartin K. Petersen 
76468475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7647f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7648773642d9SDouglas Gilbert 		if (sdebug_dix)
7649f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7650c6a44287SMartin K. Petersen 		break;
7651c6a44287SMartin K. Petersen 
76528475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7653f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7654773642d9SDouglas Gilbert 		if (sdebug_dix)
7655f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7656c6a44287SMartin K. Petersen 		break;
7657c6a44287SMartin K. Petersen 
76588475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7659f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7660773642d9SDouglas Gilbert 		if (sdebug_dix)
7661f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7662c6a44287SMartin K. Petersen 		break;
7663c6a44287SMartin K. Petersen 
7664c6a44287SMartin K. Petersen 	default:
7665773642d9SDouglas Gilbert 		if (sdebug_dix)
7666f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7667c6a44287SMartin K. Petersen 		break;
7668c6a44287SMartin K. Petersen 	}
7669c6a44287SMartin K. Petersen 
7670f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7671c6a44287SMartin K. Petersen 
7672f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7673c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7674f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7675f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7676f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7677f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7678f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7679f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7680f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7681c6a44287SMartin K. Petersen 
7682773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7683c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7684c6a44287SMartin K. Petersen 	else
7685c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7686c6a44287SMartin K. Petersen 
7687773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7688773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7689c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7690c4837394SDouglas Gilbert 		sdebug_statistics = true;
76911da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
76921da177e4SLinus Torvalds 	if (error) {
7693c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
76941da177e4SLinus Torvalds 		error = -ENODEV;
76951da177e4SLinus Torvalds 		scsi_host_put(hpnt);
769687c715dcSDouglas Gilbert 	} else {
76971da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
769887c715dcSDouglas Gilbert 	}
76991da177e4SLinus Torvalds 
77001da177e4SLinus Torvalds 	return error;
77011da177e4SLinus Torvalds }
77021da177e4SLinus Torvalds 
7703fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
77041da177e4SLinus Torvalds {
77051da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
77068b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
77071da177e4SLinus Torvalds 
77081da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
77091da177e4SLinus Torvalds 
77101da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
77111da177e4SLinus Torvalds 
77128b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
77138b40228fSFUJITA Tomonori 				 dev_list) {
77141da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7715f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
77161da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
77171da177e4SLinus Torvalds 	}
77181da177e4SLinus Torvalds 
77191da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
77201da177e4SLinus Torvalds }
77211da177e4SLinus Torvalds 
77228dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
77238dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
77241da177e4SLinus Torvalds {
77258dea0d02SFUJITA Tomonori 	return 1;
77268dea0d02SFUJITA Tomonori }
77271da177e4SLinus Torvalds 
77288dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
77298dea0d02SFUJITA Tomonori 	.name = "pseudo",
77308dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
77318dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
77328dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
773382069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
77348dea0d02SFUJITA Tomonori };
7735