xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 979e0dc3)
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)
221cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
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,
32510bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
32610bde980SDouglas Gilbert 
327fd32119bSDouglas Gilbert struct sdebug_defer {
328fd32119bSDouglas Gilbert 	struct hrtimer hrt;
329fd32119bSDouglas Gilbert 	struct execute_work ew;
330c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
331c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
332c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
333c4837394SDouglas Gilbert 	int issuing_cpu;
33410bde980SDouglas Gilbert 	bool init_hrt;
33510bde980SDouglas Gilbert 	bool init_wq;
3367382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
33710bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
338fd32119bSDouglas Gilbert };
339fd32119bSDouglas Gilbert 
340fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
341c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
342c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
343c4837394SDouglas Gilbert 	 */
344fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
345fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
346fd32119bSDouglas Gilbert };
347fd32119bSDouglas Gilbert 
348c4837394SDouglas Gilbert struct sdebug_queue {
349c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
350c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
351c4837394SDouglas Gilbert 	spinlock_t qc_lock;
352c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
353fd32119bSDouglas Gilbert };
354fd32119bSDouglas Gilbert 
355c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
356c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
357c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
358c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3593a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
360c4837394SDouglas Gilbert 
361fd32119bSDouglas Gilbert struct opcode_info_t {
362b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
363b01f6f83SDouglas Gilbert 				/* for terminating element */
364fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
365fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
366fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
367fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
368fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3699a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3709a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
371fd32119bSDouglas Gilbert };
372fd32119bSDouglas Gilbert 
373fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
374c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
375c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
376c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
377c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
378c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
379c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
380c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
381c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
382c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
383c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
384c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
385c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
386c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
38746f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
38846f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
389c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
390c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
391c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
392481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
393c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
394c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
395c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
396c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
397c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
398c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
399c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
400c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
401c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
402c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
403c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
404ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
405f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
406f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
407f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
408c2248fc9SDouglas Gilbert };
409c2248fc9SDouglas Gilbert 
410c4837394SDouglas Gilbert 
411c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
412c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
413c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
414c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
415c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
416c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
417c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
418c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
419c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
420c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
421c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
422c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
423ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
424c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
425c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
426c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
427c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
428c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
429c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
430c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
431fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
432c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
433c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
434c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
435c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
436c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
437c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
438c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
439f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
440f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44146f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
442c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
443c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
444c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
44546f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
44646f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
447c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
448c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
449c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
450c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
451c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
452c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert };
455c2248fc9SDouglas Gilbert 
45680c49563SDouglas Gilbert /*
45780c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
45880c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
45980c49563SDouglas Gilbert  * command completion, they can mask their return value with
46080c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46180c49563SDouglas Gilbert  */
46280c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46380c49563SDouglas Gilbert 
464c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
465c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
466c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
467c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
468c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
469c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
470c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
473481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
47938d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48038d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
481c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
48438d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
485acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
48680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
487ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
488f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
489f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
490f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
491f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
492f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
493c2248fc9SDouglas Gilbert 
49487c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
49587c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
49687c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
49787c715dcSDouglas Gilbert static int sdebug_add_store(void);
49887c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
49987c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50087c715dcSDouglas Gilbert 
50146f64e70SDouglas Gilbert /*
50246f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50346f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
50446f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
50546f64e70SDouglas Gilbert  */
50646f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
507c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
508c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
509c2248fc9SDouglas Gilbert };
510c2248fc9SDouglas Gilbert 
51146f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
512c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
513c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
514c2248fc9SDouglas Gilbert };
515c2248fc9SDouglas Gilbert 
51646f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
51746f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
518b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
519c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52046f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
521c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52246f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
523b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
524c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
525c2248fc9SDouglas Gilbert };
526c2248fc9SDouglas Gilbert 
52746f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
52846f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
52946f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53046f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53146f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53246f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53346f64e70SDouglas Gilbert 		   0, 0, 0} },
53446f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
53546f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53646f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
537c2248fc9SDouglas Gilbert };
538c2248fc9SDouglas Gilbert 
539c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
540c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
541c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
542c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
543c3e2fe92SDouglas Gilbert };
544c3e2fe92SDouglas Gilbert 
54546f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
546c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
547c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54846f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
549c2248fc9SDouglas Gilbert };
550c2248fc9SDouglas Gilbert 
55146f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55246f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
553b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
554c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
555481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
556481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
557481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
558c2248fc9SDouglas Gilbert };
559c2248fc9SDouglas Gilbert 
56046f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56138d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
562c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56346f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
56438d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
565c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
56646f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
567c2248fc9SDouglas Gilbert };
568c2248fc9SDouglas Gilbert 
56946f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57046f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
571c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57246f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
573c2248fc9SDouglas Gilbert };
574c2248fc9SDouglas Gilbert 
57546f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
576c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
577c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
578c2248fc9SDouglas Gilbert };
579c2248fc9SDouglas Gilbert 
58046f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
581c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
582c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
583c2248fc9SDouglas Gilbert };
584c2248fc9SDouglas Gilbert 
58580c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5864f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
58780c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58880c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
58980c49563SDouglas Gilbert };
59080c49563SDouglas Gilbert 
591ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
592b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
593ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
594ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
595ed9f3e25SDouglas Gilbert };
596ed9f3e25SDouglas Gilbert 
597f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
598b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
599f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
600f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
601b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
602f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
604b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
605f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
607f0d1cf93SDouglas Gilbert };
608f0d1cf93SDouglas Gilbert 
609f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
610b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
611f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
613f0d1cf93SDouglas Gilbert };
614f0d1cf93SDouglas Gilbert 
615c2248fc9SDouglas Gilbert 
616c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
617c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
618c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
619ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
620c2248fc9SDouglas Gilbert /* 0 */
62146f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
622c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62346f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
624c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
625c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
626c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
62746f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
628c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
629c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
630c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
631c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63246f64e70SDouglas Gilbert /* 5 */
63346f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
63446f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
63546f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
63646f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
63746f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
63846f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
63946f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
640c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
641c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64246f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
643c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
644c2248fc9SDouglas Gilbert 	     0, 0} },
64546f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
64646f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
64746f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
648c2248fc9SDouglas Gilbert /* 10 */
64946f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65046f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65146f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65280c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6534f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
654c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65546f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
65646f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
65746f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65846f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
659481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
660481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
661481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66246f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66346f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
66446f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
66546f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
66646f64e70SDouglas Gilbert /* 15 */
667c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
668c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
669c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
670c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
671c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
672c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67346f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
67446f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
67546f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
67646f64e70SDouglas Gilbert 	     0xff, 0xff} },
67746f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
67846f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
679c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
680c2248fc9SDouglas Gilbert 	     0} },
68146f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68246f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
683c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
684c2248fc9SDouglas Gilbert 	     0} },
685c2248fc9SDouglas Gilbert /* 20 */
686f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
687f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
688c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
689c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
690c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
691c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
692c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
693c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
69446f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
695b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
69646f64e70SDouglas Gilbert /* 25 */
697acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
698acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
699acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70046f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70146f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70246f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70346f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7044f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
70580c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
706b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
70780c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
70846f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
709c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
710b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
711b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
712ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
713ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
714ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
715c2248fc9SDouglas Gilbert 
716ed9f3e25SDouglas Gilbert /* 30 */
717b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
718f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
719f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
720f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
721b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
722f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
723f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
724f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
725f0d1cf93SDouglas Gilbert /* sentinel */
726c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
727c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
728c2248fc9SDouglas Gilbert };
729c2248fc9SDouglas Gilbert 
73087c715dcSDouglas Gilbert static int sdebug_num_hosts;
73187c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
732773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7339b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
734c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7359267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
736773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
737773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
738773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
739773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
740773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
741773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
742c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
743773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
744773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
745c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
746d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
747d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
748cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
749c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
750773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
751773642d9SDouglas Gilbert static int sdebug_no_uld;
752773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
753773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
754773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
755773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
756773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
75786e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
758b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
759773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
760773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
761fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
762773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
763773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
764773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
765773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
766773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
767773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
768773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
769773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
770773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
771773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
772773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
77309ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7740c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
77587c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
776773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
777773642d9SDouglas Gilbert static bool sdebug_clustering;
778773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
779773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
780817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
781773642d9SDouglas Gilbert static bool sdebug_verbose;
782f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7834f2c8bf6SDouglas Gilbert static bool write_since_sync;
784c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7859447b6ceSMartin K. Petersen static bool sdebug_wp;
7869267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7879267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7889267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7891da177e4SLinus Torvalds 
790ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
791ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
792ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
793ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
794ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
795ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
796ad0c7775SDouglas Gilbert 
797c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
7981da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8011da177e4SLinus Torvalds    may still need them */
8021da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8031da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8041da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8071da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8081da177e4SLinus Torvalds 
80987c715dcSDouglas Gilbert static struct xarray per_store_arr;
81087c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
81187c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
81287c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
81387c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8141da177e4SLinus Torvalds 
81544d92694SMartin K. Petersen static unsigned long map_size;
816cbf67842SDouglas Gilbert static int num_aborts;
817cbf67842SDouglas Gilbert static int num_dev_resets;
818cbf67842SDouglas Gilbert static int num_target_resets;
819cbf67842SDouglas Gilbert static int num_bus_resets;
820cbf67842SDouglas Gilbert static int num_host_resets;
821c6a44287SMartin K. Petersen static int dix_writes;
822c6a44287SMartin K. Petersen static int dix_reads;
823c6a44287SMartin K. Petersen static int dif_errors;
8241da177e4SLinus Torvalds 
825f0d1cf93SDouglas Gilbert /* ZBC global data */
82664e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
82798e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
828380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
829aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
830f0d1cf93SDouglas Gilbert 
831c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
832c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
833fd32119bSDouglas Gilbert 
8341da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
83587c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
83687c715dcSDouglas Gilbert 
83787c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8381da177e4SLinus Torvalds 
839cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
840cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8431da177e4SLinus Torvalds 
8441da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8451da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8461da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8471da177e4SLinus Torvalds };
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds static const int check_condition_result =
8501da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8511da177e4SLinus Torvalds 
852c6a44287SMartin K. Petersen static const int illegal_condition_result =
853c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
854c6a44287SMartin K. Petersen 
855cbf67842SDouglas Gilbert static const int device_qfull_result =
856cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
857cbf67842SDouglas Gilbert 
858ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
859ed9f3e25SDouglas Gilbert 
860fd32119bSDouglas Gilbert 
861760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
862760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
863760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
864760f3b03SDouglas Gilbert  */
865760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
866fd32119bSDouglas Gilbert {
867fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
868fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
869fd32119bSDouglas Gilbert }
870c65b1445SDouglas Gilbert 
87187c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
87287c715dcSDouglas Gilbert 			    unsigned long long lba)
87314faa944SAkinobu Mita {
87487c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
87514faa944SAkinobu Mita 
87687c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
87787c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
87887c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
87987c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
88087c715dcSDouglas Gilbert 	}
88187c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
88214faa944SAkinobu Mita }
88314faa944SAkinobu Mita 
88487c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
88587c715dcSDouglas Gilbert 				      sector_t sector)
88614faa944SAkinobu Mita {
88749413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
88814faa944SAkinobu Mita 
88987c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
89014faa944SAkinobu Mita }
89114faa944SAkinobu Mita 
8928dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8938dea0d02SFUJITA Tomonori {
8948dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
8958dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
8968dea0d02SFUJITA Tomonori 
8978dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
8988dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8998dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9008dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
901773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
902773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9038dea0d02SFUJITA Tomonori 		else
904773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
905773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
906f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9078dea0d02SFUJITA Tomonori 	}
9088dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9098dea0d02SFUJITA Tomonori }
9108dea0d02SFUJITA Tomonori 
91122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
91222017ed2SDouglas Gilbert 
91322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
914fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
915fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
91622017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
91722017ed2SDouglas Gilbert {
91822017ed2SDouglas Gilbert 	unsigned char *sbuff;
91922017ed2SDouglas Gilbert 	u8 sks[4];
92022017ed2SDouglas Gilbert 	int sl, asc;
92122017ed2SDouglas Gilbert 
92222017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
92322017ed2SDouglas Gilbert 	if (!sbuff) {
92422017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
92522017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
92622017ed2SDouglas Gilbert 		return;
92722017ed2SDouglas Gilbert 	}
92822017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
92922017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
930773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
93122017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
93222017ed2SDouglas Gilbert 	sks[0] = 0x80;
93322017ed2SDouglas Gilbert 	if (c_d)
93422017ed2SDouglas Gilbert 		sks[0] |= 0x40;
93522017ed2SDouglas Gilbert 	if (in_bit >= 0) {
93622017ed2SDouglas Gilbert 		sks[0] |= 0x8;
93722017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
93822017ed2SDouglas Gilbert 	}
93922017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
940773642d9SDouglas Gilbert 	if (sdebug_dsense) {
94122017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
94222017ed2SDouglas Gilbert 		sbuff[7] = sl;
94322017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
94422017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
94522017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
94622017ed2SDouglas Gilbert 	} else
94722017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
948773642d9SDouglas Gilbert 	if (sdebug_verbose)
94922017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
95022017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
95122017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
95222017ed2SDouglas Gilbert }
95322017ed2SDouglas Gilbert 
954cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9558dea0d02SFUJITA Tomonori {
9568dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
9578dea0d02SFUJITA Tomonori 
958cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
959cbf67842SDouglas Gilbert 	if (!sbuff) {
960cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
961cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
962cbf67842SDouglas Gilbert 		return;
963cbf67842SDouglas Gilbert 	}
964cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9658dea0d02SFUJITA Tomonori 
966773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9678dea0d02SFUJITA Tomonori 
968773642d9SDouglas Gilbert 	if (sdebug_verbose)
969cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
970cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
971cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9728dea0d02SFUJITA Tomonori }
9731da177e4SLinus Torvalds 
974fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
97522017ed2SDouglas Gilbert {
97622017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
97722017ed2SDouglas Gilbert }
97822017ed2SDouglas Gilbert 
9796f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9806f4e626fSNathan Chancellor 			    void __user *arg)
9811da177e4SLinus Torvalds {
982773642d9SDouglas Gilbert 	if (sdebug_verbose) {
983cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
984cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
985cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
986cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
987cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
988cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
989cbf67842SDouglas Gilbert 				    __func__);
990cbf67842SDouglas Gilbert 		else
991cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
992cbf67842SDouglas Gilbert 				    __func__, cmd);
9931da177e4SLinus Torvalds 	}
9941da177e4SLinus Torvalds 	return -EINVAL;
9951da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds 
9989b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
9999b760fd8SDouglas Gilbert {
10009b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10019b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10029b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10039b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10049b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10059b760fd8SDouglas Gilbert 		break;
10069b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10079b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10089b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10099b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10109b760fd8SDouglas Gilbert 		break;
10119b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10129b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10139b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10149b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10159b760fd8SDouglas Gilbert 		break;
10169b760fd8SDouglas Gilbert 	case 16:
10179b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10189b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10199b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10209b760fd8SDouglas Gilbert 		break;
10219b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10229b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10239b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10249b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10259b760fd8SDouglas Gilbert 		break;
10269b760fd8SDouglas Gilbert 	default:
10279b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10289b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10299b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10309b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10329b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10339b760fd8SDouglas Gilbert 		break;
10349b760fd8SDouglas Gilbert 	}
10359b760fd8SDouglas Gilbert }
10369b760fd8SDouglas Gilbert 
10379b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10389b760fd8SDouglas Gilbert {
10399b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10409b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10419b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10429b760fd8SDouglas Gilbert 
10439b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10449b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10459b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10469b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10479b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10489b760fd8SDouglas Gilbert 		}
10499b760fd8SDouglas Gilbert 	}
10509b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10519b760fd8SDouglas Gilbert }
10529b760fd8SDouglas Gilbert 
105319c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
105419c8ead7SEwan D. Milne {
105519c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
105619c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
105719c8ead7SEwan D. Milne 
105819c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
105919c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106019c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
106119c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
106219c8ead7SEwan D. Milne 			    (devip->target == dp->target))
106319c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
106419c8ead7SEwan D. Milne 		}
106519c8ead7SEwan D. Milne 	}
106619c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
106719c8ead7SEwan D. Milne }
106819c8ead7SEwan D. Milne 
1069f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10701da177e4SLinus Torvalds {
1071cbf67842SDouglas Gilbert 	int k;
1072cbf67842SDouglas Gilbert 
1073cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1074cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1075cbf67842SDouglas Gilbert 		const char *cp = NULL;
1076cbf67842SDouglas Gilbert 
1077cbf67842SDouglas Gilbert 		switch (k) {
1078cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1079f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1080f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1081773642d9SDouglas Gilbert 			if (sdebug_verbose)
1082cbf67842SDouglas Gilbert 				cp = "power on reset";
1083cbf67842SDouglas Gilbert 			break;
1084cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1085f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1086f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1087773642d9SDouglas Gilbert 			if (sdebug_verbose)
1088cbf67842SDouglas Gilbert 				cp = "bus reset";
1089cbf67842SDouglas Gilbert 			break;
1090cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1091f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1092f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1093773642d9SDouglas Gilbert 			if (sdebug_verbose)
1094cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1095cbf67842SDouglas Gilbert 			break;
10960d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1097f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1098f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1099773642d9SDouglas Gilbert 			if (sdebug_verbose)
11000d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1101f49accf1SEwan D. Milne 			break;
1102acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1103f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1104b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1105b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1106773642d9SDouglas Gilbert 			if (sdebug_verbose)
1107acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1108acafd0b9SEwan D. Milne 			break;
1109acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1110f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1111acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1112acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1113773642d9SDouglas Gilbert 			if (sdebug_verbose)
1114acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1115acafd0b9SEwan D. Milne 			break;
111619c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
111719c8ead7SEwan D. Milne 			/*
111819c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
111919c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
112019c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
112119c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1122773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
112319c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
112419c8ead7SEwan D. Milne 			 */
1125773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
112619c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1127f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
112819c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
112919c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1130773642d9SDouglas Gilbert 			if (sdebug_verbose)
113119c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
113219c8ead7SEwan D. Milne 			break;
1133cbf67842SDouglas Gilbert 		default:
1134773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1135773642d9SDouglas Gilbert 			if (sdebug_verbose)
1136cbf67842SDouglas Gilbert 				cp = "unknown";
1137cbf67842SDouglas Gilbert 			break;
1138cbf67842SDouglas Gilbert 		}
1139cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1140773642d9SDouglas Gilbert 		if (sdebug_verbose)
1141f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1142cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1143cbf67842SDouglas Gilbert 				   my_name, cp);
11441da177e4SLinus Torvalds 		return check_condition_result;
11451da177e4SLinus Torvalds 	}
11461da177e4SLinus Torvalds 	return 0;
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds 
1149fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11501da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11511da177e4SLinus Torvalds 				int arr_len)
11521da177e4SLinus Torvalds {
115321a61829SFUJITA Tomonori 	int act_len;
1154ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11551da177e4SLinus Torvalds 
1156072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11571da177e4SLinus Torvalds 		return 0;
1158ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1159773642d9SDouglas Gilbert 		return DID_ERROR << 16;
116021a61829SFUJITA Tomonori 
116121a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
116221a61829SFUJITA Tomonori 				      arr, arr_len);
116342d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
116421a61829SFUJITA Tomonori 
11651da177e4SLinus Torvalds 	return 0;
11661da177e4SLinus Torvalds }
11671da177e4SLinus Torvalds 
1168fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1169fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1170fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1171fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1172fb0cc8d1SDouglas Gilbert  */
1173fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1174fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1175fb0cc8d1SDouglas Gilbert {
11769237f04eSDamien Le Moal 	unsigned int act_len, n;
1177ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1178fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1179fb0cc8d1SDouglas Gilbert 
1180fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1181fb0cc8d1SDouglas Gilbert 		return 0;
1182ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1183fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1184fb0cc8d1SDouglas Gilbert 
1185fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1186fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1187fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
118842d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
118942d387beSBart Van Assche 		 scsi_get_resid(scp));
11909237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
119187c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1192fb0cc8d1SDouglas Gilbert 	return 0;
1193fb0cc8d1SDouglas Gilbert }
1194fb0cc8d1SDouglas Gilbert 
1195fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1196fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1197fb0cc8d1SDouglas Gilbert  */
11981da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
119921a61829SFUJITA Tomonori 			       int arr_len)
12001da177e4SLinus Torvalds {
120121a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12021da177e4SLinus Torvalds 		return 0;
1203ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12041da177e4SLinus Torvalds 		return -1;
120521a61829SFUJITA Tomonori 
120621a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12071da177e4SLinus Torvalds }
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 
1210e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1211e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12129b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12131b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12141b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12151b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12161b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12171da177e4SLinus Torvalds 
1218cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1219760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12205a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
122109ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1222bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12231da177e4SLinus Torvalds {
1224c65b1445SDouglas Gilbert 	int num, port_a;
1225c65b1445SDouglas Gilbert 	char b[32];
12261da177e4SLinus Torvalds 
1227c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12281da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12291da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12301da177e4SLinus Torvalds 	arr[1] = 0x1;
12311da177e4SLinus Torvalds 	arr[2] = 0x0;
1232e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1233e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12341da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12351da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12361da177e4SLinus Torvalds 	arr[3] = num;
12371da177e4SLinus Torvalds 	num += 4;
1238c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
123909ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
124009ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
124109ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
124209ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
124309ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124409ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
124509ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
124609ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124709ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
124809ba24c1SDouglas Gilbert 			num += 16;
124909ba24c1SDouglas Gilbert 		} else {
12501b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1251c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1252c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1253c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1254c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12551b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1256773642d9SDouglas Gilbert 			num += 8;
125709ba24c1SDouglas Gilbert 		}
1258c65b1445SDouglas Gilbert 		/* Target relative port number */
1259c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1260c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1261c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1262c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1263c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1264c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1265c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1266c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1267c65b1445SDouglas Gilbert 	}
12681b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1269c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1270c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1271c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1272c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12731b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1274773642d9SDouglas Gilbert 	num += 8;
12751b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12765a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12775a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12785a09e398SHannes Reinecke 	arr[num++] = 0x0;
12795a09e398SHannes Reinecke 	arr[num++] = 0x4;
12805a09e398SHannes Reinecke 	arr[num++] = 0;
12815a09e398SHannes Reinecke 	arr[num++] = 0;
1282773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1283773642d9SDouglas Gilbert 	num += 2;
12841b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1285c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1286c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1287c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1288c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12891b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1290773642d9SDouglas Gilbert 	num += 8;
1291c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1292c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1293c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1294c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1295c65b1445SDouglas Gilbert 	arr[num++] = 24;
12961b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1297c65b1445SDouglas Gilbert 	num += 12;
1298c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1299c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1300c65b1445SDouglas Gilbert 	num += 8;
1301c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1302c65b1445SDouglas Gilbert 	num += 4;
1303c65b1445SDouglas Gilbert 	return num;
1304c65b1445SDouglas Gilbert }
1305c65b1445SDouglas Gilbert 
1306c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1307c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1308c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1309c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1310c65b1445SDouglas Gilbert };
1311c65b1445SDouglas Gilbert 
1312cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1313760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1314c65b1445SDouglas Gilbert {
1315c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1316c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1317c65b1445SDouglas Gilbert }
1318c65b1445SDouglas Gilbert 
1319cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1320760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1321c65b1445SDouglas Gilbert {
1322c65b1445SDouglas Gilbert 	int num = 0;
1323c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1324c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1325c65b1445SDouglas Gilbert 	int plen, olen;
1326c65b1445SDouglas Gilbert 
1327c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1328c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1329c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1330c65b1445SDouglas Gilbert 	olen = strlen(na1);
1331c65b1445SDouglas Gilbert 	plen = olen + 1;
1332c65b1445SDouglas Gilbert 	if (plen % 4)
1333c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1334c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1335c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1336c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1337c65b1445SDouglas Gilbert 	num += plen;
1338c65b1445SDouglas Gilbert 
1339c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1340c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1341c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1342c65b1445SDouglas Gilbert 	olen = strlen(na2);
1343c65b1445SDouglas Gilbert 	plen = olen + 1;
1344c65b1445SDouglas Gilbert 	if (plen % 4)
1345c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1346c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1347c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1348c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1349c65b1445SDouglas Gilbert 	num += plen;
1350c65b1445SDouglas Gilbert 
1351c65b1445SDouglas Gilbert 	return num;
1352c65b1445SDouglas Gilbert }
1353c65b1445SDouglas Gilbert 
1354c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1355760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1356c65b1445SDouglas Gilbert {
1357c65b1445SDouglas Gilbert 	int num = 0;
1358c65b1445SDouglas Gilbert 	int port_a, port_b;
1359c65b1445SDouglas Gilbert 
1360c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1361c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1362c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1363c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1364c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1365c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1366c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1367c65b1445SDouglas Gilbert 	num += 6;
1368c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1369c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1370c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1371c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1372c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1374c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13751b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1376773642d9SDouglas Gilbert 	num += 8;
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1380c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1381c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1382c65b1445SDouglas Gilbert 	num += 6;
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1384c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1385c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1386c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1387c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1389c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1391773642d9SDouglas Gilbert 	num += 8;
1392c65b1445SDouglas Gilbert 
1393c65b1445SDouglas Gilbert 	return num;
1394c65b1445SDouglas Gilbert }
1395c65b1445SDouglas Gilbert 
1396c65b1445SDouglas Gilbert 
1397c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1398c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1399c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1400c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1401c65b1445SDouglas Gilbert '1','2','3','4',
1402c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1403c65b1445SDouglas Gilbert 0xec,0,0,0,
1404c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1405c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1406c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1407c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1408c65b1445SDouglas Gilbert 0x53,0x41,
1409c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1410c65b1445SDouglas Gilbert 0x20,0x20,
1411c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1412c65b1445SDouglas Gilbert 0x10,0x80,
1413c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1414c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1415c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1416c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1417c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1418c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1419c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1420c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,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 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1424c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1425c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1426c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1439c65b1445SDouglas Gilbert };
1440c65b1445SDouglas Gilbert 
1441cbf67842SDouglas Gilbert /* ATA Information VPD page */
1442760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1443c65b1445SDouglas Gilbert {
1444c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1445c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1446c65b1445SDouglas Gilbert }
1447c65b1445SDouglas Gilbert 
1448c65b1445SDouglas Gilbert 
1449c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14501e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14511e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
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,
1454c65b1445SDouglas Gilbert };
1455c65b1445SDouglas Gilbert 
1456cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1457760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1458c65b1445SDouglas Gilbert {
1459ea61fca5SMartin K. Petersen 	unsigned int gran;
1460ea61fca5SMartin K. Petersen 
1461c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1462e308b3d1SMartin K. Petersen 
1463e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
146486e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
146586e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
146686e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
146786e6828aSLukas Herbolt 	else
1468773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1469773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1470e308b3d1SMartin K. Petersen 
1471e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1472773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1473773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
147444d92694SMartin K. Petersen 
1475e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1476773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1477e308b3d1SMartin K. Petersen 
1478773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1479e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1480773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1481e308b3d1SMartin K. Petersen 
1482e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1483773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
148444d92694SMartin K. Petersen 	}
148544d92694SMartin K. Petersen 
1486e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1487773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1488773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
148944d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
149044d92694SMartin K. Petersen 	}
149144d92694SMartin K. Petersen 
1492e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1493773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14946014759cSMartin K. Petersen 
14955b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1496773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
14975b94e232SMartin K. Petersen 
14985b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
149944d92694SMartin K. Petersen 
1500c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15011da177e4SLinus Torvalds }
15021da177e4SLinus Torvalds 
15031e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
150464e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1505eac6e8e4SMatthew Wilcox {
1506eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1507eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15081e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15091e49f785SDouglas Gilbert 	arr[2] = 0;
15101e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
151164e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
151264e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1513eac6e8e4SMatthew Wilcox 
1514eac6e8e4SMatthew Wilcox 	return 0x3c;
1515eac6e8e4SMatthew Wilcox }
15161da177e4SLinus Torvalds 
1517760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1518760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15196014759cSMartin K. Petersen {
15203f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15216014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1522773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15236014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1524773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15256014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1526773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15275b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1528760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1529760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1530760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1531760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1532760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15333f0bc3b3SMartin K. Petersen 	return 0x4;
15346014759cSMartin K. Petersen }
15356014759cSMartin K. Petersen 
1536d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1537f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1538d36da305SDouglas Gilbert {
1539d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1540d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1541d36da305SDouglas Gilbert 	/*
1542d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1543d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1544f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1545f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1546d36da305SDouglas Gilbert 	 */
1547d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1548d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
154964e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1550f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1551f0d1cf93SDouglas Gilbert 	else
1552d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1553d36da305SDouglas Gilbert 	return 0x3c;
1554d36da305SDouglas Gilbert }
1555d36da305SDouglas Gilbert 
15561da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1557c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15581da177e4SLinus Torvalds 
1559c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15601da177e4SLinus Torvalds {
15611da177e4SLinus Torvalds 	unsigned char pq_pdt;
15625a09e398SHannes Reinecke 	unsigned char *arr;
156301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15645a09e398SHannes Reinecke 	int alloc_len, n, ret;
1565d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15661da177e4SLinus Torvalds 
1567773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15686f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15696f3cbf55SDouglas Gilbert 	if (! arr)
15706f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1571760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
157264e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1573d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1574b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1575c2248fc9SDouglas Gilbert 	if (have_wlun)
1576b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1577b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1578b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1579c65b1445SDouglas Gilbert 	else
1580773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15811da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15821da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
158322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15845a09e398SHannes Reinecke 		kfree(arr);
15851da177e4SLinus Torvalds 		return check_condition_result;
15861da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15875a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1588c65b1445SDouglas Gilbert 		char lu_id_str[6];
1589c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
15901da177e4SLinus Torvalds 
15915a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
15925a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1593b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
159423183910SDouglas Gilbert 			host_no = 0;
1595c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1596c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1597c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1598c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1599c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16001da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1601c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1602c65b1445SDouglas Gilbert 			n = 4;
1603c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1604c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1605c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1606c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1607c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1608c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1609c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1610c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1611d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1612c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1613760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1614760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1615d36da305SDouglas Gilbert 				if (is_disk)
1616d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
161764e14eceSDamien Le Moal 				if (is_zbc)
1618d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1619760f3b03SDouglas Gilbert 			}
1620c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16211da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1622c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16231da177e4SLinus Torvalds 			arr[3] = len;
1624c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16251da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1626c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1627760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16285a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
162909ba24c1SDouglas Gilbert 						lu_id_str, len,
163009ba24c1SDouglas Gilbert 						&devip->lu_name);
1631c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1632c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1633760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1634c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1635c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1636760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1637c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1638c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1639c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16408475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1641c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1642760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1643c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1644c6a44287SMartin K. Petersen 			else
1645c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1646c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1647c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1648c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1649c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1650c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1651c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1652c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1653c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1654c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1655c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1656760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1657d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1658c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1659760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1660773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1661d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1662c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1663760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1664d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1665eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
166664e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1667760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16686014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1669760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1670d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1671d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1672f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16731da177e4SLinus Torvalds 		} else {
167422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16755a09e398SHannes Reinecke 			kfree(arr);
16761da177e4SLinus Torvalds 			return check_condition_result;
16771da177e4SLinus Torvalds 		}
1678773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
16795a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1680c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
16815a09e398SHannes Reinecke 		kfree(arr);
16825a09e398SHannes Reinecke 		return ret;
16831da177e4SLinus Torvalds 	}
16841da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1685773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1686773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16871da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16881da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1689f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1690b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
169170bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1692c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
16931da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1694c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1695e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1696e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1697e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
16989b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
16999b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17001da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1701760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1702760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1703c65b1445SDouglas Gilbert 	n = 62;
1704760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1705760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1706760f3b03SDouglas Gilbert 		n += 2;
1707760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1708760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1709760f3b03SDouglas Gilbert 		n += 2;
1710d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1711d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1712d36da305SDouglas Gilbert 		n += 2;
17131da177e4SLinus Torvalds 	}
1714760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17155a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
171687c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
17175a09e398SHannes Reinecke 	kfree(arr);
17185a09e398SHannes Reinecke 	return ret;
17191da177e4SLinus Torvalds }
17201da177e4SLinus Torvalds 
172184905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1722fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1723fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1724fd32119bSDouglas Gilbert 
17251da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17261da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17271da177e4SLinus Torvalds {
172801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
172984905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
173084905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
173184905d34SDouglas Gilbert 	int alloc_len = cmd[4];
17321da177e4SLinus Torvalds 	int len = 18;
173384905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17341da177e4SLinus Torvalds 
1735c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
173684905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
173784905d34SDouglas Gilbert 		if (dsense) {
173884905d34SDouglas Gilbert 			arr[0] = 0x72;
173984905d34SDouglas Gilbert 			arr[1] = NOT_READY;
174084905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
174184905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
174284905d34SDouglas Gilbert 			len = 8;
174384905d34SDouglas Gilbert 		} else {
174484905d34SDouglas Gilbert 			arr[0] = 0x70;
174584905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
174684905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
174784905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
174884905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
174984905d34SDouglas Gilbert 		}
175084905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
175184905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1752c2248fc9SDouglas Gilbert 		if (dsense) {
1753c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1754c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1755c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
175684905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1757c2248fc9SDouglas Gilbert 			len = 8;
1758c65b1445SDouglas Gilbert 		} else {
1759c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1760c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1761c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1762c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
176384905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1764c65b1445SDouglas Gilbert 		}
176584905d34SDouglas Gilbert 	} else {	/* nothing to report */
1766c2248fc9SDouglas Gilbert 		if (dsense) {
1767c2248fc9SDouglas Gilbert 			len = 8;
176884905d34SDouglas Gilbert 			memset(arr, 0, len);
176984905d34SDouglas Gilbert 			arr[0] = 0x72;
1770c2248fc9SDouglas Gilbert 		} else {
177184905d34SDouglas Gilbert 			memset(arr, 0, len);
1772c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1773c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1774c2248fc9SDouglas Gilbert 		}
1775c65b1445SDouglas Gilbert 	}
177684905d34SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
17771da177e4SLinus Torvalds }
17781da177e4SLinus Torvalds 
1779fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1780c65b1445SDouglas Gilbert {
178101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1782fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
17834f2c8bf6SDouglas Gilbert 	bool changing;
1784c65b1445SDouglas Gilbert 
1785c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1786c65b1445SDouglas Gilbert 	if (power_cond) {
178722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1788c65b1445SDouglas Gilbert 		return check_condition_result;
1789c65b1445SDouglas Gilbert 	}
1790fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1791fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1792fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1793fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1794fc13638aSDouglas Gilbert 
1795fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1796fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1797fc13638aSDouglas Gilbert 
1798fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1799fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1800fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1801fc13638aSDouglas Gilbert 				stopped_state = 0;
1802fc13638aSDouglas Gilbert 			}
1803fc13638aSDouglas Gilbert 		}
1804fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1805fc13638aSDouglas Gilbert 			if (want_stop) {
1806fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1807fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1808fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1809fc13638aSDouglas Gilbert 				return check_condition_result;
1810fc13638aSDouglas Gilbert 			}
1811fc13638aSDouglas Gilbert 		}
1812fc13638aSDouglas Gilbert 	}
1813fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1814fc13638aSDouglas Gilbert 	if (changing)
1815fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1816fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18174f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18184f2c8bf6SDouglas Gilbert 	else
18194f2c8bf6SDouglas Gilbert 		return 0;
1820c65b1445SDouglas Gilbert }
1821c65b1445SDouglas Gilbert 
182228898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
182328898873SFUJITA Tomonori {
1824773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1825773642d9SDouglas Gilbert 
1826773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1827773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1828773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
182928898873SFUJITA Tomonori 	else
183028898873SFUJITA Tomonori 		return sdebug_store_sectors;
183128898873SFUJITA Tomonori }
183228898873SFUJITA Tomonori 
18331da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18341da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18351da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18361da177e4SLinus Torvalds {
18371da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1838c65b1445SDouglas Gilbert 	unsigned int capac;
18391da177e4SLinus Torvalds 
1840c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
184128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18421da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1843c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1844c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1845773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1846773642d9SDouglas Gilbert 	} else
1847773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1848773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18491da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds 
1852c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1853c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1854c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1855c65b1445SDouglas Gilbert {
185601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1857c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1858773642d9SDouglas Gilbert 	int alloc_len;
1859c65b1445SDouglas Gilbert 
1860773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1861c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1863c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1864773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1865773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1866773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1867773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
186844d92694SMartin K. Petersen 
1869be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18705b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1871760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1872760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1873760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1874760f3b03SDouglas Gilbert 		 */
1875760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1876760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1877be1dd78dSEric Sandeen 	}
187844d92694SMartin K. Petersen 
1879773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1880c6a44287SMartin K. Petersen 
1881760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1882773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1883c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1884c6a44287SMartin K. Petersen 	}
1885c6a44287SMartin K. Petersen 
1886c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
188787c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1888c65b1445SDouglas Gilbert }
1889c65b1445SDouglas Gilbert 
18905a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18915a09e398SHannes Reinecke 
18925a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18935a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18945a09e398SHannes Reinecke {
189501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
18965a09e398SHannes Reinecke 	unsigned char *arr;
18975a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
18985a09e398SHannes Reinecke 	int n, ret, alen, rlen;
18995a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
19005a09e398SHannes Reinecke 
1901773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19026f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19036f3cbf55SDouglas Gilbert 	if (! arr)
19046f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19055a09e398SHannes Reinecke 	/*
19065a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19075a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19085a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19095a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19105a09e398SHannes Reinecke 	 */
19115a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19125a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19135a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19145a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19155a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19165a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19175a09e398SHannes Reinecke 
19185a09e398SHannes Reinecke 	/*
19195a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19205a09e398SHannes Reinecke 	 */
19215a09e398SHannes Reinecke 	n = 4;
1922b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19235a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19245a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19255a09e398SHannes Reinecke 	} else {
19265a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1927773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19285a09e398SHannes Reinecke 	}
1929773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1930773642d9SDouglas Gilbert 	n += 2;
19315a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19325a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19335a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19345a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1937773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1938773642d9SDouglas Gilbert 	n += 2;
19395a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19405a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1941773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1942773642d9SDouglas Gilbert 	n += 2;
19435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19455a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19465a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1949773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1950773642d9SDouglas Gilbert 	n += 2;
19515a09e398SHannes Reinecke 
19525a09e398SHannes Reinecke 	rlen = n - 4;
1953773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19545a09e398SHannes Reinecke 
19555a09e398SHannes Reinecke 	/*
19565a09e398SHannes Reinecke 	 * Return the smallest value of either
19575a09e398SHannes Reinecke 	 * - The allocated length
19585a09e398SHannes Reinecke 	 * - The constructed command length
19595a09e398SHannes Reinecke 	 * - The maximum array size
19605a09e398SHannes Reinecke 	 */
196187c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
19625a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
196387c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19645a09e398SHannes Reinecke 	kfree(arr);
19655a09e398SHannes Reinecke 	return ret;
19665a09e398SHannes Reinecke }
19675a09e398SHannes Reinecke 
1968fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1969fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
197038d5c833SDouglas Gilbert {
197138d5c833SDouglas Gilbert 	bool rctd;
197238d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
197338d5c833SDouglas Gilbert 	u16 req_sa, u;
197438d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
197538d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
197638d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
197738d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
197838d5c833SDouglas Gilbert 	u8 *arr;
197938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
198038d5c833SDouglas Gilbert 
198138d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
198238d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
198338d5c833SDouglas Gilbert 	req_opcode = cmd[3];
198438d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
198538d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19866d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
198738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
198838d5c833SDouglas Gilbert 		return check_condition_result;
198938d5c833SDouglas Gilbert 	}
199038d5c833SDouglas Gilbert 	if (alloc_len > 8192)
199138d5c833SDouglas Gilbert 		a_len = 8192;
199238d5c833SDouglas Gilbert 	else
199338d5c833SDouglas Gilbert 		a_len = alloc_len;
199499531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
199538d5c833SDouglas Gilbert 	if (NULL == arr) {
199638d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
199738d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
199838d5c833SDouglas Gilbert 		return check_condition_result;
199938d5c833SDouglas Gilbert 	}
200038d5c833SDouglas Gilbert 	switch (reporting_opts) {
200138d5c833SDouglas Gilbert 	case 0:	/* all commands */
200238d5c833SDouglas Gilbert 		/* count number of commands */
200338d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
200438d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
200538d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
200638d5c833SDouglas Gilbert 				continue;
200738d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
200838d5c833SDouglas Gilbert 		}
200938d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
201038d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
201138d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
201238d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
201338d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
201438d5c833SDouglas Gilbert 				continue;
201538d5c833SDouglas Gilbert 			na = oip->num_attached;
201638d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
201738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
201838d5c833SDouglas Gilbert 			if (rctd)
201938d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
202038d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
202138d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
202238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
202338d5c833SDouglas Gilbert 			if (rctd)
202438d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
202538d5c833SDouglas Gilbert 			r_oip = oip;
202638d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
202738d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
202838d5c833SDouglas Gilbert 					continue;
202938d5c833SDouglas Gilbert 				offset += bump;
203038d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
203138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
203238d5c833SDouglas Gilbert 				if (rctd)
203338d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
203438d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
203538d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
203638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
203738d5c833SDouglas Gilbert 						   arr + offset + 6);
203838d5c833SDouglas Gilbert 				if (rctd)
203938d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
204038d5c833SDouglas Gilbert 							   arr + offset + 8);
204138d5c833SDouglas Gilbert 			}
204238d5c833SDouglas Gilbert 			oip = r_oip;
204338d5c833SDouglas Gilbert 			offset += bump;
204438d5c833SDouglas Gilbert 		}
204538d5c833SDouglas Gilbert 		break;
204638d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
204738d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
204838d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
204938d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
205038d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
205138d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
205238d5c833SDouglas Gilbert 			supp = 1;
205338d5c833SDouglas Gilbert 			offset = 4;
205438d5c833SDouglas Gilbert 		} else {
205538d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
205638d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
205738d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
205838d5c833SDouglas Gilbert 							     2, 2);
205938d5c833SDouglas Gilbert 					kfree(arr);
206038d5c833SDouglas Gilbert 					return check_condition_result;
206138d5c833SDouglas Gilbert 				}
206238d5c833SDouglas Gilbert 				req_sa = 0;
206338d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
206438d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
206538d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
206638d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
206738d5c833SDouglas Gilbert 				return check_condition_result;
206838d5c833SDouglas Gilbert 			}
206938d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
207038d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
207138d5c833SDouglas Gilbert 				supp = 3;
207238d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
207338d5c833SDouglas Gilbert 				na = oip->num_attached;
207438d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
207538d5c833SDouglas Gilbert 				     ++k, ++oip) {
207638d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
207738d5c833SDouglas Gilbert 						break;
207838d5c833SDouglas Gilbert 				}
207938d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208038d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
208138d5c833SDouglas Gilbert 				na = oip->num_attached;
208238d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
208338d5c833SDouglas Gilbert 				     ++k, ++oip) {
208438d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
208538d5c833SDouglas Gilbert 						break;
208638d5c833SDouglas Gilbert 				}
208738d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208838d5c833SDouglas Gilbert 			} else
208938d5c833SDouglas Gilbert 				supp = 3;
209038d5c833SDouglas Gilbert 			if (3 == supp) {
209138d5c833SDouglas Gilbert 				u = oip->len_mask[0];
209238d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
209338d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
209438d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
209538d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
209638d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
209738d5c833SDouglas Gilbert 				offset = 4 + u;
209838d5c833SDouglas Gilbert 			} else
209938d5c833SDouglas Gilbert 				offset = 4;
210038d5c833SDouglas Gilbert 		}
210138d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
210238d5c833SDouglas Gilbert 		if (rctd) {
210338d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
210438d5c833SDouglas Gilbert 			offset += 12;
210538d5c833SDouglas Gilbert 		}
210638d5c833SDouglas Gilbert 		break;
210738d5c833SDouglas Gilbert 	default:
210838d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
210938d5c833SDouglas Gilbert 		kfree(arr);
211038d5c833SDouglas Gilbert 		return check_condition_result;
211138d5c833SDouglas Gilbert 	}
211238d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
211338d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
211438d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
211538d5c833SDouglas Gilbert 	kfree(arr);
211638d5c833SDouglas Gilbert 	return errsts;
211738d5c833SDouglas Gilbert }
211838d5c833SDouglas Gilbert 
2119fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2120fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
212138d5c833SDouglas Gilbert {
212238d5c833SDouglas Gilbert 	bool repd;
212338d5c833SDouglas Gilbert 	u32 alloc_len, len;
212438d5c833SDouglas Gilbert 	u8 arr[16];
212538d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
212638d5c833SDouglas Gilbert 
212738d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
212838d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
212938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
213038d5c833SDouglas Gilbert 	if (alloc_len < 4) {
213138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
213238d5c833SDouglas Gilbert 		return check_condition_result;
213338d5c833SDouglas Gilbert 	}
213438d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
213538d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
213638d5c833SDouglas Gilbert 	if (repd) {
213738d5c833SDouglas Gilbert 		arr[3] = 0xc;
213838d5c833SDouglas Gilbert 		len = 16;
213938d5c833SDouglas Gilbert 	} else
214038d5c833SDouglas Gilbert 		len = 4;
214138d5c833SDouglas Gilbert 
214238d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
214338d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
214438d5c833SDouglas Gilbert }
214538d5c833SDouglas Gilbert 
21461da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21491da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21501da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21511da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21521da177e4SLinus Torvalds 
21531da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21541da177e4SLinus Torvalds 	if (1 == pcontrol)
21551da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21561da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21571da177e4SLinus Torvalds }
21581da177e4SLinus Torvalds 
21591da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21601da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21611da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21621da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21651da177e4SLinus Torvalds 	if (1 == pcontrol)
21661da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21671da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21681da177e4SLinus Torvalds }
21691da177e4SLinus Torvalds 
21701da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21711da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21721da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21731da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21741da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21751da177e4SLinus Torvalds 
21761da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2177773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2178773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2179773642d9SDouglas Gilbert 	if (sdebug_removable)
21801da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21811da177e4SLinus Torvalds 	if (1 == pcontrol)
21821da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21831da177e4SLinus Torvalds 	return sizeof(format_pg);
21841da177e4SLinus Torvalds }
21851da177e4SLinus Torvalds 
2186fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2187fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2188fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2189fd32119bSDouglas Gilbert 
21901da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21911da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2192cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2193cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2194cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21951da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
21961da177e4SLinus Torvalds 
2197773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2198cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
21991da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22001da177e4SLinus Torvalds 	if (1 == pcontrol)
2201cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2202cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2203cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22041da177e4SLinus Torvalds 	return sizeof(caching_pg);
22051da177e4SLinus Torvalds }
22061da177e4SLinus Torvalds 
2207fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2208fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2209fd32119bSDouglas Gilbert 
22101da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22111da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2212c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2213c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2214c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22151da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22161da177e4SLinus Torvalds 
2217773642d9SDouglas Gilbert 	if (sdebug_dsense)
22181da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2219c65b1445SDouglas Gilbert 	else
2220c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2221c6a44287SMartin K. Petersen 
2222773642d9SDouglas Gilbert 	if (sdebug_ato)
2223c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2224c6a44287SMartin K. Petersen 
22251da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22261da177e4SLinus Torvalds 	if (1 == pcontrol)
2227c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2228c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2229c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22301da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22311da177e4SLinus Torvalds }
22321da177e4SLinus Torvalds 
2233c65b1445SDouglas Gilbert 
22341da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22351da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2236c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22371da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2238c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2239c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2240c65b1445SDouglas Gilbert 
22411da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22421da177e4SLinus Torvalds 	if (1 == pcontrol)
2243c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2244c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2245c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22461da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22471da177e4SLinus Torvalds }
22481da177e4SLinus Torvalds 
2249c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2250c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2251c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2252c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2253c65b1445SDouglas Gilbert 
2254c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2255c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2256c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2257c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2258c65b1445SDouglas Gilbert }
2259c65b1445SDouglas Gilbert 
2260c65b1445SDouglas Gilbert 
2261c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2262c65b1445SDouglas Gilbert 			      int target_dev_id)
2263c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2264c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2265c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2266773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2267773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2268c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2269c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2270c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2271c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2272773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2273773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2274c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2275c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2276c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2277c65b1445SDouglas Gilbert 		};
2278c65b1445SDouglas Gilbert 	int port_a, port_b;
2279c65b1445SDouglas Gilbert 
22801b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22811b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22821b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22831b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2284c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2285c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2286c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2287773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2288773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2289c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2290c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2291c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2292c65b1445SDouglas Gilbert }
2293c65b1445SDouglas Gilbert 
2294c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2295c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2296c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2297c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2298c65b1445SDouglas Gilbert 		};
2299c65b1445SDouglas Gilbert 
2300c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2301c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2302c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2303c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2304c65b1445SDouglas Gilbert }
2305c65b1445SDouglas Gilbert 
23061da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23071da177e4SLinus Torvalds 
2308fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2309fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23101da177e4SLinus Torvalds {
231123183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23121da177e4SLinus Torvalds 	unsigned char dev_spec;
2313760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2314c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23151da177e4SLinus Torvalds 	unsigned char *ap;
23161da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
231701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2318d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23191da177e4SLinus Torvalds 
2320760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23211da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23221da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23231da177e4SLinus Torvalds 	subpcode = cmd[3];
23241da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2325760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2326760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
232764e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2328d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
232923183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
233023183910SDouglas Gilbert 	else
233123183910SDouglas Gilbert 		bd_len = 0;
2332773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23331da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23341da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2335cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23361da177e4SLinus Torvalds 		return check_condition_result;
23371da177e4SLinus Torvalds 	}
2338c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2339c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2340d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2341d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2342b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23439447b6ceSMartin K. Petersen 		if (sdebug_wp)
23449447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23459447b6ceSMartin K. Petersen 	} else
234623183910SDouglas Gilbert 		dev_spec = 0x0;
23471da177e4SLinus Torvalds 	if (msense_6) {
23481da177e4SLinus Torvalds 		arr[2] = dev_spec;
234923183910SDouglas Gilbert 		arr[3] = bd_len;
23501da177e4SLinus Torvalds 		offset = 4;
23511da177e4SLinus Torvalds 	} else {
23521da177e4SLinus Torvalds 		arr[3] = dev_spec;
235323183910SDouglas Gilbert 		if (16 == bd_len)
235423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
235523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23561da177e4SLinus Torvalds 		offset = 8;
23571da177e4SLinus Torvalds 	}
23581da177e4SLinus Torvalds 	ap = arr + offset;
235928898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
236028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
236128898873SFUJITA Tomonori 
236223183910SDouglas Gilbert 	if (8 == bd_len) {
2363773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2364773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2365773642d9SDouglas Gilbert 		else
2366773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2367773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
236823183910SDouglas Gilbert 		offset += bd_len;
236923183910SDouglas Gilbert 		ap = arr + offset;
237023183910SDouglas Gilbert 	} else if (16 == bd_len) {
2371773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2372773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
237323183910SDouglas Gilbert 		offset += bd_len;
237423183910SDouglas Gilbert 		ap = arr + offset;
237523183910SDouglas Gilbert 	}
23761da177e4SLinus Torvalds 
2377c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2378c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
237922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23801da177e4SLinus Torvalds 		return check_condition_result;
23811da177e4SLinus Torvalds 	}
2382760f3b03SDouglas Gilbert 	bad_pcode = false;
2383760f3b03SDouglas Gilbert 
23841da177e4SLinus Torvalds 	switch (pcode) {
23851da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23861da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23871da177e4SLinus Torvalds 		offset += len;
23881da177e4SLinus Torvalds 		break;
23891da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23901da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23911da177e4SLinus Torvalds 		offset += len;
23921da177e4SLinus Torvalds 		break;
23931da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2394760f3b03SDouglas Gilbert 		if (is_disk) {
23951da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
23961da177e4SLinus Torvalds 			offset += len;
2397760f3b03SDouglas Gilbert 		} else
2398760f3b03SDouglas Gilbert 			bad_pcode = true;
23991da177e4SLinus Torvalds 		break;
24001da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2401d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24021da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24031da177e4SLinus Torvalds 			offset += len;
2404760f3b03SDouglas Gilbert 		} else
2405760f3b03SDouglas Gilbert 			bad_pcode = true;
24061da177e4SLinus Torvalds 		break;
24071da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24081da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24091da177e4SLinus Torvalds 		offset += len;
24101da177e4SLinus Torvalds 		break;
2411c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2412c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
241322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2414c65b1445SDouglas Gilbert 			return check_condition_result;
2415c65b1445SDouglas Gilbert 		}
2416c65b1445SDouglas Gilbert 		len = 0;
2417c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2418c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2419c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2420c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2421c65b1445SDouglas Gilbert 						  target_dev_id);
2422c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2423c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2424c65b1445SDouglas Gilbert 		offset += len;
2425c65b1445SDouglas Gilbert 		break;
24261da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24271da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24281da177e4SLinus Torvalds 		offset += len;
24291da177e4SLinus Torvalds 		break;
24301da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2431c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24321da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24331da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2434760f3b03SDouglas Gilbert 			if (is_disk) {
2435760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2436760f3b03SDouglas Gilbert 						      target);
2437760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2438760f3b03SDouglas Gilbert 						       target);
2439d36da305SDouglas Gilbert 			} else if (is_zbc) {
2440d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2441d36da305SDouglas Gilbert 						       target);
2442760f3b03SDouglas Gilbert 			}
24431da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2444c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2445c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2446c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2447c65b1445SDouglas Gilbert 						  target, target_dev_id);
2448c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2449c65b1445SDouglas Gilbert 			}
24501da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2451760f3b03SDouglas Gilbert 			offset += len;
2452c65b1445SDouglas Gilbert 		} else {
245322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2454c65b1445SDouglas Gilbert 			return check_condition_result;
2455c65b1445SDouglas Gilbert 		}
24561da177e4SLinus Torvalds 		break;
24571da177e4SLinus Torvalds 	default:
2458760f3b03SDouglas Gilbert 		bad_pcode = true;
2459760f3b03SDouglas Gilbert 		break;
2460760f3b03SDouglas Gilbert 	}
2461760f3b03SDouglas Gilbert 	if (bad_pcode) {
246222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24631da177e4SLinus Torvalds 		return check_condition_result;
24641da177e4SLinus Torvalds 	}
24651da177e4SLinus Torvalds 	if (msense_6)
24661da177e4SLinus Torvalds 		arr[0] = offset - 1;
2467773642d9SDouglas Gilbert 	else
2468773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
246987c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24701da177e4SLinus Torvalds }
24711da177e4SLinus Torvalds 
2472c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2473c65b1445SDouglas Gilbert 
2474fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2475fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2476c65b1445SDouglas Gilbert {
2477c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2478c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2479c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
248001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2481c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2482c65b1445SDouglas Gilbert 
2483c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2484c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2485c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2486773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2487c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
248822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2489c65b1445SDouglas Gilbert 		return check_condition_result;
2490c65b1445SDouglas Gilbert 	}
2491c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2492c65b1445SDouglas Gilbert 	if (-1 == res)
2493773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2494773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2495cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2496cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2497cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2498773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2499773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
250023183910SDouglas Gilbert 	if (md_len > 2) {
250122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2502c65b1445SDouglas Gilbert 		return check_condition_result;
2503c65b1445SDouglas Gilbert 	}
2504c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2505c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2506c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2507c65b1445SDouglas Gilbert 	if (ps) {
250822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2509c65b1445SDouglas Gilbert 		return check_condition_result;
2510c65b1445SDouglas Gilbert 	}
2511c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2512773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2513c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2514c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2515cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2516c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2517c65b1445SDouglas Gilbert 		return check_condition_result;
2518c65b1445SDouglas Gilbert 	}
2519c65b1445SDouglas Gilbert 	switch (mpage) {
2520cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2521cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2522cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2523cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2524cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2525cbf67842SDouglas Gilbert 		}
2526cbf67842SDouglas Gilbert 		break;
2527c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2528c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2529c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2530c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25319447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25329447b6ceSMartin K. Petersen 				sdebug_wp = true;
25339447b6ceSMartin K. Petersen 			else
25349447b6ceSMartin K. Petersen 				sdebug_wp = false;
2535773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2536cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2537c65b1445SDouglas Gilbert 		}
2538c65b1445SDouglas Gilbert 		break;
2539c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2540c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2541c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2542c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2543cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2544c65b1445SDouglas Gilbert 		}
2545c65b1445SDouglas Gilbert 		break;
2546c65b1445SDouglas Gilbert 	default:
2547c65b1445SDouglas Gilbert 		break;
2548c65b1445SDouglas Gilbert 	}
254922017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2550c65b1445SDouglas Gilbert 	return check_condition_result;
2551cbf67842SDouglas Gilbert set_mode_changed_ua:
2552cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2553cbf67842SDouglas Gilbert 	return 0;
2554c65b1445SDouglas Gilbert }
2555c65b1445SDouglas Gilbert 
2556c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2557c65b1445SDouglas Gilbert {
2558c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2559c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2560c65b1445SDouglas Gilbert 		};
2561c65b1445SDouglas Gilbert 
2562c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2563c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2564c65b1445SDouglas Gilbert }
2565c65b1445SDouglas Gilbert 
2566c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2567c65b1445SDouglas Gilbert {
2568c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2569c65b1445SDouglas Gilbert 		};
2570c65b1445SDouglas Gilbert 
2571c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2572c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2573c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2574c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2575c65b1445SDouglas Gilbert 	}
2576c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2577c65b1445SDouglas Gilbert }
2578c65b1445SDouglas Gilbert 
2579c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2580c65b1445SDouglas Gilbert 
2581c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2582c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2583c65b1445SDouglas Gilbert {
2584ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2585c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
258601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2587c65b1445SDouglas Gilbert 
2588c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2589c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2590c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2591c65b1445SDouglas Gilbert 	if (ppc || sp) {
259222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2593c65b1445SDouglas Gilbert 		return check_condition_result;
2594c65b1445SDouglas Gilbert 	}
2595c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
259623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2597773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2598c65b1445SDouglas Gilbert 	arr[0] = pcode;
259923183910SDouglas Gilbert 	if (0 == subpcode) {
2600c65b1445SDouglas Gilbert 		switch (pcode) {
2601c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2602c65b1445SDouglas Gilbert 			n = 4;
2603c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2604c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2605c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2606c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2607c65b1445SDouglas Gilbert 			break;
2608c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2609c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2610c65b1445SDouglas Gilbert 			break;
2611c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2612c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2613c65b1445SDouglas Gilbert 			break;
2614c65b1445SDouglas Gilbert 		default:
261522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2616c65b1445SDouglas Gilbert 			return check_condition_result;
2617c65b1445SDouglas Gilbert 		}
261823183910SDouglas Gilbert 	} else if (0xff == subpcode) {
261923183910SDouglas Gilbert 		arr[0] |= 0x40;
262023183910SDouglas Gilbert 		arr[1] = subpcode;
262123183910SDouglas Gilbert 		switch (pcode) {
262223183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
262323183910SDouglas Gilbert 			n = 4;
262423183910SDouglas Gilbert 			arr[n++] = 0x0;
262523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
262623183910SDouglas Gilbert 			arr[n++] = 0x0;
262723183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
262823183910SDouglas Gilbert 			arr[n++] = 0xd;
262923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
263023183910SDouglas Gilbert 			arr[n++] = 0x2f;
263123183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
263223183910SDouglas Gilbert 			arr[3] = n - 4;
263323183910SDouglas Gilbert 			break;
263423183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
263523183910SDouglas Gilbert 			n = 4;
263623183910SDouglas Gilbert 			arr[n++] = 0xd;
263723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
263823183910SDouglas Gilbert 			arr[3] = n - 4;
263923183910SDouglas Gilbert 			break;
264023183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
264123183910SDouglas Gilbert 			n = 4;
264223183910SDouglas Gilbert 			arr[n++] = 0x2f;
264323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
264423183910SDouglas Gilbert 			arr[3] = n - 4;
264523183910SDouglas Gilbert 			break;
264623183910SDouglas Gilbert 		default:
264722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
264823183910SDouglas Gilbert 			return check_condition_result;
264923183910SDouglas Gilbert 		}
265023183910SDouglas Gilbert 	} else {
265122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
265223183910SDouglas Gilbert 		return check_condition_result;
265323183910SDouglas Gilbert 	}
265487c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2655c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
265687c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2657c65b1445SDouglas Gilbert }
2658c65b1445SDouglas Gilbert 
2659f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2660f0d1cf93SDouglas Gilbert {
2661f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2662f0d1cf93SDouglas Gilbert }
2663f0d1cf93SDouglas Gilbert 
2664f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2665f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2666f0d1cf93SDouglas Gilbert {
2667108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2668f0d1cf93SDouglas Gilbert }
2669f0d1cf93SDouglas Gilbert 
2670f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2671f0d1cf93SDouglas Gilbert {
267264e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2673f0d1cf93SDouglas Gilbert }
2674f0d1cf93SDouglas Gilbert 
2675f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2676f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2677f0d1cf93SDouglas Gilbert {
2678f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2679f0d1cf93SDouglas Gilbert 
2680f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2681f0d1cf93SDouglas Gilbert 		return;
2682f0d1cf93SDouglas Gilbert 
2683f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2684f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2685f0d1cf93SDouglas Gilbert 		return;
2686f0d1cf93SDouglas Gilbert 
2687f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2688f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2689f0d1cf93SDouglas Gilbert 	else
2690f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2691f0d1cf93SDouglas Gilbert 
2692f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2693f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2694f0d1cf93SDouglas Gilbert 	} else {
2695f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2696f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2697f0d1cf93SDouglas Gilbert 	}
2698f0d1cf93SDouglas Gilbert }
2699f0d1cf93SDouglas Gilbert 
2700f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2701f0d1cf93SDouglas Gilbert {
2702f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2703f0d1cf93SDouglas Gilbert 	unsigned int i;
2704f0d1cf93SDouglas Gilbert 
2705f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2706f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2707f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2708f0d1cf93SDouglas Gilbert 			return;
2709f0d1cf93SDouglas Gilbert 		}
2710f0d1cf93SDouglas Gilbert 	}
2711f0d1cf93SDouglas Gilbert }
2712f0d1cf93SDouglas Gilbert 
2713f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2714f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2715f0d1cf93SDouglas Gilbert {
2716f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2717f0d1cf93SDouglas Gilbert 
2718f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2719f0d1cf93SDouglas Gilbert 		return;
2720f0d1cf93SDouglas Gilbert 
2721f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2722f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2723f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2724f0d1cf93SDouglas Gilbert 		return;
2725f0d1cf93SDouglas Gilbert 
2726f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2727f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2728f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2729f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2730f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2731f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2732f0d1cf93SDouglas Gilbert 
2733f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2734f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2735f0d1cf93SDouglas Gilbert 	if (explicit) {
2736f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2737f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2738f0d1cf93SDouglas Gilbert 	} else {
2739f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2740f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2741f0d1cf93SDouglas Gilbert 	}
2742f0d1cf93SDouglas Gilbert }
2743f0d1cf93SDouglas Gilbert 
2744f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2745f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2746f0d1cf93SDouglas Gilbert {
2747f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
274864e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2749f0d1cf93SDouglas Gilbert 
2750f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2751f0d1cf93SDouglas Gilbert 		return;
2752f0d1cf93SDouglas Gilbert 
275364e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2754f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
275564e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2756f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
275764e14eceSDamien Le Moal 		return;
275864e14eceSDamien Le Moal 	}
275964e14eceSDamien Le Moal 
276064e14eceSDamien Le Moal 	while (num) {
276164e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
276264e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
276364e14eceSDamien Le Moal 
276464e14eceSDamien Le Moal 		end = lba + num;
276564e14eceSDamien Le Moal 		if (end >= zend) {
276664e14eceSDamien Le Moal 			n = zend - lba;
276764e14eceSDamien Le Moal 			zsp->z_wp = zend;
276864e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
276964e14eceSDamien Le Moal 			n = num;
277064e14eceSDamien Le Moal 			zsp->z_wp = end;
277164e14eceSDamien Le Moal 		} else {
277264e14eceSDamien Le Moal 			n = num;
277364e14eceSDamien Le Moal 		}
277464e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
277564e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
277664e14eceSDamien Le Moal 
277764e14eceSDamien Le Moal 		num -= n;
277864e14eceSDamien Le Moal 		lba += n;
277964e14eceSDamien Le Moal 		if (num) {
278064e14eceSDamien Le Moal 			zsp++;
278164e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
278264e14eceSDamien Le Moal 		}
278364e14eceSDamien Le Moal 	}
2784f0d1cf93SDouglas Gilbert }
2785f0d1cf93SDouglas Gilbert 
2786f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27879447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27881da177e4SLinus Torvalds {
2789f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2790f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2791f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2792f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2793f0d1cf93SDouglas Gilbert 
2794f0d1cf93SDouglas Gilbert 	if (!write) {
279564e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
279664e14eceSDamien Le Moal 			return 0;
279764e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2798f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2799f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2800f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2801f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2802f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2803f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2804f0d1cf93SDouglas Gilbert 			return check_condition_result;
2805f0d1cf93SDouglas Gilbert 		}
2806f0d1cf93SDouglas Gilbert 		return 0;
2807f0d1cf93SDouglas Gilbert 	}
2808f0d1cf93SDouglas Gilbert 
2809f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2810f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2811f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2812f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2813f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2814f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2815f0d1cf93SDouglas Gilbert 			return check_condition_result;
2816f0d1cf93SDouglas Gilbert 		}
2817f0d1cf93SDouglas Gilbert 		return 0;
2818f0d1cf93SDouglas Gilbert 	}
2819f0d1cf93SDouglas Gilbert 
282064e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2821f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2822f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2823f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2824f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2825f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2826f0d1cf93SDouglas Gilbert 			return check_condition_result;
2827f0d1cf93SDouglas Gilbert 		}
2828f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2829f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2830f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2831f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2832f0d1cf93SDouglas Gilbert 			return check_condition_result;
2833f0d1cf93SDouglas Gilbert 		}
2834f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2835f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2836f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2837f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2838f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2839f0d1cf93SDouglas Gilbert 			return check_condition_result;
2840f0d1cf93SDouglas Gilbert 		}
284164e14eceSDamien Le Moal 	}
2842f0d1cf93SDouglas Gilbert 
2843f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2844f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2845f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2846f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2847f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2848f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2849f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2850f0d1cf93SDouglas Gilbert 			return check_condition_result;
2851f0d1cf93SDouglas Gilbert 		}
2852f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2853f0d1cf93SDouglas Gilbert 	}
2854f0d1cf93SDouglas Gilbert 
2855f0d1cf93SDouglas Gilbert 	return 0;
2856f0d1cf93SDouglas Gilbert }
2857f0d1cf93SDouglas Gilbert 
2858f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2859f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2860f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2861f0d1cf93SDouglas Gilbert {
2862f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2863f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2864f0d1cf93SDouglas Gilbert 
2865c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
286622017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28671da177e4SLinus Torvalds 		return check_condition_result;
28681da177e4SLinus Torvalds 	}
2869c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2870c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
287122017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2872cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2873c65b1445SDouglas Gilbert 		return check_condition_result;
2874c65b1445SDouglas Gilbert 	}
28759447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28769447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28779447b6ceSMartin K. Petersen 		return check_condition_result;
28789447b6ceSMartin K. Petersen 	}
2879f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2880f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2881f0d1cf93SDouglas Gilbert 
288219789100SFUJITA Tomonori 	return 0;
288319789100SFUJITA Tomonori }
288419789100SFUJITA Tomonori 
2885b6ff8ca7SDouglas Gilbert /*
2886b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2887b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2888b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2889b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2890b6ff8ca7SDouglas Gilbert  */
2891b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2892b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
289387c715dcSDouglas Gilbert {
2894b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2895b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2896b6ff8ca7SDouglas Gilbert 		return NULL;
2897b6ff8ca7SDouglas Gilbert 	}
2898b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
289987c715dcSDouglas Gilbert }
290087c715dcSDouglas Gilbert 
2901a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
290287c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
290387c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
290419789100SFUJITA Tomonori {
290519789100SFUJITA Tomonori 	int ret;
2906c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2907a4517511SAkinobu Mita 	enum dma_data_direction dir;
290887c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
290987c715dcSDouglas Gilbert 	u8 *fsp;
291019789100SFUJITA Tomonori 
2911c2248fc9SDouglas Gilbert 	if (do_write) {
2912a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
29134f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2914a4517511SAkinobu Mita 	} else {
2915a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2916a4517511SAkinobu Mita 	}
2917a4517511SAkinobu Mita 
291887c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2919a4517511SAkinobu Mita 		return 0;
292087c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2921a4517511SAkinobu Mita 		return -1;
292287c715dcSDouglas Gilbert 	fsp = sip->storep;
292319789100SFUJITA Tomonori 
292419789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
292519789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
292619789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
292719789100SFUJITA Tomonori 
2928386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
292987c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29300a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2931773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2932a4517511SAkinobu Mita 		return ret;
2933a4517511SAkinobu Mita 
2934a4517511SAkinobu Mita 	if (rest) {
2935386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
293687c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29370a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29380a7e69c7SDouglas Gilbert 			    do_write);
2939a4517511SAkinobu Mita 	}
294019789100SFUJITA Tomonori 
294119789100SFUJITA Tomonori 	return ret;
294219789100SFUJITA Tomonori }
294319789100SFUJITA Tomonori 
294487c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
294587c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
294687c715dcSDouglas Gilbert {
294787c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
294887c715dcSDouglas Gilbert 
294987c715dcSDouglas Gilbert 	if (!sdb->length)
295087c715dcSDouglas Gilbert 		return 0;
295187c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
295287c715dcSDouglas Gilbert 		return -1;
295387c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
295487c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
295587c715dcSDouglas Gilbert }
295687c715dcSDouglas Gilbert 
295787c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
295887c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
295938d5c833SDouglas Gilbert  * return false. */
296087c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2961c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
296238d5c833SDouglas Gilbert {
296338d5c833SDouglas Gilbert 	bool res;
296438d5c833SDouglas Gilbert 	u64 block, rest = 0;
296538d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2966773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
296787c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
296838d5c833SDouglas Gilbert 
296938d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
297038d5c833SDouglas Gilbert 	if (block + num > store_blks)
297138d5c833SDouglas Gilbert 		rest = block + num - store_blks;
297238d5c833SDouglas Gilbert 
297387c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
297438d5c833SDouglas Gilbert 	if (!res)
297538d5c833SDouglas Gilbert 		return res;
297638d5c833SDouglas Gilbert 	if (rest)
297787c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
297838d5c833SDouglas Gilbert 			     rest * lb_size);
297938d5c833SDouglas Gilbert 	if (!res)
298038d5c833SDouglas Gilbert 		return res;
2981c3e2fe92SDouglas Gilbert 	if (compare_only)
2982c3e2fe92SDouglas Gilbert 		return true;
298338d5c833SDouglas Gilbert 	arr += num * lb_size;
298487c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
298538d5c833SDouglas Gilbert 	if (rest)
298687c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
298738d5c833SDouglas Gilbert 	return res;
298838d5c833SDouglas Gilbert }
298938d5c833SDouglas Gilbert 
299051d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2991beb40ea4SAkinobu Mita {
299251d648afSAkinobu Mita 	__be16 csum;
2993beb40ea4SAkinobu Mita 
2994773642d9SDouglas Gilbert 	if (sdebug_guard)
299551d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
299651d648afSAkinobu Mita 	else
2997beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
299851d648afSAkinobu Mita 
2999beb40ea4SAkinobu Mita 	return csum;
3000beb40ea4SAkinobu Mita }
3001beb40ea4SAkinobu Mita 
30026ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3003beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3004beb40ea4SAkinobu Mita {
3005773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3006beb40ea4SAkinobu Mita 
3007beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3008c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3009beb40ea4SAkinobu Mita 			(unsigned long)sector,
3010beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3011beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3012beb40ea4SAkinobu Mita 		return 0x01;
3013beb40ea4SAkinobu Mita 	}
30148475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3015beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3016c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3017c1287970STomas Winkler 			(unsigned long)sector);
3018beb40ea4SAkinobu Mita 		return 0x03;
3019beb40ea4SAkinobu Mita 	}
30208475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3021beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3022c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3023c1287970STomas Winkler 			(unsigned long)sector);
3024beb40ea4SAkinobu Mita 		return 0x03;
3025beb40ea4SAkinobu Mita 	}
3026beb40ea4SAkinobu Mita 	return 0;
3027beb40ea4SAkinobu Mita }
3028beb40ea4SAkinobu Mita 
302987c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
303065f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3031c6a44287SMartin K. Petersen {
3032be4e11beSAkinobu Mita 	size_t resid;
3033c6a44287SMartin K. Petersen 	void *paddr;
303487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3035b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
303687c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
303714faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3038be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3039c6a44287SMartin K. Petersen 
3040e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3041e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3042c6a44287SMartin K. Petersen 
304387c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
304487c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3045be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3046be4e11beSAkinobu Mita 
3047be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
304887c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
304987c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3050be4e11beSAkinobu Mita 		size_t rest = 0;
305114faa944SAkinobu Mita 
305214faa944SAkinobu Mita 		if (dif_store_end < start + len)
305314faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3054c6a44287SMartin K. Petersen 
3055be4e11beSAkinobu Mita 		paddr = miter.addr;
305614faa944SAkinobu Mita 
305765f72f2aSAkinobu Mita 		if (read)
305865f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
305965f72f2aSAkinobu Mita 		else
306065f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
306165f72f2aSAkinobu Mita 
306265f72f2aSAkinobu Mita 		if (rest) {
306365f72f2aSAkinobu Mita 			if (read)
306414faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
306565f72f2aSAkinobu Mita 			else
306665f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
306765f72f2aSAkinobu Mita 		}
3068c6a44287SMartin K. Petersen 
3069e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3070c6a44287SMartin K. Petersen 		resid -= len;
3071c6a44287SMartin K. Petersen 	}
3072be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3073bb8c063cSAkinobu Mita }
3074c6a44287SMartin K. Petersen 
307587c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3076bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3077bb8c063cSAkinobu Mita {
3078bb8c063cSAkinobu Mita 	unsigned int i;
3079bb8c063cSAkinobu Mita 	sector_t sector;
308087c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3081b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
308287c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3083bb8c063cSAkinobu Mita 
3084c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3085bb8c063cSAkinobu Mita 		int ret;
3086bb8c063cSAkinobu Mita 
3087bb8c063cSAkinobu Mita 		sector = start_sec + i;
308887c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3089bb8c063cSAkinobu Mita 
309051d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3091bb8c063cSAkinobu Mita 			continue;
3092bb8c063cSAkinobu Mita 
309387c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
309487c715dcSDouglas Gilbert 				 ei_lba);
3095bb8c063cSAkinobu Mita 		if (ret) {
3096bb8c063cSAkinobu Mita 			dif_errors++;
3097bb8c063cSAkinobu Mita 			return ret;
3098bb8c063cSAkinobu Mita 		}
3099bb8c063cSAkinobu Mita 	}
3100bb8c063cSAkinobu Mita 
310187c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3102c6a44287SMartin K. Petersen 	dix_reads++;
3103c6a44287SMartin K. Petersen 
3104c6a44287SMartin K. Petersen 	return 0;
3105c6a44287SMartin K. Petersen }
3106c6a44287SMartin K. Petersen 
3107fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
310819789100SFUJITA Tomonori {
310987c715dcSDouglas Gilbert 	bool check_prot;
3110c2248fc9SDouglas Gilbert 	u32 num;
3111c2248fc9SDouglas Gilbert 	u32 ei_lba;
311219789100SFUJITA Tomonori 	int ret;
311387c715dcSDouglas Gilbert 	u64 lba;
3114b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
311587c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
311687c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
311719789100SFUJITA Tomonori 
3118c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3119c2248fc9SDouglas Gilbert 	case READ_16:
3120c2248fc9SDouglas Gilbert 		ei_lba = 0;
3121c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3122c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3123c2248fc9SDouglas Gilbert 		check_prot = true;
3124c2248fc9SDouglas Gilbert 		break;
3125c2248fc9SDouglas Gilbert 	case READ_10:
3126c2248fc9SDouglas Gilbert 		ei_lba = 0;
3127c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3128c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3129c2248fc9SDouglas Gilbert 		check_prot = true;
3130c2248fc9SDouglas Gilbert 		break;
3131c2248fc9SDouglas Gilbert 	case READ_6:
3132c2248fc9SDouglas Gilbert 		ei_lba = 0;
3133c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3134c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3135c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3136c2248fc9SDouglas Gilbert 		check_prot = true;
3137c2248fc9SDouglas Gilbert 		break;
3138c2248fc9SDouglas Gilbert 	case READ_12:
3139c2248fc9SDouglas Gilbert 		ei_lba = 0;
3140c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3141c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3142c2248fc9SDouglas Gilbert 		check_prot = true;
3143c2248fc9SDouglas Gilbert 		break;
3144c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3145c2248fc9SDouglas Gilbert 		ei_lba = 0;
3146c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3147c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3148c2248fc9SDouglas Gilbert 		check_prot = false;
3149c2248fc9SDouglas Gilbert 		break;
3150c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3151c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3152c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3153c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3154c2248fc9SDouglas Gilbert 		check_prot = false;
3155c2248fc9SDouglas Gilbert 		break;
3156c2248fc9SDouglas Gilbert 	}
3157f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31588475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3159c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3160c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3161c2248fc9SDouglas Gilbert 			return check_condition_result;
3162c2248fc9SDouglas Gilbert 		}
31638475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31648475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3165c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3166c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3167c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3168c2248fc9SDouglas Gilbert 	}
31693a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
31703a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3171c2248fc9SDouglas Gilbert 		num /= 2;
31723a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3173c2248fc9SDouglas Gilbert 	}
3174c2248fc9SDouglas Gilbert 
31759447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31769447b6ceSMartin K. Petersen 	if (ret)
31779447b6ceSMartin K. Petersen 		return ret;
3178f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3179d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3180d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3181c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3182c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3183c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3184c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3185c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
318632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
318732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3188c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3189c65b1445SDouglas Gilbert 		}
3190c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
31911da177e4SLinus Torvalds 		return check_condition_result;
31921da177e4SLinus Torvalds 	}
3193c6a44287SMartin K. Petersen 
319467da413fSDouglas Gilbert 	read_lock(macc_lckp);
31956c78cc06SAkinobu Mita 
3196c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3197f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3198c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
3199c6a44287SMartin K. Petersen 
3200c6a44287SMartin K. Petersen 		if (prot_ret) {
320167da413fSDouglas Gilbert 			read_unlock(macc_lckp);
3202c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
3203c6a44287SMartin K. Petersen 			return illegal_condition_result;
3204c6a44287SMartin K. Petersen 		}
3205c6a44287SMartin K. Petersen 	}
3206c6a44287SMartin K. Petersen 
320787c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
320867da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3209f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3210a4517511SAkinobu Mita 		return DID_ERROR << 16;
3211a4517511SAkinobu Mita 
321242d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3213a4517511SAkinobu Mita 
32143a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
32153a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
32163a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
32173a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
32183a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3219c2248fc9SDouglas Gilbert 			return check_condition_result;
32203a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3221c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3222c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
32233a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3224c2248fc9SDouglas Gilbert 			return illegal_condition_result;
32253a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3226c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
32273a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3228c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3229c2248fc9SDouglas Gilbert 		}
3230c2248fc9SDouglas Gilbert 	}
3231a4517511SAkinobu Mita 	return 0;
32321da177e4SLinus Torvalds }
32331da177e4SLinus Torvalds 
323458a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
3235c6a44287SMartin K. Petersen {
3236cbf67842SDouglas Gilbert 	int i, j, n;
3237c6a44287SMartin K. Petersen 
3238cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
3239c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
3240cbf67842SDouglas Gilbert 		char b[128];
3241c6a44287SMartin K. Petersen 
3242cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
3243c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
3244c6a44287SMartin K. Petersen 
3245cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
3246cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3247cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
3248cbf67842SDouglas Gilbert 			else
3249cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3250cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
3251cbf67842SDouglas Gilbert 		}
3252cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
3253c6a44287SMartin K. Petersen 	}
3254c6a44287SMartin K. Petersen }
3255c6a44287SMartin K. Petersen 
3256c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3257395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3258c6a44287SMartin K. Petersen {
3259be4e11beSAkinobu Mita 	int ret;
32606ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3261be4e11beSAkinobu Mita 	void *daddr;
326265f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3263c6a44287SMartin K. Petersen 	int ppage_offset;
3264be4e11beSAkinobu Mita 	int dpage_offset;
3265be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3266be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3267c6a44287SMartin K. Petersen 
3268c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3269c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3270c6a44287SMartin K. Petersen 
3271be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3272be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3273be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3274be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3275be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3276c6a44287SMartin K. Petersen 
3277be4e11beSAkinobu Mita 	/* For each protection page */
3278be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3279be4e11beSAkinobu Mita 		dpage_offset = 0;
3280be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3281be4e11beSAkinobu Mita 			ret = 0x01;
3282be4e11beSAkinobu Mita 			goto out;
3283c6a44287SMartin K. Petersen 		}
3284c6a44287SMartin K. Petersen 
3285be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32866ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3287be4e11beSAkinobu Mita 			/* If we're at the end of the current
3288be4e11beSAkinobu Mita 			 * data page advance to the next one
3289be4e11beSAkinobu Mita 			 */
3290be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3291be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3292be4e11beSAkinobu Mita 					ret = 0x01;
3293be4e11beSAkinobu Mita 					goto out;
3294be4e11beSAkinobu Mita 				}
3295be4e11beSAkinobu Mita 				dpage_offset = 0;
3296be4e11beSAkinobu Mita 			}
3297c6a44287SMartin K. Petersen 
3298be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3299be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3300be4e11beSAkinobu Mita 
3301be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
3302beb40ea4SAkinobu Mita 			if (ret) {
3303773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
3304395cef03SMartin K. Petersen 				goto out;
3305395cef03SMartin K. Petersen 			}
3306395cef03SMartin K. Petersen 
3307c6a44287SMartin K. Petersen 			sector++;
3308395cef03SMartin K. Petersen 			ei_lba++;
3309773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3310c6a44287SMartin K. Petersen 		}
3311be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3312be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3313c6a44287SMartin K. Petersen 	}
3314be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3315c6a44287SMartin K. Petersen 
331665f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3317c6a44287SMartin K. Petersen 	dix_writes++;
3318c6a44287SMartin K. Petersen 
3319c6a44287SMartin K. Petersen 	return 0;
3320c6a44287SMartin K. Petersen 
3321c6a44287SMartin K. Petersen out:
3322c6a44287SMartin K. Petersen 	dif_errors++;
3323be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3324be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3325c6a44287SMartin K. Petersen 	return ret;
3326c6a44287SMartin K. Petersen }
3327c6a44287SMartin K. Petersen 
3328b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3329b90ebc3dSAkinobu Mita {
3330773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3331773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3332773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3333b90ebc3dSAkinobu Mita 	return lba;
3334b90ebc3dSAkinobu Mita }
3335b90ebc3dSAkinobu Mita 
3336b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3337b90ebc3dSAkinobu Mita {
3338773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3339a027b5b9SAkinobu Mita 
3340773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3341773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3342a027b5b9SAkinobu Mita 	return lba;
3343a027b5b9SAkinobu Mita }
3344a027b5b9SAkinobu Mita 
334587c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
334687c715dcSDouglas Gilbert 			      unsigned int *num)
334744d92694SMartin K. Petersen {
3348b90ebc3dSAkinobu Mita 	sector_t end;
3349b90ebc3dSAkinobu Mita 	unsigned int mapped;
3350b90ebc3dSAkinobu Mita 	unsigned long index;
3351b90ebc3dSAkinobu Mita 	unsigned long next;
335244d92694SMartin K. Petersen 
3353b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
335487c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
335544d92694SMartin K. Petersen 
335644d92694SMartin K. Petersen 	if (mapped)
335787c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
335844d92694SMartin K. Petersen 	else
335987c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
336044d92694SMartin K. Petersen 
3361b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
336244d92694SMartin K. Petersen 	*num = end - lba;
336344d92694SMartin K. Petersen 	return mapped;
336444d92694SMartin K. Petersen }
336544d92694SMartin K. Petersen 
336687c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
336787c715dcSDouglas Gilbert 		       unsigned int len)
336844d92694SMartin K. Petersen {
336944d92694SMartin K. Petersen 	sector_t end = lba + len;
337044d92694SMartin K. Petersen 
337144d92694SMartin K. Petersen 	while (lba < end) {
3372b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
337344d92694SMartin K. Petersen 
3374b90ebc3dSAkinobu Mita 		if (index < map_size)
337587c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
337644d92694SMartin K. Petersen 
3377b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
337844d92694SMartin K. Petersen 	}
337944d92694SMartin K. Petersen }
338044d92694SMartin K. Petersen 
338187c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
338287c715dcSDouglas Gilbert 			 unsigned int len)
338344d92694SMartin K. Petersen {
338444d92694SMartin K. Petersen 	sector_t end = lba + len;
338587c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
338644d92694SMartin K. Petersen 
338744d92694SMartin K. Petersen 	while (lba < end) {
3388b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
338944d92694SMartin K. Petersen 
3390b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3391773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3392b90ebc3dSAkinobu Mita 		    index < map_size) {
339387c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3394760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
339587c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3396760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3397773642d9SDouglas Gilbert 				       sdebug_sector_size *
3398773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3399be1dd78dSEric Sandeen 			}
340087c715dcSDouglas Gilbert 			if (sip->dif_storep) {
340187c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
340287c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3403773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3404e9926b43SAkinobu Mita 			}
3405b90ebc3dSAkinobu Mita 		}
3406b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
340744d92694SMartin K. Petersen 	}
340844d92694SMartin K. Petersen }
340944d92694SMartin K. Petersen 
3410fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34111da177e4SLinus Torvalds {
341287c715dcSDouglas Gilbert 	bool check_prot;
3413c2248fc9SDouglas Gilbert 	u32 num;
3414c2248fc9SDouglas Gilbert 	u32 ei_lba;
341519789100SFUJITA Tomonori 	int ret;
341687c715dcSDouglas Gilbert 	u64 lba;
3417b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3418b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
341987c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
34201da177e4SLinus Torvalds 
3421c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3422c2248fc9SDouglas Gilbert 	case WRITE_16:
3423c2248fc9SDouglas Gilbert 		ei_lba = 0;
3424c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3425c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3426c2248fc9SDouglas Gilbert 		check_prot = true;
3427c2248fc9SDouglas Gilbert 		break;
3428c2248fc9SDouglas Gilbert 	case WRITE_10:
3429c2248fc9SDouglas Gilbert 		ei_lba = 0;
3430c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3431c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3432c2248fc9SDouglas Gilbert 		check_prot = true;
3433c2248fc9SDouglas Gilbert 		break;
3434c2248fc9SDouglas Gilbert 	case WRITE_6:
3435c2248fc9SDouglas Gilbert 		ei_lba = 0;
3436c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3437c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3438c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3439c2248fc9SDouglas Gilbert 		check_prot = true;
3440c2248fc9SDouglas Gilbert 		break;
3441c2248fc9SDouglas Gilbert 	case WRITE_12:
3442c2248fc9SDouglas Gilbert 		ei_lba = 0;
3443c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3444c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3445c2248fc9SDouglas Gilbert 		check_prot = true;
3446c2248fc9SDouglas Gilbert 		break;
3447c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3448c2248fc9SDouglas Gilbert 		ei_lba = 0;
3449c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3450c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3451c2248fc9SDouglas Gilbert 		check_prot = false;
3452c2248fc9SDouglas Gilbert 		break;
3453c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3454c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3455c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3456c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3457c2248fc9SDouglas Gilbert 		check_prot = false;
3458c2248fc9SDouglas Gilbert 		break;
3459c2248fc9SDouglas Gilbert 	}
3460f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34618475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3462c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3463c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3464c2248fc9SDouglas Gilbert 			return check_condition_result;
3465c2248fc9SDouglas Gilbert 		}
34668475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34678475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3468c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3469c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3470c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3471c2248fc9SDouglas Gilbert 	}
3472f0d1cf93SDouglas Gilbert 
347367da413fSDouglas Gilbert 	write_lock(macc_lckp);
3474f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3475f0d1cf93SDouglas Gilbert 	if (ret) {
3476f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3477f0d1cf93SDouglas Gilbert 		return ret;
3478f0d1cf93SDouglas Gilbert 	}
34796c78cc06SAkinobu Mita 
3480c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3481f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3482c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3483c6a44287SMartin K. Petersen 
3484c6a44287SMartin K. Petersen 		if (prot_ret) {
348567da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3486c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3487c6a44287SMartin K. Petersen 			return illegal_condition_result;
3488c6a44287SMartin K. Petersen 		}
3489c6a44287SMartin K. Petersen 	}
3490c6a44287SMartin K. Petersen 
349187c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3492f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
349387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3494f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3495f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3496f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
349767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3498f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3499773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3500c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3501c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3502c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3503cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3504773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
350544d92694SMartin K. Petersen 
35063a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
35073a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
35083a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
35093a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
35103a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3511c2248fc9SDouglas Gilbert 			return check_condition_result;
35123a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3513c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3514c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
35153a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3516c2248fc9SDouglas Gilbert 			return illegal_condition_result;
35173a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3518c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
35193a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3520c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3521c2248fc9SDouglas Gilbert 		}
3522c2248fc9SDouglas Gilbert 	}
35231da177e4SLinus Torvalds 	return 0;
35241da177e4SLinus Torvalds }
35251da177e4SLinus Torvalds 
3526481b5e5cSDouglas Gilbert /*
3527481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3528481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3529481b5e5cSDouglas Gilbert  */
3530481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3531481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3532481b5e5cSDouglas Gilbert {
3533481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3534481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3535481b5e5cSDouglas Gilbert 	u8 *up;
3536b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3537b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
3538481b5e5cSDouglas Gilbert 	u8 wrprotect;
3539481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3540481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3541481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3542481b5e5cSDouglas Gilbert 	u32 ei_lba;
3543481b5e5cSDouglas Gilbert 	u64 lba;
3544481b5e5cSDouglas Gilbert 	int ret, res;
3545481b5e5cSDouglas Gilbert 	bool is_16;
3546481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3547481b5e5cSDouglas Gilbert 
3548481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3549481b5e5cSDouglas Gilbert 		is_16 = false;
3550481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3551481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3552481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3553481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3554481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3555481b5e5cSDouglas Gilbert 		is_16 = true;
3556481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3557481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3558481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3559481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3560481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3561481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3562481b5e5cSDouglas Gilbert 			    wrprotect) {
3563481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3564481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3565481b5e5cSDouglas Gilbert 			}
3566481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3567481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3568481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3569481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3570481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3571481b5e5cSDouglas Gilbert 		}
3572481b5e5cSDouglas Gilbert 	}
3573481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3574481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3575481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3576481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3577481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3578481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3579481b5e5cSDouglas Gilbert 				my_name, __func__);
3580481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3581481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3582481b5e5cSDouglas Gilbert 	}
3583481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3584481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3585481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3586481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3587481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3588481b5e5cSDouglas Gilbert 				my_name, __func__);
3589481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3590481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3591481b5e5cSDouglas Gilbert 	}
3592481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3593481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3594481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3595481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3596481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3597481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3598481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3599481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3600481b5e5cSDouglas Gilbert 	if (res == -1) {
3601481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3602481b5e5cSDouglas Gilbert 		goto err_out;
3603481b5e5cSDouglas Gilbert 	}
3604481b5e5cSDouglas Gilbert 
360567da413fSDouglas Gilbert 	write_lock(macc_lckp);
3606481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3607481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3608481b5e5cSDouglas Gilbert 	cum_lb = 0;
3609481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3610481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3611481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3612481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3613481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3614481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3615481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3616481b5e5cSDouglas Gilbert 		if (num == 0)
3617481b5e5cSDouglas Gilbert 			continue;
36189447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3619481b5e5cSDouglas Gilbert 		if (ret)
3620481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3621481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3622481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3623481b5e5cSDouglas Gilbert 
3624481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3625481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3626481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3627481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3628481b5e5cSDouglas Gilbert 				    my_name, __func__);
3629481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3630481b5e5cSDouglas Gilbert 					0);
3631481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3632481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3633481b5e5cSDouglas Gilbert 		}
3634481b5e5cSDouglas Gilbert 
3635481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3636481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3637481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3638481b5e5cSDouglas Gilbert 							 ei_lba);
3639481b5e5cSDouglas Gilbert 
3640481b5e5cSDouglas Gilbert 			if (prot_ret) {
3641481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3642481b5e5cSDouglas Gilbert 						prot_ret);
3643481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3644481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3645481b5e5cSDouglas Gilbert 			}
3646481b5e5cSDouglas Gilbert 		}
3647481b5e5cSDouglas Gilbert 
364887c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3649f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3650f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3651f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3652481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
365387c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3654481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3655481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3656481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3657481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3658481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3659481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3660481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3661481b5e5cSDouglas Gilbert 
36623a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36633a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
36643a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36653a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36663a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
36673a90a63dSDouglas Gilbert 				ret = check_condition_result;
3668481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36693a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3670481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
36713a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
36723a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3673481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3674481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36753a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
36763a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
36773a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3678481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3679481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3680481b5e5cSDouglas Gilbert 			}
3681481b5e5cSDouglas Gilbert 		}
3682481b5e5cSDouglas Gilbert 		sg_off += num_by;
3683481b5e5cSDouglas Gilbert 		cum_lb += num;
3684481b5e5cSDouglas Gilbert 	}
3685481b5e5cSDouglas Gilbert 	ret = 0;
3686481b5e5cSDouglas Gilbert err_out_unlock:
368767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3688481b5e5cSDouglas Gilbert err_out:
3689481b5e5cSDouglas Gilbert 	kfree(lrdp);
3690481b5e5cSDouglas Gilbert 	return ret;
3691481b5e5cSDouglas Gilbert }
3692481b5e5cSDouglas Gilbert 
3693fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3694fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
369544d92694SMartin K. Petersen {
3696f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3697f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
369844d92694SMartin K. Petersen 	unsigned long long i;
369940d07b52SDouglas Gilbert 	u64 block, lbaa;
370087c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
370187c715dcSDouglas Gilbert 	int ret;
370287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3703b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
3704b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
370540d07b52SDouglas Gilbert 	u8 *fs1p;
370687c715dcSDouglas Gilbert 	u8 *fsp;
370744d92694SMartin K. Petersen 
370867da413fSDouglas Gilbert 	write_lock(macc_lckp);
370944d92694SMartin K. Petersen 
3710f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3711f0d1cf93SDouglas Gilbert 	if (ret) {
3712f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3713f0d1cf93SDouglas Gilbert 		return ret;
3714f0d1cf93SDouglas Gilbert 	}
3715f0d1cf93SDouglas Gilbert 
37169ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
371787c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
371844d92694SMartin K. Petersen 		goto out;
371944d92694SMartin K. Petersen 	}
372040d07b52SDouglas Gilbert 	lbaa = lba;
372140d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3722c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
372387c715dcSDouglas Gilbert 	fsp = sip->storep;
372487c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3725c2248fc9SDouglas Gilbert 	if (ndob) {
372640d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3727c2248fc9SDouglas Gilbert 		ret = 0;
3728c2248fc9SDouglas Gilbert 	} else
372940d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
373044d92694SMartin K. Petersen 
373144d92694SMartin K. Petersen 	if (-1 == ret) {
373267da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3733773642d9SDouglas Gilbert 		return DID_ERROR << 16;
373440d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3735c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3736e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
373740d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
373844d92694SMartin K. Petersen 
373944d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
374040d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
374140d07b52SDouglas Gilbert 		lbaa = lba + i;
374240d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
374387c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
374440d07b52SDouglas Gilbert 	}
37459ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
374687c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3747f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3748f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3749f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
375044d92694SMartin K. Petersen out:
375167da413fSDouglas Gilbert 	write_unlock(macc_lckp);
375244d92694SMartin K. Petersen 
375344d92694SMartin K. Petersen 	return 0;
375444d92694SMartin K. Petersen }
375544d92694SMartin K. Petersen 
3756fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3757fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3758c2248fc9SDouglas Gilbert {
3759c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3760c2248fc9SDouglas Gilbert 	u32 lba;
3761c2248fc9SDouglas Gilbert 	u16 num;
3762c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3763c2248fc9SDouglas Gilbert 	bool unmap = false;
3764c2248fc9SDouglas Gilbert 
3765c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3766773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3767c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3768c2248fc9SDouglas Gilbert 			return check_condition_result;
3769c2248fc9SDouglas Gilbert 		} else
3770c2248fc9SDouglas Gilbert 			unmap = true;
3771c2248fc9SDouglas Gilbert 	}
3772c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3773c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3774773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3775c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3776c2248fc9SDouglas Gilbert 		return check_condition_result;
3777c2248fc9SDouglas Gilbert 	}
3778c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3779c2248fc9SDouglas Gilbert }
3780c2248fc9SDouglas Gilbert 
3781fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3782fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3783c2248fc9SDouglas Gilbert {
3784c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3785c2248fc9SDouglas Gilbert 	u64 lba;
3786c2248fc9SDouglas Gilbert 	u32 num;
3787c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3788c2248fc9SDouglas Gilbert 	bool unmap = false;
3789c2248fc9SDouglas Gilbert 	bool ndob = false;
3790c2248fc9SDouglas Gilbert 
3791c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3792773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3793c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3794c2248fc9SDouglas Gilbert 			return check_condition_result;
3795c2248fc9SDouglas Gilbert 		} else
3796c2248fc9SDouglas Gilbert 			unmap = true;
3797c2248fc9SDouglas Gilbert 	}
3798c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3799c2248fc9SDouglas Gilbert 		ndob = true;
3800c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3801c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3802773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3803c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3804c2248fc9SDouglas Gilbert 		return check_condition_result;
3805c2248fc9SDouglas Gilbert 	}
3806c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3807c2248fc9SDouglas Gilbert }
3808c2248fc9SDouglas Gilbert 
3809acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3810acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3811acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3812fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3813fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3814acafd0b9SEwan D. Milne {
3815acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3816acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3817acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3818acafd0b9SEwan D. Milne 	u8 mode;
3819acafd0b9SEwan D. Milne 
3820acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3821acafd0b9SEwan D. Milne 	switch (mode) {
3822acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3823acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3824acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3825acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3826acafd0b9SEwan D. Milne 		break;
3827acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3828acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3829acafd0b9SEwan D. Milne 		break;
3830acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3831acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3832acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3833acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3834acafd0b9SEwan D. Milne 				    dev_list)
3835acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3836acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3837acafd0b9SEwan D. Milne 				if (devip != dp)
3838acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3839acafd0b9SEwan D. Milne 						dp->uas_bm);
3840acafd0b9SEwan D. Milne 			}
3841acafd0b9SEwan D. Milne 		break;
3842acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3843acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3844acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3845acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3846acafd0b9SEwan D. Milne 				    dev_list)
3847acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3848acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3849acafd0b9SEwan D. Milne 					dp->uas_bm);
3850acafd0b9SEwan D. Milne 		break;
3851acafd0b9SEwan D. Milne 	default:
3852acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3853acafd0b9SEwan D. Milne 		break;
3854acafd0b9SEwan D. Milne 	}
3855acafd0b9SEwan D. Milne 	return 0;
3856acafd0b9SEwan D. Milne }
3857acafd0b9SEwan D. Milne 
3858fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3859fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
386038d5c833SDouglas Gilbert {
386138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
386238d5c833SDouglas Gilbert 	u8 *arr;
3863b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3864b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
386538d5c833SDouglas Gilbert 	u64 lba;
386638d5c833SDouglas Gilbert 	u32 dnum;
3867773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
386838d5c833SDouglas Gilbert 	u8 num;
386938d5c833SDouglas Gilbert 	int ret;
3870d467d31fSDouglas Gilbert 	int retval = 0;
387138d5c833SDouglas Gilbert 
3872d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
387338d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
387438d5c833SDouglas Gilbert 	if (0 == num)
387538d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38768475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
387738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
387838d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
387938d5c833SDouglas Gilbert 		return check_condition_result;
388038d5c833SDouglas Gilbert 	}
38818475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
38828475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
388338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
388438d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
388538d5c833SDouglas Gilbert 			    "to DIF device\n");
38869447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
38879447b6ceSMartin K. Petersen 	if (ret)
38889447b6ceSMartin K. Petersen 		return ret;
3889d467d31fSDouglas Gilbert 	dnum = 2 * num;
38906396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3891d467d31fSDouglas Gilbert 	if (NULL == arr) {
3892d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3893d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3894d467d31fSDouglas Gilbert 		return check_condition_result;
3895d467d31fSDouglas Gilbert 	}
389638d5c833SDouglas Gilbert 
389767da413fSDouglas Gilbert 	write_lock(macc_lckp);
389838d5c833SDouglas Gilbert 
389987c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
390038d5c833SDouglas Gilbert 	if (ret == -1) {
3901d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3902d467d31fSDouglas Gilbert 		goto cleanup;
3903773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
390438d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
390538d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
390638d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3907c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
390838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3909d467d31fSDouglas Gilbert 		retval = check_condition_result;
3910d467d31fSDouglas Gilbert 		goto cleanup;
391138d5c833SDouglas Gilbert 	}
391238d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
391387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3914d467d31fSDouglas Gilbert cleanup:
391567da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3916d467d31fSDouglas Gilbert 	kfree(arr);
3917d467d31fSDouglas Gilbert 	return retval;
391838d5c833SDouglas Gilbert }
391938d5c833SDouglas Gilbert 
392044d92694SMartin K. Petersen struct unmap_block_desc {
392144d92694SMartin K. Petersen 	__be64	lba;
392244d92694SMartin K. Petersen 	__be32	blocks;
392344d92694SMartin K. Petersen 	__be32	__reserved;
392444d92694SMartin K. Petersen };
392544d92694SMartin K. Petersen 
3926fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
392744d92694SMartin K. Petersen {
392844d92694SMartin K. Petersen 	unsigned char *buf;
392944d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
3930b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3931b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
393244d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
393344d92694SMartin K. Petersen 	int ret;
393444d92694SMartin K. Petersen 
3935c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3936c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3937c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3938c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
393944d92694SMartin K. Petersen 
394044d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3941773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3942c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
394344d92694SMartin K. Petersen 		return check_condition_result;
3944c2248fc9SDouglas Gilbert 	}
394544d92694SMartin K. Petersen 
3946b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3947c2248fc9SDouglas Gilbert 	if (!buf) {
3948c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3949c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3950c2248fc9SDouglas Gilbert 		return check_condition_result;
3951c2248fc9SDouglas Gilbert 	}
3952c2248fc9SDouglas Gilbert 
3953c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
395444d92694SMartin K. Petersen 
395544d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
395644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
395744d92694SMartin K. Petersen 
395844d92694SMartin K. Petersen 	desc = (void *)&buf[8];
395944d92694SMartin K. Petersen 
396067da413fSDouglas Gilbert 	write_lock(macc_lckp);
39616c78cc06SAkinobu Mita 
396244d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
396344d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
396444d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
396544d92694SMartin K. Petersen 
39669447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
396744d92694SMartin K. Petersen 		if (ret)
396844d92694SMartin K. Petersen 			goto out;
396944d92694SMartin K. Petersen 
397087c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
397144d92694SMartin K. Petersen 	}
397244d92694SMartin K. Petersen 
397344d92694SMartin K. Petersen 	ret = 0;
397444d92694SMartin K. Petersen 
397544d92694SMartin K. Petersen out:
397667da413fSDouglas Gilbert 	write_unlock(macc_lckp);
397744d92694SMartin K. Petersen 	kfree(buf);
397844d92694SMartin K. Petersen 
397944d92694SMartin K. Petersen 	return ret;
398044d92694SMartin K. Petersen }
398144d92694SMartin K. Petersen 
398244d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
398344d92694SMartin K. Petersen 
3984fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3985fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
398644d92694SMartin K. Petersen {
3987c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3988c2248fc9SDouglas Gilbert 	u64 lba;
3989c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
399044d92694SMartin K. Petersen 	int ret;
399187c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
399244d92694SMartin K. Petersen 
3993c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3994c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
399544d92694SMartin K. Petersen 
399644d92694SMartin K. Petersen 	if (alloc_len < 24)
399744d92694SMartin K. Petersen 		return 0;
399844d92694SMartin K. Petersen 
39999447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
400044d92694SMartin K. Petersen 	if (ret)
400144d92694SMartin K. Petersen 		return ret;
400244d92694SMartin K. Petersen 
4003b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4004b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4005b6ff8ca7SDouglas Gilbert 
400687c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4007b6ff8ca7SDouglas Gilbert 	} else {
4008c2248fc9SDouglas Gilbert 		mapped = 1;
4009c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4010c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4011c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4012c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4013c2248fc9SDouglas Gilbert 		else
4014c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4015c2248fc9SDouglas Gilbert 	}
401644d92694SMartin K. Petersen 
401744d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4018c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4019c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4020c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4021c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
402244d92694SMartin K. Petersen 
4023c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
402444d92694SMartin K. Petersen }
402544d92694SMartin K. Petersen 
402680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
402780c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
402880c49563SDouglas Gilbert {
40294f2c8bf6SDouglas Gilbert 	int res = 0;
403080c49563SDouglas Gilbert 	u64 lba;
403180c49563SDouglas Gilbert 	u32 num_blocks;
403280c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
403380c49563SDouglas Gilbert 
403480c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
403580c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
403680c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
403780c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
403880c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
403980c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
404080c49563SDouglas Gilbert 	}
404180c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
404280c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
404380c49563SDouglas Gilbert 		return check_condition_result;
404480c49563SDouglas Gilbert 	}
4045fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
40464f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40474f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40484f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40494f2c8bf6SDouglas Gilbert 	return res;
405080c49563SDouglas Gilbert }
405180c49563SDouglas Gilbert 
4052ed9f3e25SDouglas Gilbert /*
4053ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4054ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4055ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4056ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4057ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4058ed9f3e25SDouglas Gilbert  */
4059ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4060ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4061ed9f3e25SDouglas Gilbert {
4062ed9f3e25SDouglas Gilbert 	int res = 0;
4063ed9f3e25SDouglas Gilbert 	u64 lba;
4064ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4065ed9f3e25SDouglas Gilbert 	u32 nblks;
4066ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4067b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4068b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4069b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4070ed9f3e25SDouglas Gilbert 
4071ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4072ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4073ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4074ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4075ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4076ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4077ed9f3e25SDouglas Gilbert 	}
4078ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4079ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4080ed9f3e25SDouglas Gilbert 		return check_condition_result;
4081ed9f3e25SDouglas Gilbert 	}
4082ed9f3e25SDouglas Gilbert 	if (!fsp)
4083ed9f3e25SDouglas Gilbert 		goto fini;
4084ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4085ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4086ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4087ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4088ed9f3e25SDouglas Gilbert 
4089ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4090ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4091ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4092ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4093ed9f3e25SDouglas Gilbert 	if (rest)
4094ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4095ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4096ed9f3e25SDouglas Gilbert fini:
4097ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4098ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4099ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4100ed9f3e25SDouglas Gilbert }
4101ed9f3e25SDouglas Gilbert 
4102fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4103fb0cc8d1SDouglas Gilbert 
41048d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
41058d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
41068d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
41078d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41088d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
41098d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
41108d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
41118d039e22SDouglas Gilbert  */
41121da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
41131da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
41141da177e4SLinus Torvalds {
411501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
41168d039e22SDouglas Gilbert 	unsigned int alloc_len;
41178d039e22SDouglas Gilbert 	unsigned char select_report;
41188d039e22SDouglas Gilbert 	u64 lun;
41198d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4120fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41218d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41228d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
41238d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
41248d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4125fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4126fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4127fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41281da177e4SLinus Torvalds 
412919c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41308d039e22SDouglas Gilbert 
41318d039e22SDouglas Gilbert 	select_report = cmd[2];
41328d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41338d039e22SDouglas Gilbert 
41348d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41358d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41368d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41371da177e4SLinus Torvalds 		return check_condition_result;
41381da177e4SLinus Torvalds 	}
41398d039e22SDouglas Gilbert 
41408d039e22SDouglas Gilbert 	switch (select_report) {
41418d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4142773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41438d039e22SDouglas Gilbert 		wlun_cnt = 0;
41448d039e22SDouglas Gilbert 		break;
41458d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4146c65b1445SDouglas Gilbert 		lun_cnt = 0;
41478d039e22SDouglas Gilbert 		wlun_cnt = 1;
41488d039e22SDouglas Gilbert 		break;
41498d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41508d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41518d039e22SDouglas Gilbert 		wlun_cnt = 1;
41528d039e22SDouglas Gilbert 		break;
41538d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41548d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41558d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41568d039e22SDouglas Gilbert 	default:
41578d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41588d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41598d039e22SDouglas Gilbert 		return check_condition_result;
41608d039e22SDouglas Gilbert 	}
41618d039e22SDouglas Gilbert 
41628d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4163c65b1445SDouglas Gilbert 		--lun_cnt;
41648d039e22SDouglas Gilbert 
41658d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4166fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4167fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41688d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41698d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41708d039e22SDouglas Gilbert 
4171fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41728d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4173fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4174fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4175fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4176fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4177fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4178fb0cc8d1SDouglas Gilbert 			++lun_p;
4179fb0cc8d1SDouglas Gilbert 			j = 1;
4180fb0cc8d1SDouglas Gilbert 		}
4181fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4182fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4183fb0cc8d1SDouglas Gilbert 				break;
4184fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4185ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4186ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4187fb0cc8d1SDouglas Gilbert 		}
4188fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4189fb0cc8d1SDouglas Gilbert 			break;
4190fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4191fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4192fb0cc8d1SDouglas Gilbert 		if (res)
4193fb0cc8d1SDouglas Gilbert 			return res;
4194fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4195fb0cc8d1SDouglas Gilbert 	}
4196fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4197fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4198fb0cc8d1SDouglas Gilbert 		++j;
4199fb0cc8d1SDouglas Gilbert 	}
4200fb0cc8d1SDouglas Gilbert 	if (j > 0)
4201fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
42028d039e22SDouglas Gilbert 	return res;
42031da177e4SLinus Torvalds }
42041da177e4SLinus Torvalds 
4205c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4206c3e2fe92SDouglas Gilbert {
4207c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4208c3e2fe92SDouglas Gilbert 	u8 bytchk;
4209c3e2fe92SDouglas Gilbert 	int ret, j;
4210c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4211c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4212c3e2fe92SDouglas Gilbert 	u64 lba;
4213c3e2fe92SDouglas Gilbert 	u8 *arr;
4214c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4215b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4216b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4217c3e2fe92SDouglas Gilbert 
4218c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4219c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4220c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4221c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4222c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4223c3e2fe92SDouglas Gilbert 		return check_condition_result;
4224c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4225c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4226c3e2fe92SDouglas Gilbert 	}
4227c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4228c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4229c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4230c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4231c3e2fe92SDouglas Gilbert 		break;
4232c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4233c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4234c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4235c3e2fe92SDouglas Gilbert 		break;
4236c3e2fe92SDouglas Gilbert 	default:
4237c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4238c3e2fe92SDouglas Gilbert 		return check_condition_result;
4239c3e2fe92SDouglas Gilbert 	}
4240c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4241c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4242c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4243c3e2fe92SDouglas Gilbert 	if (ret)
4244c3e2fe92SDouglas Gilbert 		return ret;
4245c3e2fe92SDouglas Gilbert 
4246c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4247c3e2fe92SDouglas Gilbert 	if (!arr) {
4248c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4249c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4250c3e2fe92SDouglas Gilbert 		return check_condition_result;
4251c3e2fe92SDouglas Gilbert 	}
4252c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
425367da413fSDouglas Gilbert 	read_lock(macc_lckp);
4254c3e2fe92SDouglas Gilbert 
4255c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4256c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4257c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4258c3e2fe92SDouglas Gilbert 		goto cleanup;
4259c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4260c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4261c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4262c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4263c3e2fe92SDouglas Gilbert 	}
4264c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4265c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4266c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4267c3e2fe92SDouglas Gilbert 	}
4268c3e2fe92SDouglas Gilbert 	ret = 0;
4269c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4270c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4271c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4272c3e2fe92SDouglas Gilbert 		goto cleanup;
4273c3e2fe92SDouglas Gilbert 	}
4274c3e2fe92SDouglas Gilbert cleanup:
427567da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4276c3e2fe92SDouglas Gilbert 	kfree(arr);
4277c3e2fe92SDouglas Gilbert 	return ret;
4278c3e2fe92SDouglas Gilbert }
4279c3e2fe92SDouglas Gilbert 
4280f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4281f0d1cf93SDouglas Gilbert 
4282f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4283f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4284f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4285f0d1cf93SDouglas Gilbert {
4286f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4287f0d1cf93SDouglas Gilbert 	int ret = 0;
4288f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4289f0d1cf93SDouglas Gilbert 	bool partial;
4290f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4291f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4292f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4293f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4294b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4295f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4296f0d1cf93SDouglas Gilbert 
4297f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4298f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4299f0d1cf93SDouglas Gilbert 		return check_condition_result;
4300f0d1cf93SDouglas Gilbert 	}
4301f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4302f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4303f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4304f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4305f0d1cf93SDouglas Gilbert 
4306f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4307f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4308f0d1cf93SDouglas Gilbert 		return check_condition_result;
4309f0d1cf93SDouglas Gilbert 	}
4310f0d1cf93SDouglas Gilbert 
4311108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4312f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4313f0d1cf93SDouglas Gilbert 			    max_zones);
4314f0d1cf93SDouglas Gilbert 
4315f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4316f0d1cf93SDouglas Gilbert 	if (!arr) {
4317f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4318f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4319f0d1cf93SDouglas Gilbert 		return check_condition_result;
4320f0d1cf93SDouglas Gilbert 	}
4321f0d1cf93SDouglas Gilbert 
4322f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4323f0d1cf93SDouglas Gilbert 
4324f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4325f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4326f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4327f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4328f0d1cf93SDouglas Gilbert 			break;
4329f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4330f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4331f0d1cf93SDouglas Gilbert 		case 0x00:
4332f0d1cf93SDouglas Gilbert 			/* All zones */
4333f0d1cf93SDouglas Gilbert 			break;
4334f0d1cf93SDouglas Gilbert 		case 0x01:
4335f0d1cf93SDouglas Gilbert 			/* Empty zones */
4336f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4337f0d1cf93SDouglas Gilbert 				continue;
4338f0d1cf93SDouglas Gilbert 			break;
4339f0d1cf93SDouglas Gilbert 		case 0x02:
4340f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4341f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4342f0d1cf93SDouglas Gilbert 				continue;
4343f0d1cf93SDouglas Gilbert 			break;
4344f0d1cf93SDouglas Gilbert 		case 0x03:
4345f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4346f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4347f0d1cf93SDouglas Gilbert 				continue;
4348f0d1cf93SDouglas Gilbert 			break;
4349f0d1cf93SDouglas Gilbert 		case 0x04:
4350f0d1cf93SDouglas Gilbert 			/* Closed zones */
4351f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4352f0d1cf93SDouglas Gilbert 				continue;
4353f0d1cf93SDouglas Gilbert 			break;
4354f0d1cf93SDouglas Gilbert 		case 0x05:
4355f0d1cf93SDouglas Gilbert 			/* Full zones */
4356f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4357f0d1cf93SDouglas Gilbert 				continue;
4358f0d1cf93SDouglas Gilbert 			break;
4359f0d1cf93SDouglas Gilbert 		case 0x06:
4360f0d1cf93SDouglas Gilbert 		case 0x07:
4361f0d1cf93SDouglas Gilbert 		case 0x10:
4362f0d1cf93SDouglas Gilbert 			/*
436364e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
436464e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4365f0d1cf93SDouglas Gilbert 			 */
4366f0d1cf93SDouglas Gilbert 			continue;
436764e14eceSDamien Le Moal 		case 0x11:
436864e14eceSDamien Le Moal 			/* non-seq-resource set */
436964e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
437064e14eceSDamien Le Moal 				continue;
437164e14eceSDamien Le Moal 			break;
4372f0d1cf93SDouglas Gilbert 		case 0x3f:
4373f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4374f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4375f0d1cf93SDouglas Gilbert 				continue;
4376f0d1cf93SDouglas Gilbert 			break;
4377f0d1cf93SDouglas Gilbert 		default:
4378f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4379f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4380f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4381f0d1cf93SDouglas Gilbert 			goto fini;
4382f0d1cf93SDouglas Gilbert 		}
4383f0d1cf93SDouglas Gilbert 
4384f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4385f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
438664e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4387f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
438864e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
438964e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4390f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4391f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4392f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4393f0d1cf93SDouglas Gilbert 			desc += 64;
4394f0d1cf93SDouglas Gilbert 		}
4395f0d1cf93SDouglas Gilbert 
4396f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4397f0d1cf93SDouglas Gilbert 			break;
4398f0d1cf93SDouglas Gilbert 
4399f0d1cf93SDouglas Gilbert 		nrz++;
4400f0d1cf93SDouglas Gilbert 	}
4401f0d1cf93SDouglas Gilbert 
4402f0d1cf93SDouglas Gilbert 	/* Report header */
4403f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4404f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4405f0d1cf93SDouglas Gilbert 
4406f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4407f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4408f0d1cf93SDouglas Gilbert 
4409f0d1cf93SDouglas Gilbert fini:
4410f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4411f0d1cf93SDouglas Gilbert 	kfree(arr);
4412f0d1cf93SDouglas Gilbert 	return ret;
4413f0d1cf93SDouglas Gilbert }
4414f0d1cf93SDouglas Gilbert 
4415f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4416f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4417f0d1cf93SDouglas Gilbert {
4418f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4419f0d1cf93SDouglas Gilbert 	unsigned int i;
4420f0d1cf93SDouglas Gilbert 
4421f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4422f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4423f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4424f0d1cf93SDouglas Gilbert 	}
4425f0d1cf93SDouglas Gilbert }
4426f0d1cf93SDouglas Gilbert 
4427f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4428f0d1cf93SDouglas Gilbert {
4429f0d1cf93SDouglas Gilbert 	int res = 0;
4430f0d1cf93SDouglas Gilbert 	u64 z_id;
4431f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4432f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4433f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4434f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4435b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4436f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4437f0d1cf93SDouglas Gilbert 
4438f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4439f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4440f0d1cf93SDouglas Gilbert 		return check_condition_result;
4441f0d1cf93SDouglas Gilbert 	}
4442f0d1cf93SDouglas Gilbert 
4443f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4444f0d1cf93SDouglas Gilbert 
4445f0d1cf93SDouglas Gilbert 	if (all) {
4446f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4447f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4448f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4449f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4450f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4451f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4452f0d1cf93SDouglas Gilbert 			goto fini;
4453f0d1cf93SDouglas Gilbert 		}
4454f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4455f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4456f0d1cf93SDouglas Gilbert 		goto fini;
4457f0d1cf93SDouglas Gilbert 	}
4458f0d1cf93SDouglas Gilbert 
4459f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4460f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4461f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4462f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4463f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4464f0d1cf93SDouglas Gilbert 		goto fini;
4465f0d1cf93SDouglas Gilbert 	}
4466f0d1cf93SDouglas Gilbert 
4467f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4468f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4469f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4470f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4471f0d1cf93SDouglas Gilbert 		goto fini;
4472f0d1cf93SDouglas Gilbert 	}
4473f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4474f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4475f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4476f0d1cf93SDouglas Gilbert 		goto fini;
4477f0d1cf93SDouglas Gilbert 	}
4478f0d1cf93SDouglas Gilbert 
4479f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4480f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4481f0d1cf93SDouglas Gilbert 		goto fini;
4482f0d1cf93SDouglas Gilbert 
4483f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4484f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4485f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4486f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4487f0d1cf93SDouglas Gilbert 		goto fini;
4488f0d1cf93SDouglas Gilbert 	}
4489f0d1cf93SDouglas Gilbert 
4490f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
4491f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4492f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4493f0d1cf93SDouglas Gilbert fini:
4494f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4495f0d1cf93SDouglas Gilbert 	return res;
4496f0d1cf93SDouglas Gilbert }
4497f0d1cf93SDouglas Gilbert 
4498f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4499f0d1cf93SDouglas Gilbert {
4500f0d1cf93SDouglas Gilbert 	unsigned int i;
4501f0d1cf93SDouglas Gilbert 
4502f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4503f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4504f0d1cf93SDouglas Gilbert }
4505f0d1cf93SDouglas Gilbert 
4506f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4507f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4508f0d1cf93SDouglas Gilbert {
4509f0d1cf93SDouglas Gilbert 	int res = 0;
4510f0d1cf93SDouglas Gilbert 	u64 z_id;
4511f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4512f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4513f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4514b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4515f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4516f0d1cf93SDouglas Gilbert 
4517f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4518f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4519f0d1cf93SDouglas Gilbert 		return check_condition_result;
4520f0d1cf93SDouglas Gilbert 	}
4521f0d1cf93SDouglas Gilbert 
4522f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4523f0d1cf93SDouglas Gilbert 
4524f0d1cf93SDouglas Gilbert 	if (all) {
4525f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4526f0d1cf93SDouglas Gilbert 		goto fini;
4527f0d1cf93SDouglas Gilbert 	}
4528f0d1cf93SDouglas Gilbert 
4529f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4530f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4531f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4532f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4533f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4534f0d1cf93SDouglas Gilbert 		goto fini;
4535f0d1cf93SDouglas Gilbert 	}
4536f0d1cf93SDouglas Gilbert 
4537f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4538f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4539f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4540f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4541f0d1cf93SDouglas Gilbert 		goto fini;
4542f0d1cf93SDouglas Gilbert 	}
4543f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4544f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4545f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4546f0d1cf93SDouglas Gilbert 		goto fini;
4547f0d1cf93SDouglas Gilbert 	}
4548f0d1cf93SDouglas Gilbert 
4549f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4550f0d1cf93SDouglas Gilbert fini:
4551f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4552f0d1cf93SDouglas Gilbert 	return res;
4553f0d1cf93SDouglas Gilbert }
4554f0d1cf93SDouglas Gilbert 
4555f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4556f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4557f0d1cf93SDouglas Gilbert {
4558f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4559f0d1cf93SDouglas Gilbert 
4560f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4561f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4562f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4563f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4564f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4565f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4566f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4567f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4568f0d1cf93SDouglas Gilbert 	}
4569f0d1cf93SDouglas Gilbert }
4570f0d1cf93SDouglas Gilbert 
4571f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4572f0d1cf93SDouglas Gilbert {
4573f0d1cf93SDouglas Gilbert 	unsigned int i;
4574f0d1cf93SDouglas Gilbert 
4575f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4576f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4577f0d1cf93SDouglas Gilbert }
4578f0d1cf93SDouglas Gilbert 
4579f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4580f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4581f0d1cf93SDouglas Gilbert {
4582f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4583f0d1cf93SDouglas Gilbert 	int res = 0;
4584f0d1cf93SDouglas Gilbert 	u64 z_id;
4585f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4586f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4587b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4588f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4589f0d1cf93SDouglas Gilbert 
4590f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4591f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4592f0d1cf93SDouglas Gilbert 		return check_condition_result;
4593f0d1cf93SDouglas Gilbert 	}
4594f0d1cf93SDouglas Gilbert 
4595f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4596f0d1cf93SDouglas Gilbert 
4597f0d1cf93SDouglas Gilbert 	if (all) {
4598f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4599f0d1cf93SDouglas Gilbert 		goto fini;
4600f0d1cf93SDouglas Gilbert 	}
4601f0d1cf93SDouglas Gilbert 
4602f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4603f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4604f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4605f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4606f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4607f0d1cf93SDouglas Gilbert 		goto fini;
4608f0d1cf93SDouglas Gilbert 	}
4609f0d1cf93SDouglas Gilbert 
4610f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4611f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4612f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4613f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4614f0d1cf93SDouglas Gilbert 		goto fini;
4615f0d1cf93SDouglas Gilbert 	}
4616f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4617f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4618f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4619f0d1cf93SDouglas Gilbert 		goto fini;
4620f0d1cf93SDouglas Gilbert 	}
4621f0d1cf93SDouglas Gilbert 
4622f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4623f0d1cf93SDouglas Gilbert fini:
4624f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4625f0d1cf93SDouglas Gilbert 	return res;
4626f0d1cf93SDouglas Gilbert }
4627f0d1cf93SDouglas Gilbert 
4628f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4629f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4630f0d1cf93SDouglas Gilbert {
4631f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4632f0d1cf93SDouglas Gilbert 
4633f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4634f0d1cf93SDouglas Gilbert 		return;
4635f0d1cf93SDouglas Gilbert 
4636f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4637f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4638f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4639f0d1cf93SDouglas Gilbert 
4640f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4641f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4642f0d1cf93SDouglas Gilbert 
464364e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4644f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4645f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4646f0d1cf93SDouglas Gilbert }
4647f0d1cf93SDouglas Gilbert 
4648f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4649f0d1cf93SDouglas Gilbert {
4650f0d1cf93SDouglas Gilbert 	unsigned int i;
4651f0d1cf93SDouglas Gilbert 
4652f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4653f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4654f0d1cf93SDouglas Gilbert }
4655f0d1cf93SDouglas Gilbert 
4656f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4657f0d1cf93SDouglas Gilbert {
4658f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4659f0d1cf93SDouglas Gilbert 	int res = 0;
4660f0d1cf93SDouglas Gilbert 	u64 z_id;
4661f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4662f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4663b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4664f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4665f0d1cf93SDouglas Gilbert 
4666f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4667f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4668f0d1cf93SDouglas Gilbert 		return check_condition_result;
4669f0d1cf93SDouglas Gilbert 	}
4670f0d1cf93SDouglas Gilbert 
4671f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4672f0d1cf93SDouglas Gilbert 
4673f0d1cf93SDouglas Gilbert 	if (all) {
4674f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4675f0d1cf93SDouglas Gilbert 		goto fini;
4676f0d1cf93SDouglas Gilbert 	}
4677f0d1cf93SDouglas Gilbert 
4678f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4679f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4680f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4681f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4682f0d1cf93SDouglas Gilbert 		goto fini;
4683f0d1cf93SDouglas Gilbert 	}
4684f0d1cf93SDouglas Gilbert 
4685f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4686f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4687f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4688f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4689f0d1cf93SDouglas Gilbert 		goto fini;
4690f0d1cf93SDouglas Gilbert 	}
4691f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4692f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4693f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4694f0d1cf93SDouglas Gilbert 		goto fini;
4695f0d1cf93SDouglas Gilbert 	}
4696f0d1cf93SDouglas Gilbert 
4697f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4698f0d1cf93SDouglas Gilbert fini:
4699f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4700f0d1cf93SDouglas Gilbert 	return res;
4701f0d1cf93SDouglas Gilbert }
4702f0d1cf93SDouglas Gilbert 
4703c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4704c4837394SDouglas Gilbert {
4705c10fa55fSJohn Garry 	u16 hwq;
4706c10fa55fSJohn Garry 
4707c10fa55fSJohn Garry 	if (sdebug_host_max_queue) {
4708c10fa55fSJohn Garry 		/* Provide a simple method to choose the hwq */
4709c10fa55fSJohn Garry 		hwq = smp_processor_id() % submit_queues;
4710c10fa55fSJohn Garry 	} else {
4711c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
4712c10fa55fSJohn Garry 
4713c10fa55fSJohn Garry 		hwq = blk_mq_unique_tag_to_hwq(tag);
4714c4837394SDouglas Gilbert 
4715458df78bSBart Van Assche 		pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4716458df78bSBart Van Assche 		if (WARN_ON_ONCE(hwq >= submit_queues))
4717458df78bSBart Van Assche 			hwq = 0;
4718c10fa55fSJohn Garry 	}
4719458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4720c4837394SDouglas Gilbert }
4721c4837394SDouglas Gilbert 
4722c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4723c10fa55fSJohn Garry {
4724c10fa55fSJohn Garry 	return blk_mq_unique_tag(cmnd->request);
4725c10fa55fSJohn Garry }
4726c10fa55fSJohn Garry 
4727c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4728fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47291da177e4SLinus Torvalds {
47307382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4731c4837394SDouglas Gilbert 	int qc_idx;
4732cbf67842SDouglas Gilbert 	int retiring = 0;
47331da177e4SLinus Torvalds 	unsigned long iflags;
4734c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4735cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4736cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4737cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47381da177e4SLinus Torvalds 
473910bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
47407382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47417382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4742c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4743c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4744c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4745cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4746c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4747c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4748c4837394SDouglas Gilbert 	}
4749c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4750c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47511da177e4SLinus Torvalds 		return;
47521da177e4SLinus Torvalds 	}
4753c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4754c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4755cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4756b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4757c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4758c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4759c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
47601da177e4SLinus Torvalds 		return;
47611da177e4SLinus Torvalds 	}
4762cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4763f46eb0e9SDouglas Gilbert 	if (likely(devip))
4764cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4765cbf67842SDouglas Gilbert 	else
4766c1287970STomas Winkler 		pr_err("devip=NULL\n");
4767f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4768cbf67842SDouglas Gilbert 		retiring = 1;
4769cbf67842SDouglas Gilbert 
4770cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4771c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4772c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4773c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4774cbf67842SDouglas Gilbert 		return;
47751da177e4SLinus Torvalds 	}
47761da177e4SLinus Torvalds 
4777cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4778cbf67842SDouglas Gilbert 		int k, retval;
4779cbf67842SDouglas Gilbert 
4780cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4781c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4782c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4783c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4784cbf67842SDouglas Gilbert 			return;
4785cbf67842SDouglas Gilbert 		}
4786c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4787773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4788cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4789cbf67842SDouglas Gilbert 		else
4790cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4791cbf67842SDouglas Gilbert 	}
4792c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47937382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
47947382f9d8SDouglas Gilbert 		if (sdebug_verbose)
47957382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
47967382f9d8SDouglas Gilbert 		return;
47977382f9d8SDouglas Gilbert 	}
4798cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4799cbf67842SDouglas Gilbert }
4800cbf67842SDouglas Gilbert 
4801cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4802fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4803cbf67842SDouglas Gilbert {
4804a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4805a10bc12aSDouglas Gilbert 						  hrt);
4806a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4807cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4808cbf67842SDouglas Gilbert }
48091da177e4SLinus Torvalds 
4810a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4811fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4812a10bc12aSDouglas Gilbert {
4813a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4814a10bc12aSDouglas Gilbert 						  ew.work);
4815a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4816a10bc12aSDouglas Gilbert }
4817a10bc12aSDouglas Gilbert 
481809ba24c1SDouglas Gilbert static bool got_shared_uuid;
4819bf476433SChristoph Hellwig static uuid_t shared_uuid;
482009ba24c1SDouglas Gilbert 
4821f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4822f0d1cf93SDouglas Gilbert {
4823f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4824f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4825f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4826f0d1cf93SDouglas Gilbert 	unsigned int i;
4827f0d1cf93SDouglas Gilbert 
4828f0d1cf93SDouglas Gilbert 	/*
482998e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
483098e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4831f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4832f0d1cf93SDouglas Gilbert 	 * created for the device.
4833f0d1cf93SDouglas Gilbert 	 */
483498e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4835f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4836f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4837f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4838f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4839f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4840f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4841f0d1cf93SDouglas Gilbert 			return -EINVAL;
4842f0d1cf93SDouglas Gilbert 		}
4843f0d1cf93SDouglas Gilbert 	} else {
4844108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4845108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4846108e36f0SDamien Le Moal 			return -EINVAL;
4847108e36f0SDamien Le Moal 		}
484898e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4849f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4850f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4851f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4852f0d1cf93SDouglas Gilbert 			return -EINVAL;
4853f0d1cf93SDouglas Gilbert 		}
4854f0d1cf93SDouglas Gilbert 	}
4855f0d1cf93SDouglas Gilbert 
4856f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4857f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4858f0d1cf93SDouglas Gilbert 
4859aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4860aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4861aa8fecf9SDamien Le Moal 		return -EINVAL;
4862aa8fecf9SDamien Le Moal 	}
4863aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4864aa8fecf9SDamien Le Moal 
486564e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
486664e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4867380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4868f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4869f0d1cf93SDouglas Gilbert 		else
4870380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
487164e14eceSDamien Le Moal 	}
4872f0d1cf93SDouglas Gilbert 
4873f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4874f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4875f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4876f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4877f0d1cf93SDouglas Gilbert 
4878f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4879f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4880f0d1cf93SDouglas Gilbert 
4881f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4882f0d1cf93SDouglas Gilbert 
4883aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
488464e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4885f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4886f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4887f0d1cf93SDouglas Gilbert 		} else {
488864e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
488964e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
489064e14eceSDamien Le Moal 			else
489164e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4892f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4893f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4894f0d1cf93SDouglas Gilbert 		}
4895f0d1cf93SDouglas Gilbert 
4896f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4897f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4898f0d1cf93SDouglas Gilbert 		else
4899f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4900f0d1cf93SDouglas Gilbert 
4901f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4902f0d1cf93SDouglas Gilbert 	}
4903f0d1cf93SDouglas Gilbert 
4904f0d1cf93SDouglas Gilbert 	return 0;
4905f0d1cf93SDouglas Gilbert }
4906f0d1cf93SDouglas Gilbert 
4907fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4908fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
49095cb2fc06SFUJITA Tomonori {
49105cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
49115cb2fc06SFUJITA Tomonori 
49125cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
49135cb2fc06SFUJITA Tomonori 	if (devip) {
491409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4915bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
491609ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
491709ba24c1SDouglas Gilbert 			if (got_shared_uuid)
491809ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
491909ba24c1SDouglas Gilbert 			else {
4920bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
492109ba24c1SDouglas Gilbert 				got_shared_uuid = true;
492209ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
492309ba24c1SDouglas Gilbert 			}
492409ba24c1SDouglas Gilbert 		}
49255cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4926f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
492764e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4928f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4929f0d1cf93SDouglas Gilbert 				kfree(devip);
4930f0d1cf93SDouglas Gilbert 				return NULL;
4931f0d1cf93SDouglas Gilbert 			}
493264e14eceSDamien Le Moal 		} else {
493364e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4934f0d1cf93SDouglas Gilbert 		}
4935f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
4936fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
4937fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
49385cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49395cb2fc06SFUJITA Tomonori 	}
49405cb2fc06SFUJITA Tomonori 	return devip;
49415cb2fc06SFUJITA Tomonori }
49425cb2fc06SFUJITA Tomonori 
4943f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49441da177e4SLinus Torvalds {
49451da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49461da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4947f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49481da177e4SLinus Torvalds 
4949d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49501da177e4SLinus Torvalds 	if (!sdbg_host) {
4951c1287970STomas Winkler 		pr_err("Host info NULL\n");
49521da177e4SLinus Torvalds 		return NULL;
49531da177e4SLinus Torvalds 	}
4954ad0c7775SDouglas Gilbert 
49551da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49561da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49571da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49581da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49591da177e4SLinus Torvalds 			return devip;
49601da177e4SLinus Torvalds 		else {
49611da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49621da177e4SLinus Torvalds 				open_devip = devip;
49631da177e4SLinus Torvalds 		}
49641da177e4SLinus Torvalds 	}
49655cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49665cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49675cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4968c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49691da177e4SLinus Torvalds 			return NULL;
49701da177e4SLinus Torvalds 		}
49711da177e4SLinus Torvalds 	}
4972a75869d1SFUJITA Tomonori 
49731da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
49741da177e4SLinus Torvalds 	open_devip->target = sdev->id;
49751da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
49761da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4977cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4978cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4979c2248fc9SDouglas Gilbert 	open_devip->used = true;
49801da177e4SLinus Torvalds 	return open_devip;
49811da177e4SLinus Torvalds }
49821da177e4SLinus Torvalds 
49838dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
49841da177e4SLinus Torvalds {
4985773642d9SDouglas Gilbert 	if (sdebug_verbose)
4986c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
49878dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49888dea0d02SFUJITA Tomonori 	return 0;
49898dea0d02SFUJITA Tomonori }
49901da177e4SLinus Torvalds 
49918dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
49928dea0d02SFUJITA Tomonori {
4993f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4994f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4995a34c4e98SFUJITA Tomonori 
4996773642d9SDouglas Gilbert 	if (sdebug_verbose)
4997c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
49988dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4999b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5000b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5001b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5002f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5003b01f6f83SDouglas Gilbert 		if (devip == NULL)
50048dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5005f46eb0e9SDouglas Gilbert 	}
5006c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5007773642d9SDouglas Gilbert 	if (sdebug_no_uld)
500878d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
50099b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
50108dea0d02SFUJITA Tomonori 	return 0;
50118dea0d02SFUJITA Tomonori }
50128dea0d02SFUJITA Tomonori 
50138dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
50148dea0d02SFUJITA Tomonori {
50158dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
50168dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
50178dea0d02SFUJITA Tomonori 
5018773642d9SDouglas Gilbert 	if (sdebug_verbose)
5019c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
50208dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50218dea0d02SFUJITA Tomonori 	if (devip) {
502225985edcSLucas De Marchi 		/* make this slot available for re-use */
5023c2248fc9SDouglas Gilbert 		devip->used = false;
50248dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
50258dea0d02SFUJITA Tomonori 	}
50268dea0d02SFUJITA Tomonori }
50278dea0d02SFUJITA Tomonori 
502810bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
502910bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5030c4837394SDouglas Gilbert {
5031c4837394SDouglas Gilbert 	if (!sd_dp)
5032c4837394SDouglas Gilbert 		return;
503310bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5034c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
503510bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5036c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5037c4837394SDouglas Gilbert }
5038c4837394SDouglas Gilbert 
5039a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5040a10bc12aSDouglas Gilbert    returns false */
5041a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50428dea0d02SFUJITA Tomonori {
50438dea0d02SFUJITA Tomonori 	unsigned long iflags;
5044c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
504510bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5046c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50478dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5048cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5049a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50508dea0d02SFUJITA Tomonori 
5051c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5052c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5053773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5054cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5055cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5056cbf67842SDouglas Gilbert 			qmax = r_qmax;
5057cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5058c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5059c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5060a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5061a10bc12aSDouglas Gilbert 					continue;
5062c4837394SDouglas Gilbert 				/* found */
5063db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5064db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5065db525fceSDouglas Gilbert 				if (devip)
5066db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5067db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5068a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
506910bde980SDouglas Gilbert 				if (sd_dp) {
507010bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
507110bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
507210bde980SDouglas Gilbert 				} else
507310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5074c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
507510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5076c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5077a10bc12aSDouglas Gilbert 				return true;
50788dea0d02SFUJITA Tomonori 			}
5079cbf67842SDouglas Gilbert 		}
5080c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5081c4837394SDouglas Gilbert 	}
5082a10bc12aSDouglas Gilbert 	return false;
50838dea0d02SFUJITA Tomonori }
50848dea0d02SFUJITA Tomonori 
5085a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
50868dea0d02SFUJITA Tomonori static void stop_all_queued(void)
50878dea0d02SFUJITA Tomonori {
50888dea0d02SFUJITA Tomonori 	unsigned long iflags;
5089c4837394SDouglas Gilbert 	int j, k;
509010bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5091c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50928dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5093cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5094a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50958dea0d02SFUJITA Tomonori 
5096c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5097c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5098c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5099c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5100c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5101c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5102a10bc12aSDouglas Gilbert 					continue;
5103db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5104db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5105db525fceSDouglas Gilbert 				if (devip)
5106db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5107db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5108a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
510910bde980SDouglas Gilbert 				if (sd_dp) {
511010bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
511110bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
511210bde980SDouglas Gilbert 				} else
511310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5114c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
511510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5116c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5117c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
51188dea0d02SFUJITA Tomonori 			}
51198dea0d02SFUJITA Tomonori 		}
5120c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5121c4837394SDouglas Gilbert 	}
5122cbf67842SDouglas Gilbert }
5123cbf67842SDouglas Gilbert 
5124cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5125cbf67842SDouglas Gilbert static void free_all_queued(void)
5126cbf67842SDouglas Gilbert {
5127c4837394SDouglas Gilbert 	int j, k;
5128c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5129cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5130cbf67842SDouglas Gilbert 
5131c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5132c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5133c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5134a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5135a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5136cbf67842SDouglas Gilbert 		}
51371da177e4SLinus Torvalds 	}
5138c4837394SDouglas Gilbert }
51391da177e4SLinus Torvalds 
51401da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51411da177e4SLinus Torvalds {
5142a10bc12aSDouglas Gilbert 	bool ok;
5143a10bc12aSDouglas Gilbert 
51441da177e4SLinus Torvalds 	++num_aborts;
5145cbf67842SDouglas Gilbert 	if (SCpnt) {
5146a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5147a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5148a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5149a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5150a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5151cbf67842SDouglas Gilbert 	}
51521da177e4SLinus Torvalds 	return SUCCESS;
51531da177e4SLinus Torvalds }
51541da177e4SLinus Torvalds 
51551da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51561da177e4SLinus Torvalds {
51571da177e4SLinus Torvalds 	++num_dev_resets;
5158cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5159cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5160f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5161f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5162cbf67842SDouglas Gilbert 
5163773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5164cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51651da177e4SLinus Torvalds 		if (devip)
5166cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51671da177e4SLinus Torvalds 	}
51681da177e4SLinus Torvalds 	return SUCCESS;
51691da177e4SLinus Torvalds }
51701da177e4SLinus Torvalds 
5171cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5172cbf67842SDouglas Gilbert {
5173cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5174cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5175cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5176cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5177cbf67842SDouglas Gilbert 	int k = 0;
5178cbf67842SDouglas Gilbert 
5179cbf67842SDouglas Gilbert 	++num_target_resets;
5180cbf67842SDouglas Gilbert 	if (!SCpnt)
5181cbf67842SDouglas Gilbert 		goto lie;
5182cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5183cbf67842SDouglas Gilbert 	if (!sdp)
5184cbf67842SDouglas Gilbert 		goto lie;
5185773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5186cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5187cbf67842SDouglas Gilbert 	hp = sdp->host;
5188cbf67842SDouglas Gilbert 	if (!hp)
5189cbf67842SDouglas Gilbert 		goto lie;
5190cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5191cbf67842SDouglas Gilbert 	if (sdbg_host) {
5192cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5193cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5194cbf67842SDouglas Gilbert 				    dev_list)
5195cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5196cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5197cbf67842SDouglas Gilbert 				++k;
5198cbf67842SDouglas Gilbert 			}
5199cbf67842SDouglas Gilbert 	}
5200773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5201cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5202cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5203cbf67842SDouglas Gilbert lie:
5204cbf67842SDouglas Gilbert 	return SUCCESS;
5205cbf67842SDouglas Gilbert }
5206cbf67842SDouglas Gilbert 
52071da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
52081da177e4SLinus Torvalds {
52091da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5210cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
52111da177e4SLinus Torvalds 	struct scsi_device *sdp;
52121da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5213cbf67842SDouglas Gilbert 	int k = 0;
52141da177e4SLinus Torvalds 
52151da177e4SLinus Torvalds 	++num_bus_resets;
5216cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5217cbf67842SDouglas Gilbert 		goto lie;
5218cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5219773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5220cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5221cbf67842SDouglas Gilbert 	hp = sdp->host;
5222cbf67842SDouglas Gilbert 	if (hp) {
5223d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52241da177e4SLinus Torvalds 		if (sdbg_host) {
5225cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
52261da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5227cbf67842SDouglas Gilbert 					    dev_list) {
5228cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5229cbf67842SDouglas Gilbert 				++k;
52301da177e4SLinus Torvalds 			}
52311da177e4SLinus Torvalds 		}
5232cbf67842SDouglas Gilbert 	}
5233773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5234cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5235cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5236cbf67842SDouglas Gilbert lie:
52371da177e4SLinus Torvalds 	return SUCCESS;
52381da177e4SLinus Torvalds }
52391da177e4SLinus Torvalds 
52401da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52411da177e4SLinus Torvalds {
52421da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5243cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5244cbf67842SDouglas Gilbert 	int k = 0;
52451da177e4SLinus Torvalds 
52461da177e4SLinus Torvalds 	++num_host_resets;
5247773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5248cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52491da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52501da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5251cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5252cbf67842SDouglas Gilbert 				    dev_list) {
5253cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5254cbf67842SDouglas Gilbert 			++k;
5255cbf67842SDouglas Gilbert 		}
52561da177e4SLinus Torvalds 	}
52571da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52581da177e4SLinus Torvalds 	stop_all_queued();
5259773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5260cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5261cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
52621da177e4SLinus Torvalds 	return SUCCESS;
52631da177e4SLinus Torvalds }
52641da177e4SLinus Torvalds 
526587c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52661da177e4SLinus Torvalds {
52671442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5268979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
52691da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
52701da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
52711da177e4SLinus Torvalds 
52721da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5273773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
52741da177e4SLinus Torvalds 		return;
5275773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5276773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5277c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
52781da177e4SLinus Torvalds 	}
5279c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
52801da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5281773642d9SDouglas Gilbert 			   / sdebug_num_parts;
52821da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
52831da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5284979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5285979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
52861da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
52871da177e4SLinus Torvalds 			    * heads_by_sects;
5288979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5289979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5290979e0dc3SJohn Pittman 	}
5291773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5292773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
52931da177e4SLinus Torvalds 
52941da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
52951da177e4SLinus Torvalds 	ramp[511] = 0xAA;
52961442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
52971da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
52981da177e4SLinus Torvalds 		start_sec = starts[k];
5299979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
53001da177e4SLinus Torvalds 		pp->boot_ind = 0;
53011da177e4SLinus Torvalds 
53021da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
53031da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
53041da177e4SLinus Torvalds 			   / sdebug_sectors_per;
53051da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
53061da177e4SLinus Torvalds 
53071da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
53081da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
53091da177e4SLinus Torvalds 			       / sdebug_sectors_per;
53101da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
53111da177e4SLinus Torvalds 
5312150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5313150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
53141da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
53151da177e4SLinus Torvalds 	}
53161da177e4SLinus Torvalds }
53171da177e4SLinus Torvalds 
5318c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5319c4837394SDouglas Gilbert {
5320c4837394SDouglas Gilbert 	int j;
5321c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5322c4837394SDouglas Gilbert 
5323c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5324c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5325c4837394SDouglas Gilbert }
5326c4837394SDouglas Gilbert 
5327c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5328c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5329c4837394SDouglas Gilbert  */
5330c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5331c4837394SDouglas Gilbert {
5332c4837394SDouglas Gilbert 	int count, modulo;
5333c4837394SDouglas Gilbert 
5334c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5335c4837394SDouglas Gilbert 	if (modulo < 2)
5336c4837394SDouglas Gilbert 		return;
5337c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5338c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5339c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5340c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5341c4837394SDouglas Gilbert }
5342c4837394SDouglas Gilbert 
5343c4837394SDouglas Gilbert static void clear_queue_stats(void)
5344c4837394SDouglas Gilbert {
5345c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5346c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5347c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5348c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5349c4837394SDouglas Gilbert }
5350c4837394SDouglas Gilbert 
53513a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5352c4837394SDouglas Gilbert {
53533a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
53543a90a63dSDouglas Gilbert 		return false;
53553a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5356c4837394SDouglas Gilbert }
5357c4837394SDouglas Gilbert 
5358a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5359a2aede97SDouglas Gilbert 
5360c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5361c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5362c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5363c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5364c4837394SDouglas Gilbert  */
5365fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5366f66b8517SMartin Wilck 			 int scsi_result,
5367f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5368f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5369f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
53701da177e4SLinus Torvalds {
5371a2aede97SDouglas Gilbert 	bool new_sd_dp;
53723a90a63dSDouglas Gilbert 	bool inject = false;
53733a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5374a2aede97SDouglas Gilbert 	unsigned long iflags;
5375a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5376c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5377c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5378299b6c07STomas Winkler 	struct scsi_device *sdp;
5379a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53801da177e4SLinus Torvalds 
5381b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5382b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5383f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5384f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
53851da177e4SLinus Torvalds 	}
5386299b6c07STomas Winkler 	sdp = cmnd->device;
5387299b6c07STomas Winkler 
5388cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5389cd62b7daSDouglas Gilbert 		goto respond_in_thread;
53901da177e4SLinus Torvalds 
5391c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5392c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5393c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5394c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5395c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5396c4837394SDouglas Gilbert 	}
5397cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5398cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5399f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5400cd62b7daSDouglas Gilbert 		if (scsi_result) {
5401c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5402cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5403cd62b7daSDouglas Gilbert 		} else
5404cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5405c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5406773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5407f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5408cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5409cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5410773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5411cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
54123a90a63dSDouglas Gilbert 			inject = true;
5413cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
54141da177e4SLinus Torvalds 		}
5415cbf67842SDouglas Gilbert 	}
5416cbf67842SDouglas Gilbert 
5417c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5418f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5419c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5420cd62b7daSDouglas Gilbert 		if (scsi_result)
5421cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5422773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5423cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5424773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5425cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5426cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5427773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5428cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5429cbf67842SDouglas Gilbert 						    "report: host busy"));
5430cd62b7daSDouglas Gilbert 		if (scsi_result)
5431cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5432cd62b7daSDouglas Gilbert 		else
5433cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
54341da177e4SLinus Torvalds 	}
543574595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5436cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5437c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
54381da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5439c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5440a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5441c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
544274595c04SDouglas Gilbert 	if (!sd_dp) {
544310bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
544474595c04SDouglas Gilbert 		if (!sd_dp) {
544574595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
544674595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
544710bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
544874595c04SDouglas Gilbert 		}
5449a2aede97SDouglas Gilbert 		new_sd_dp = true;
5450a2aede97SDouglas Gilbert 	} else {
5451a2aede97SDouglas Gilbert 		new_sd_dp = false;
545210bde980SDouglas Gilbert 	}
5453f66b8517SMartin Wilck 
5454c10fa55fSJohn Garry 	/* Set the hostwide tag */
5455c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5456c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5457c10fa55fSJohn Garry 
5458a2aede97SDouglas Gilbert 	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
5459a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5460a2aede97SDouglas Gilbert 
5461a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
54623a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5463f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5464f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5465f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5466f66b8517SMartin Wilck 	}
5467f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5468f66b8517SMartin Wilck 		cmnd->result = scsi_result;
54693a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
54703a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
54713a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
54723a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
54733a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
54743a90a63dSDouglas Gilbert 		}
54753a90a63dSDouglas Gilbert 	}
5476f66b8517SMartin Wilck 
5477f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5478f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5479f66b8517SMartin Wilck 			    __func__, cmnd->result);
5480f66b8517SMartin Wilck 
548110bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5482b333a819SDouglas Gilbert 		ktime_t kt;
5483cbf67842SDouglas Gilbert 
5484b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
54850c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
54860c4bc91dSDouglas Gilbert 
54870c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
54880c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
54890c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
54900c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
54910c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
54920c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
54930c4bc91dSDouglas Gilbert 				ns <<= 12;
54940c4bc91dSDouglas Gilbert 			}
54950c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
54960c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
54970c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
54980c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5499a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5500a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5501a2aede97SDouglas Gilbert 
5502a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5503a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5504a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5505a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5506a2aede97SDouglas Gilbert 					if (new_sd_dp)
5507a2aede97SDouglas Gilbert 						kfree(sd_dp);
5508a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
5509a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
5510a2aede97SDouglas Gilbert 					return 0;
5511a2aede97SDouglas Gilbert 				}
5512a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5513a2aede97SDouglas Gilbert 				kt -= d;
5514a2aede97SDouglas Gilbert 			}
55150c4bc91dSDouglas Gilbert 		}
551610bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
551710bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
5518a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5519a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5520c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
5521a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5522c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5523c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5524cbf67842SDouglas Gilbert 		}
5525c4837394SDouglas Gilbert 		if (sdebug_statistics)
5526c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
552710bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
5528a2aede97SDouglas Gilbert 		/* schedule the invocation of scsi_done() for a later time */
5529c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
5530c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
553110bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
553210bde980SDouglas Gilbert 			sd_dp->init_wq = true;
5533a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5534c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5535c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5536a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5537cbf67842SDouglas Gilbert 		}
5538c4837394SDouglas Gilbert 		if (sdebug_statistics)
5539c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
554010bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
55413a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55423a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
55437382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
5544a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
55453a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55463a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
55473a90a63dSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
55487382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
55493a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
55507382f9d8SDouglas Gilbert 		}
5551cbf67842SDouglas Gilbert 	}
55523a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
55533a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
55543a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
55551da177e4SLinus Torvalds 	return 0;
5556cd62b7daSDouglas Gilbert 
5557cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5558f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5559f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5560f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5561cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
5562cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
5563cd62b7daSDouglas Gilbert 	return 0;
55641da177e4SLinus Torvalds }
5565cbf67842SDouglas Gilbert 
556623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
556723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
556823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
556923183910SDouglas Gilbert    as it can when the corresponding attribute in the
557023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
557123183910SDouglas Gilbert  */
5572773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5573773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
55749b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5575773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5576c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5577773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5578773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5579773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5580773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5581773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5582773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5583773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5584773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5585c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5586e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5587e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5588e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5589e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
55905d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
55915d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
55925d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5593773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5594773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5595773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5596773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5597ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5598773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5599773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
56005d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
56015d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56025d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
56035d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5604773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5605773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5606773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5607773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5608773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5609773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
56105d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5611773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
561287c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
561387c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5614773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5615773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
56160c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5617773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5618773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5619773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5620c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5621773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5622c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5623fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5624773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5625773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5626773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5627773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
562809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
56295d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5630773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
563123183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56329447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5633773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
56345b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
56359267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5636380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5637aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
563898e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56391da177e4SLinus Torvalds 
56401da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56411da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
56421da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5643b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
56441da177e4SLinus Torvalds 
56455d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56465b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56479b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56480759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5649cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5650c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
56515b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
56525b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5653c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5654beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
565523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
56565b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5657185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5658c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5659c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5660e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
56619b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
56629b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
56635d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
56645d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
56655d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
56665b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
56675b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
56685b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
56695b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5670c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5671ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5672cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5673d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
56745d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5675cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5676c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
567778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
56781da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5679c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
568032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
568186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
56825d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
56835d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
56845d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
56851da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
56860c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5687d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5688760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5689ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5690c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5691c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5692c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5693fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
56945b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
56955b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
56966014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
56976014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
569809ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
569909ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5700c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
57015b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
57029447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
57035b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
57049267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5705380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5706aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
570798e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
57081da177e4SLinus Torvalds 
5709760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5710760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
57111da177e4SLinus Torvalds 
57121da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
57131da177e4SLinus Torvalds {
5714c4837394SDouglas Gilbert 	int k;
5715c4837394SDouglas Gilbert 
5716760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5717760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5718760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5719c4837394SDouglas Gilbert 		return sdebug_info;
5720760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5721760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5722760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5723760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
57241da177e4SLinus Torvalds 	return sdebug_info;
57251da177e4SLinus Torvalds }
57261da177e4SLinus Torvalds 
5727cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5728fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5729fd32119bSDouglas Gilbert 				 int length)
57301da177e4SLinus Torvalds {
57311da177e4SLinus Torvalds 	char arr[16];
5732c8ed555aSAl Viro 	int opts;
57331da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
57341da177e4SLinus Torvalds 
57351da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
57361da177e4SLinus Torvalds 		return -EACCES;
57371da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
57381da177e4SLinus Torvalds 	arr[minLen] = '\0';
5739c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
57401da177e4SLinus Torvalds 		return -EINVAL;
5741773642d9SDouglas Gilbert 	sdebug_opts = opts;
5742773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5743773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5744773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5745c4837394SDouglas Gilbert 		tweak_cmnd_count();
57461da177e4SLinus Torvalds 	return length;
57471da177e4SLinus Torvalds }
5748c8ed555aSAl Viro 
5749cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5750cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5751cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5752c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5753c8ed555aSAl Viro {
5754c4837394SDouglas Gilbert 	int f, j, l;
5755c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
575687c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5757cbf67842SDouglas Gilbert 
5758c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5759c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5760c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5761c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5762c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5763c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5764c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5765c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5766c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5767c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5768c4837394SDouglas Gilbert 		   num_aborts);
5769c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5770c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5771c4837394SDouglas Gilbert 		   num_host_resets);
5772c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5773c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5774458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5775458df78bSBart Van Assche 		   sdebug_statistics);
5776c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
5777c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5778c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5779c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
5780c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
5781cbf67842SDouglas Gilbert 
5782c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5783c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5784c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5785c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5786773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5787c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5788c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5789c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5790c4837394SDouglas Gilbert 		}
5791cbf67842SDouglas Gilbert 	}
579287c715dcSDouglas Gilbert 
579387c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
579487c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
579587c715dcSDouglas Gilbert 		bool niu;
579687c715dcSDouglas Gilbert 		int idx;
579787c715dcSDouglas Gilbert 		unsigned long l_idx;
579887c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
579987c715dcSDouglas Gilbert 
580087c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
580187c715dcSDouglas Gilbert 		j = 0;
580287c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
580387c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
580487c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
580587c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
580687c715dcSDouglas Gilbert 			++j;
580787c715dcSDouglas Gilbert 		}
580887c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
580987c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
581087c715dcSDouglas Gilbert 		j = 0;
581187c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
581287c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
581387c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
581487c715dcSDouglas Gilbert 			idx = (int)l_idx;
581587c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
581687c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
581787c715dcSDouglas Gilbert 			++j;
581887c715dcSDouglas Gilbert 		}
581987c715dcSDouglas Gilbert 	}
5820c8ed555aSAl Viro 	return 0;
58211da177e4SLinus Torvalds }
58221da177e4SLinus Torvalds 
582382069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
58241da177e4SLinus Torvalds {
5825c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
58261da177e4SLinus Torvalds }
5827c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5828c4837394SDouglas Gilbert  * of delay is jiffies.
5829c4837394SDouglas Gilbert  */
583082069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
583182069379SAkinobu Mita 			   size_t count)
58321da177e4SLinus Torvalds {
5833c2206098SDouglas Gilbert 	int jdelay, res;
58341da177e4SLinus Torvalds 
5835b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5836cbf67842SDouglas Gilbert 		res = count;
5837c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5838c4837394SDouglas Gilbert 			int j, k;
5839c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5840cbf67842SDouglas Gilbert 
5841c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5842c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5843c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5844c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5845c4837394SDouglas Gilbert 						   sdebug_max_queue);
5846c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5847c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5848c4837394SDouglas Gilbert 					break;
5849c4837394SDouglas Gilbert 				}
5850c4837394SDouglas Gilbert 			}
5851c4837394SDouglas Gilbert 			if (res > 0) {
5852c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5853773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
58541da177e4SLinus Torvalds 			}
5855c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5856cbf67842SDouglas Gilbert 		}
5857cbf67842SDouglas Gilbert 		return res;
58581da177e4SLinus Torvalds 	}
58591da177e4SLinus Torvalds 	return -EINVAL;
58601da177e4SLinus Torvalds }
586182069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
58621da177e4SLinus Torvalds 
5863cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5864cbf67842SDouglas Gilbert {
5865773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5866cbf67842SDouglas Gilbert }
5867cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5868c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5869cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5870cbf67842SDouglas Gilbert 			    size_t count)
5871cbf67842SDouglas Gilbert {
5872c4837394SDouglas Gilbert 	int ndelay, res;
5873cbf67842SDouglas Gilbert 
5874cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5875c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5876cbf67842SDouglas Gilbert 		res = count;
5877773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5878c4837394SDouglas Gilbert 			int j, k;
5879c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5880c4837394SDouglas Gilbert 
5881c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5882c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5883c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5884c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5885c4837394SDouglas Gilbert 						   sdebug_max_queue);
5886c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5887c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5888c4837394SDouglas Gilbert 					break;
5889c4837394SDouglas Gilbert 				}
5890c4837394SDouglas Gilbert 			}
5891c4837394SDouglas Gilbert 			if (res > 0) {
5892773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5893c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5894c2206098SDouglas Gilbert 							: DEF_JDELAY;
5895cbf67842SDouglas Gilbert 			}
5896c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5897cbf67842SDouglas Gilbert 		}
5898cbf67842SDouglas Gilbert 		return res;
5899cbf67842SDouglas Gilbert 	}
5900cbf67842SDouglas Gilbert 	return -EINVAL;
5901cbf67842SDouglas Gilbert }
5902cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5903cbf67842SDouglas Gilbert 
590482069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
59051da177e4SLinus Torvalds {
5906773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
59071da177e4SLinus Torvalds }
59081da177e4SLinus Torvalds 
590982069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
591082069379SAkinobu Mita 			  size_t count)
59111da177e4SLinus Torvalds {
59121da177e4SLinus Torvalds 	int opts;
59131da177e4SLinus Torvalds 	char work[20];
59141da177e4SLinus Torvalds 
59159a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
59169a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
59179a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
59181da177e4SLinus Torvalds 				goto opts_done;
59191da177e4SLinus Torvalds 		} else {
59209a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
59211da177e4SLinus Torvalds 				goto opts_done;
59221da177e4SLinus Torvalds 		}
59231da177e4SLinus Torvalds 	}
59241da177e4SLinus Torvalds 	return -EINVAL;
59251da177e4SLinus Torvalds opts_done:
5926773642d9SDouglas Gilbert 	sdebug_opts = opts;
5927773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5928773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5929c4837394SDouglas Gilbert 	tweak_cmnd_count();
59301da177e4SLinus Torvalds 	return count;
59311da177e4SLinus Torvalds }
593282069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
59331da177e4SLinus Torvalds 
593482069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
59351da177e4SLinus Torvalds {
5936773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
59371da177e4SLinus Torvalds }
593882069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
593982069379SAkinobu Mita 			   size_t count)
59401da177e4SLinus Torvalds {
59411da177e4SLinus Torvalds 	int n;
59421da177e4SLinus Torvalds 
5943f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5944f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5945f0d1cf93SDouglas Gilbert 		return -EINVAL;
5946f0d1cf93SDouglas Gilbert 
59471da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5948f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
5949f0d1cf93SDouglas Gilbert 			return -EINVAL;
5950773642d9SDouglas Gilbert 		sdebug_ptype = n;
59511da177e4SLinus Torvalds 		return count;
59521da177e4SLinus Torvalds 	}
59531da177e4SLinus Torvalds 	return -EINVAL;
59541da177e4SLinus Torvalds }
595582069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
59561da177e4SLinus Torvalds 
595782069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
59581da177e4SLinus Torvalds {
5959773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
59601da177e4SLinus Torvalds }
596182069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
596282069379SAkinobu Mita 			    size_t count)
59631da177e4SLinus Torvalds {
59641da177e4SLinus Torvalds 	int n;
59651da177e4SLinus Torvalds 
59661da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5967773642d9SDouglas Gilbert 		sdebug_dsense = n;
59681da177e4SLinus Torvalds 		return count;
59691da177e4SLinus Torvalds 	}
59701da177e4SLinus Torvalds 	return -EINVAL;
59711da177e4SLinus Torvalds }
597282069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
59731da177e4SLinus Torvalds 
597482069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
597523183910SDouglas Gilbert {
5976773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
597723183910SDouglas Gilbert }
597882069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
597982069379SAkinobu Mita 			     size_t count)
598023183910SDouglas Gilbert {
598187c715dcSDouglas Gilbert 	int n, idx;
598223183910SDouglas Gilbert 
598323183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
598487c715dcSDouglas Gilbert 		bool want_store = (n == 0);
598587c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
598687c715dcSDouglas Gilbert 
5987cbf67842SDouglas Gilbert 		n = (n > 0);
5988773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
598987c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
599087c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
5991cbf67842SDouglas Gilbert 
599287c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
599387c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
599487c715dcSDouglas Gilbert 				idx = sdebug_add_store();
599587c715dcSDouglas Gilbert 				if (idx < 0)
599687c715dcSDouglas Gilbert 					return idx;
599787c715dcSDouglas Gilbert 			} else {
599887c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
599987c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
600087c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6001cbf67842SDouglas Gilbert 			}
600287c715dcSDouglas Gilbert 			/* make all hosts use same store */
600387c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
600487c715dcSDouglas Gilbert 					    host_list) {
600587c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
600687c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
600787c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
600887c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
600987c715dcSDouglas Gilbert 				}
601087c715dcSDouglas Gilbert 			}
601187c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
601287c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
601387c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6014cbf67842SDouglas Gilbert 		}
6015773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
601623183910SDouglas Gilbert 		return count;
601723183910SDouglas Gilbert 	}
601823183910SDouglas Gilbert 	return -EINVAL;
601923183910SDouglas Gilbert }
602082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
602123183910SDouglas Gilbert 
602282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6023c65b1445SDouglas Gilbert {
6024773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6025c65b1445SDouglas Gilbert }
602682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
602782069379SAkinobu Mita 			      size_t count)
6028c65b1445SDouglas Gilbert {
6029c65b1445SDouglas Gilbert 	int n;
6030c65b1445SDouglas Gilbert 
6031c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6032773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6033c65b1445SDouglas Gilbert 		return count;
6034c65b1445SDouglas Gilbert 	}
6035c65b1445SDouglas Gilbert 	return -EINVAL;
6036c65b1445SDouglas Gilbert }
603782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6038c65b1445SDouglas Gilbert 
603982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
60401da177e4SLinus Torvalds {
6041773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60421da177e4SLinus Torvalds }
604382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
604482069379SAkinobu Mita 			      size_t count)
60451da177e4SLinus Torvalds {
60461da177e4SLinus Torvalds 	int n;
60471da177e4SLinus Torvalds 
60481da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6049773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
60501da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
60511da177e4SLinus Torvalds 		return count;
60521da177e4SLinus Torvalds 	}
60531da177e4SLinus Torvalds 	return -EINVAL;
60541da177e4SLinus Torvalds }
605582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
60561da177e4SLinus Torvalds 
605782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
60581da177e4SLinus Torvalds {
6059773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
60601da177e4SLinus Torvalds }
606182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
60621da177e4SLinus Torvalds 
606387c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
606487c715dcSDouglas Gilbert {
606587c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
606687c715dcSDouglas Gilbert }
606787c715dcSDouglas Gilbert 
606887c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
606987c715dcSDouglas Gilbert 				    size_t count)
607087c715dcSDouglas Gilbert {
607187c715dcSDouglas Gilbert 	bool v;
607287c715dcSDouglas Gilbert 
607387c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
607487c715dcSDouglas Gilbert 		return -EINVAL;
607587c715dcSDouglas Gilbert 
607687c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
607787c715dcSDouglas Gilbert 	return count;
607887c715dcSDouglas Gilbert }
607987c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
608087c715dcSDouglas Gilbert 
608182069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
60821da177e4SLinus Torvalds {
6083773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
60841da177e4SLinus Torvalds }
608582069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
60861da177e4SLinus Torvalds 
608782069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
60881da177e4SLinus Torvalds {
6089773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
60901da177e4SLinus Torvalds }
609182069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
609282069379SAkinobu Mita 			       size_t count)
60931da177e4SLinus Torvalds {
60941da177e4SLinus Torvalds 	int nth;
60953a90a63dSDouglas Gilbert 	char work[20];
60961da177e4SLinus Torvalds 
60973a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
60983a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
60993a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
61003a90a63dSDouglas Gilbert 				goto every_nth_done;
61013a90a63dSDouglas Gilbert 		} else {
61023a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
61033a90a63dSDouglas Gilbert 				goto every_nth_done;
61043a90a63dSDouglas Gilbert 		}
61053a90a63dSDouglas Gilbert 	}
61063a90a63dSDouglas Gilbert 	return -EINVAL;
61073a90a63dSDouglas Gilbert 
61083a90a63dSDouglas Gilbert every_nth_done:
6109773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6110c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6111c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6112c4837394SDouglas Gilbert 		sdebug_statistics = true;
6113c4837394SDouglas Gilbert 	}
6114c4837394SDouglas Gilbert 	tweak_cmnd_count();
61151da177e4SLinus Torvalds 	return count;
61161da177e4SLinus Torvalds }
611782069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
61181da177e4SLinus Torvalds 
6119ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6120ad0c7775SDouglas Gilbert {
6121ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6122ad0c7775SDouglas Gilbert }
6123ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6124ad0c7775SDouglas Gilbert 				size_t count)
6125ad0c7775SDouglas Gilbert {
6126ad0c7775SDouglas Gilbert 	int n;
6127ad0c7775SDouglas Gilbert 	bool changed;
6128ad0c7775SDouglas Gilbert 
6129ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6130ad0c7775SDouglas Gilbert 		return -EINVAL;
6131ad0c7775SDouglas Gilbert 	if (n >= 0) {
6132ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6133ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6134ad0c7775SDouglas Gilbert 			return -EINVAL;
6135ad0c7775SDouglas Gilbert 		}
6136ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6137ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6138ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6139ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6140ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6141ad0c7775SDouglas Gilbert 
6142ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6143ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6144ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6145ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6146ad0c7775SDouglas Gilbert 				}
6147ad0c7775SDouglas Gilbert 			}
6148ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6149ad0c7775SDouglas Gilbert 		}
6150ad0c7775SDouglas Gilbert 		return count;
6151ad0c7775SDouglas Gilbert 	}
6152ad0c7775SDouglas Gilbert 	return -EINVAL;
6153ad0c7775SDouglas Gilbert }
6154ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6155ad0c7775SDouglas Gilbert 
615682069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
61571da177e4SLinus Torvalds {
6158773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
61591da177e4SLinus Torvalds }
616082069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
616182069379SAkinobu Mita 			      size_t count)
61621da177e4SLinus Torvalds {
61631da177e4SLinus Torvalds 	int n;
616419c8ead7SEwan D. Milne 	bool changed;
61651da177e4SLinus Torvalds 
61661da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
61678d039e22SDouglas Gilbert 		if (n > 256) {
61688d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
61698d039e22SDouglas Gilbert 			return -EINVAL;
61708d039e22SDouglas Gilbert 		}
6171773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6172773642d9SDouglas Gilbert 		sdebug_max_luns = n;
61731da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6174773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
617519c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
617619c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
617719c8ead7SEwan D. Milne 
617819c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
617919c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
618019c8ead7SEwan D. Milne 					    host_list) {
618119c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
618219c8ead7SEwan D. Milne 						    dev_list) {
618319c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
618419c8ead7SEwan D. Milne 						dp->uas_bm);
618519c8ead7SEwan D. Milne 				}
618619c8ead7SEwan D. Milne 			}
618719c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
618819c8ead7SEwan D. Milne 		}
61891da177e4SLinus Torvalds 		return count;
61901da177e4SLinus Torvalds 	}
61911da177e4SLinus Torvalds 	return -EINVAL;
61921da177e4SLinus Torvalds }
619382069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
61941da177e4SLinus Torvalds 
619582069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
619678d4e5a0SDouglas Gilbert {
6197773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
619878d4e5a0SDouglas Gilbert }
6199cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6200cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
620182069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
620282069379SAkinobu Mita 			       size_t count)
620378d4e5a0SDouglas Gilbert {
6204c4837394SDouglas Gilbert 	int j, n, k, a;
6205c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
620678d4e5a0SDouglas Gilbert 
620778d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6208c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6209c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6210c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6211c4837394SDouglas Gilbert 		k = 0;
6212c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6213c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6214c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6215c4837394SDouglas Gilbert 			if (a > k)
6216c4837394SDouglas Gilbert 				k = a;
6217c4837394SDouglas Gilbert 		}
6218773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6219c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6220cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6221cbf67842SDouglas Gilbert 		else if (k >= n)
6222cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6223cbf67842SDouglas Gilbert 		else
6224cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6225c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
622678d4e5a0SDouglas Gilbert 		return count;
622778d4e5a0SDouglas Gilbert 	}
622878d4e5a0SDouglas Gilbert 	return -EINVAL;
622978d4e5a0SDouglas Gilbert }
623082069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
623178d4e5a0SDouglas Gilbert 
6232c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6233c10fa55fSJohn Garry {
6234c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6235c10fa55fSJohn Garry }
6236c10fa55fSJohn Garry 
6237c10fa55fSJohn Garry /*
6238c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6239c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6240c10fa55fSJohn Garry  */
6241c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6242c10fa55fSJohn Garry 
624382069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
624478d4e5a0SDouglas Gilbert {
6245773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
624678d4e5a0SDouglas Gilbert }
624782069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
624878d4e5a0SDouglas Gilbert 
624982069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
62501da177e4SLinus Torvalds {
6251773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
62521da177e4SLinus Torvalds }
625382069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
62541da177e4SLinus Torvalds 
625582069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6256c65b1445SDouglas Gilbert {
6257773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6258c65b1445SDouglas Gilbert }
625982069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
626082069379SAkinobu Mita 				size_t count)
6261c65b1445SDouglas Gilbert {
6262c65b1445SDouglas Gilbert 	int n;
62630d01c5dfSDouglas Gilbert 	bool changed;
6264c65b1445SDouglas Gilbert 
6265f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6266f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6267f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6268f0d1cf93SDouglas Gilbert 
6269c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6270773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6271773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
627228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
62730d01c5dfSDouglas Gilbert 		if (changed) {
62740d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
62750d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
627628898873SFUJITA Tomonori 
62774bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
62780d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
62790d01c5dfSDouglas Gilbert 					    host_list) {
62800d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
62810d01c5dfSDouglas Gilbert 						    dev_list) {
62820d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
62830d01c5dfSDouglas Gilbert 						dp->uas_bm);
62840d01c5dfSDouglas Gilbert 				}
62850d01c5dfSDouglas Gilbert 			}
62864bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
62870d01c5dfSDouglas Gilbert 		}
6288c65b1445SDouglas Gilbert 		return count;
6289c65b1445SDouglas Gilbert 	}
6290c65b1445SDouglas Gilbert 	return -EINVAL;
6291c65b1445SDouglas Gilbert }
629282069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6293c65b1445SDouglas Gilbert 
629482069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
62951da177e4SLinus Torvalds {
629687c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
629787c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
62981da177e4SLinus Torvalds }
62991da177e4SLinus Torvalds 
630082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
630182069379SAkinobu Mita 			      size_t count)
63021da177e4SLinus Torvalds {
630387c715dcSDouglas Gilbert 	bool found;
630487c715dcSDouglas Gilbert 	unsigned long idx;
630587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
630687c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
63071da177e4SLinus Torvalds 	int delta_hosts;
63081da177e4SLinus Torvalds 
6309f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
63101da177e4SLinus Torvalds 		return -EINVAL;
63111da177e4SLinus Torvalds 	if (delta_hosts > 0) {
63121da177e4SLinus Torvalds 		do {
631387c715dcSDouglas Gilbert 			found = false;
631487c715dcSDouglas Gilbert 			if (want_phs) {
631587c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
631687c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
631787c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
631887c715dcSDouglas Gilbert 					found = true;
631987c715dcSDouglas Gilbert 					break;
632087c715dcSDouglas Gilbert 				}
632187c715dcSDouglas Gilbert 				if (found)	/* re-use case */
632287c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
632387c715dcSDouglas Gilbert 				else
632487c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
632587c715dcSDouglas Gilbert 			} else {
632687c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
632787c715dcSDouglas Gilbert 			}
63281da177e4SLinus Torvalds 		} while (--delta_hosts);
63291da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
63301da177e4SLinus Torvalds 		do {
633187c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
63321da177e4SLinus Torvalds 		} while (++delta_hosts);
63331da177e4SLinus Torvalds 	}
63341da177e4SLinus Torvalds 	return count;
63351da177e4SLinus Torvalds }
633682069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
63371da177e4SLinus Torvalds 
633882069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
633923183910SDouglas Gilbert {
6340773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
634123183910SDouglas Gilbert }
634282069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
634382069379SAkinobu Mita 				    size_t count)
634423183910SDouglas Gilbert {
634523183910SDouglas Gilbert 	int n;
634623183910SDouglas Gilbert 
634723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6348773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
634923183910SDouglas Gilbert 		return count;
635023183910SDouglas Gilbert 	}
635123183910SDouglas Gilbert 	return -EINVAL;
635223183910SDouglas Gilbert }
635382069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
635423183910SDouglas Gilbert 
6355c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6356c4837394SDouglas Gilbert {
6357c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6358c4837394SDouglas Gilbert }
6359c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6360c4837394SDouglas Gilbert 				size_t count)
6361c4837394SDouglas Gilbert {
6362c4837394SDouglas Gilbert 	int n;
6363c4837394SDouglas Gilbert 
6364c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6365c4837394SDouglas Gilbert 		if (n > 0)
6366c4837394SDouglas Gilbert 			sdebug_statistics = true;
6367c4837394SDouglas Gilbert 		else {
6368c4837394SDouglas Gilbert 			clear_queue_stats();
6369c4837394SDouglas Gilbert 			sdebug_statistics = false;
6370c4837394SDouglas Gilbert 		}
6371c4837394SDouglas Gilbert 		return count;
6372c4837394SDouglas Gilbert 	}
6373c4837394SDouglas Gilbert 	return -EINVAL;
6374c4837394SDouglas Gilbert }
6375c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6376c4837394SDouglas Gilbert 
637782069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6378597136abSMartin K. Petersen {
6379773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6380597136abSMartin K. Petersen }
638182069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6382597136abSMartin K. Petersen 
6383c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6384c4837394SDouglas Gilbert {
6385c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6386c4837394SDouglas Gilbert }
6387c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6388c4837394SDouglas Gilbert 
638982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6390c6a44287SMartin K. Petersen {
6391773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6392c6a44287SMartin K. Petersen }
639382069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6394c6a44287SMartin K. Petersen 
639582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6396c6a44287SMartin K. Petersen {
6397773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6398c6a44287SMartin K. Petersen }
639982069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6400c6a44287SMartin K. Petersen 
640182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6402c6a44287SMartin K. Petersen {
6403773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6404c6a44287SMartin K. Petersen }
640582069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6406c6a44287SMartin K. Petersen 
640782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6408c6a44287SMartin K. Petersen {
6409773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6410c6a44287SMartin K. Petersen }
641182069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6412c6a44287SMartin K. Petersen 
641382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
641444d92694SMartin K. Petersen {
641587c715dcSDouglas Gilbert 	ssize_t count = 0;
641644d92694SMartin K. Petersen 
64175b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
641844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
641944d92694SMartin K. Petersen 				 sdebug_store_sectors);
642044d92694SMartin K. Petersen 
642187c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
642287c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
642387c715dcSDouglas Gilbert 
642487c715dcSDouglas Gilbert 		if (sip)
6425c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
642687c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
642787c715dcSDouglas Gilbert 	}
642844d92694SMartin K. Petersen 	buf[count++] = '\n';
6429c7badc90STejun Heo 	buf[count] = '\0';
643044d92694SMartin K. Petersen 
643144d92694SMartin K. Petersen 	return count;
643244d92694SMartin K. Petersen }
643382069379SAkinobu Mita static DRIVER_ATTR_RO(map);
643444d92694SMartin K. Petersen 
64350c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
64360c4bc91dSDouglas Gilbert {
64370c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
64380c4bc91dSDouglas Gilbert }
64390c4bc91dSDouglas Gilbert 
64400c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
64410c4bc91dSDouglas Gilbert 			    size_t count)
64420c4bc91dSDouglas Gilbert {
64430c4bc91dSDouglas Gilbert 	bool v;
64440c4bc91dSDouglas Gilbert 
64450c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
64460c4bc91dSDouglas Gilbert 		return -EINVAL;
64470c4bc91dSDouglas Gilbert 
64480c4bc91dSDouglas Gilbert 	sdebug_random = v;
64490c4bc91dSDouglas Gilbert 	return count;
64500c4bc91dSDouglas Gilbert }
64510c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
64520c4bc91dSDouglas Gilbert 
645382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6454d986788bSMartin Pitt {
6455773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6456d986788bSMartin Pitt }
645782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
645882069379SAkinobu Mita 			       size_t count)
6459d986788bSMartin Pitt {
6460d986788bSMartin Pitt 	int n;
6461d986788bSMartin Pitt 
6462d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6463773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6464d986788bSMartin Pitt 		return count;
6465d986788bSMartin Pitt 	}
6466d986788bSMartin Pitt 	return -EINVAL;
6467d986788bSMartin Pitt }
646882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6469d986788bSMartin Pitt 
6470cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6471cbf67842SDouglas Gilbert {
6472773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6473cbf67842SDouglas Gilbert }
6474185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6475cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6476cbf67842SDouglas Gilbert 			       size_t count)
6477cbf67842SDouglas Gilbert {
6478185dd232SDouglas Gilbert 	int n;
6479cbf67842SDouglas Gilbert 
6480cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6481185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6482185dd232SDouglas Gilbert 		return count;
6483cbf67842SDouglas Gilbert 	}
6484cbf67842SDouglas Gilbert 	return -EINVAL;
6485cbf67842SDouglas Gilbert }
6486cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6487cbf67842SDouglas Gilbert 
6488c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6489c2248fc9SDouglas Gilbert {
6490773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6491c2248fc9SDouglas Gilbert }
6492c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6493c2248fc9SDouglas Gilbert 			    size_t count)
6494c2248fc9SDouglas Gilbert {
6495c2248fc9SDouglas Gilbert 	int n;
6496c2248fc9SDouglas Gilbert 
6497c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6498773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6499c2248fc9SDouglas Gilbert 		return count;
6500c2248fc9SDouglas Gilbert 	}
6501c2248fc9SDouglas Gilbert 	return -EINVAL;
6502c2248fc9SDouglas Gilbert }
6503c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6504c2248fc9SDouglas Gilbert 
650509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
650609ba24c1SDouglas Gilbert {
650709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
650809ba24c1SDouglas Gilbert }
650909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
651009ba24c1SDouglas Gilbert 
65119b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
65129b760fd8SDouglas Gilbert {
65139b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
65149b760fd8SDouglas Gilbert }
65159b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
65169b760fd8SDouglas Gilbert 			     size_t count)
65179b760fd8SDouglas Gilbert {
65189b760fd8SDouglas Gilbert 	int ret, n;
65199b760fd8SDouglas Gilbert 
65209b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
65219b760fd8SDouglas Gilbert 	if (ret)
65229b760fd8SDouglas Gilbert 		return ret;
65239b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
65249b760fd8SDouglas Gilbert 	all_config_cdb_len();
65259b760fd8SDouglas Gilbert 	return count;
65269b760fd8SDouglas Gilbert }
65279b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
65289b760fd8SDouglas Gilbert 
65299267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
65309267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
65319267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
65329267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
65339267e0ebSDouglas Gilbert };
65349267e0ebSDouglas Gilbert 
65359267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
65369267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
65379267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
65389267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
65399267e0ebSDouglas Gilbert };
65409267e0ebSDouglas Gilbert 
65419267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
65429267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
65439267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
65449267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
65459267e0ebSDouglas Gilbert };
65469267e0ebSDouglas Gilbert 
65479267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
65489267e0ebSDouglas Gilbert {
65499267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
65509267e0ebSDouglas Gilbert 
65519267e0ebSDouglas Gilbert 	if (res < 0) {
65529267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
65539267e0ebSDouglas Gilbert 		if (res < 0) {
65549267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
655547742bdeSDan Carpenter 			if (res < 0)
65569267e0ebSDouglas Gilbert 				return -EINVAL;
65579267e0ebSDouglas Gilbert 		}
65589267e0ebSDouglas Gilbert 	}
65599267e0ebSDouglas Gilbert 	return res;
65609267e0ebSDouglas Gilbert }
65619267e0ebSDouglas Gilbert 
65629267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
65639267e0ebSDouglas Gilbert {
65649267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
65659267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
65669267e0ebSDouglas Gilbert }
65679267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6568cbf67842SDouglas Gilbert 
6569fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6570fc13638aSDouglas Gilbert {
6571fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6572fc13638aSDouglas Gilbert }
6573fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6574fc13638aSDouglas Gilbert 
657582069379SAkinobu Mita /* Note: The following array creates attribute files in the
657623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
657723183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
657823183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
657987c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
658023183910SDouglas Gilbert  */
65816ecaff7fSRandy Dunlap 
658282069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
658382069379SAkinobu Mita 	&driver_attr_delay.attr,
658482069379SAkinobu Mita 	&driver_attr_opts.attr,
658582069379SAkinobu Mita 	&driver_attr_ptype.attr,
658682069379SAkinobu Mita 	&driver_attr_dsense.attr,
658782069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6588c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
658982069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
659082069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
659182069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
659282069379SAkinobu Mita 	&driver_attr_num_parts.attr,
659382069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6594ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
659582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
659682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
659782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
659882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
659982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
660082069379SAkinobu Mita 	&driver_attr_add_host.attr,
660187c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
660282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
660382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6604c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6605c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
660682069379SAkinobu Mita 	&driver_attr_dix.attr,
660782069379SAkinobu Mita 	&driver_attr_dif.attr,
660882069379SAkinobu Mita 	&driver_attr_guard.attr,
660982069379SAkinobu Mita 	&driver_attr_ato.attr,
661082069379SAkinobu Mita 	&driver_attr_map.attr,
66110c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
661282069379SAkinobu Mita 	&driver_attr_removable.attr,
6613cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6614cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6615c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
661609ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
66179b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6618fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
66199267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
662082069379SAkinobu Mita 	NULL,
662182069379SAkinobu Mita };
662282069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
66231da177e4SLinus Torvalds 
662411ddcecaSAkinobu Mita static struct device *pseudo_primary;
66258dea0d02SFUJITA Tomonori 
66261da177e4SLinus Torvalds static int __init scsi_debug_init(void)
66271da177e4SLinus Torvalds {
662887c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
66295f2578e5SFUJITA Tomonori 	unsigned long sz;
663087c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
663187c715dcSDouglas Gilbert 	int idx = -1;
66321da177e4SLinus Torvalds 
663387c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
663487c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6635cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6636cbf67842SDouglas Gilbert 
6637773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6638c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6639773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6640773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6641c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6642cbf67842SDouglas Gilbert 
6643773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6644597136abSMartin K. Petersen 	case  512:
6645597136abSMartin K. Petersen 	case 1024:
6646597136abSMartin K. Petersen 	case 2048:
6647597136abSMartin K. Petersen 	case 4096:
6648597136abSMartin K. Petersen 		break;
6649597136abSMartin K. Petersen 	default:
6650773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6651597136abSMartin K. Petersen 		return -EINVAL;
6652597136abSMartin K. Petersen 	}
6653597136abSMartin K. Petersen 
6654773642d9SDouglas Gilbert 	switch (sdebug_dif) {
66558475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6656f46eb0e9SDouglas Gilbert 		break;
66578475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
66588475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
66598475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6660f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6661c6a44287SMartin K. Petersen 		break;
6662c6a44287SMartin K. Petersen 
6663c6a44287SMartin K. Petersen 	default:
6664c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6665c6a44287SMartin K. Petersen 		return -EINVAL;
6666c6a44287SMartin K. Petersen 	}
6667c6a44287SMartin K. Petersen 
6668aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6669aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6670aa5334c4SMaurizio Lombardi 		return -EINVAL;
6671aa5334c4SMaurizio Lombardi 	}
6672aa5334c4SMaurizio Lombardi 
6673773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6674c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6675c6a44287SMartin K. Petersen 		return -EINVAL;
6676c6a44287SMartin K. Petersen 	}
6677c6a44287SMartin K. Petersen 
6678773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6679c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6680c6a44287SMartin K. Petersen 		return -EINVAL;
6681c6a44287SMartin K. Petersen 	}
6682c6a44287SMartin K. Petersen 
6683773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6684773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6685ea61fca5SMartin K. Petersen 		return -EINVAL;
6686ea61fca5SMartin K. Petersen 	}
6687ad0c7775SDouglas Gilbert 
6688ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6689ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6690ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6691ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6692ad0c7775SDouglas Gilbert 	}
6693ad0c7775SDouglas Gilbert 
66948d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6695ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6696ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
66978d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
66988d039e22SDouglas Gilbert 		}
6699ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6700ad0c7775SDouglas Gilbert 	}
6701ea61fca5SMartin K. Petersen 
6702773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6703773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6704ea61fca5SMartin K. Petersen 		return -EINVAL;
6705ea61fca5SMartin K. Petersen 	}
6706ea61fca5SMartin K. Petersen 
6707c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6708c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6709c4837394SDouglas Gilbert 		return -EINVAL;
6710c4837394SDouglas Gilbert 	}
6711c87bf24cSJohn Garry 
6712c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6713c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6714c87bf24cSJohn Garry 		return -EINVAL;
6715c87bf24cSJohn Garry 	}
6716c87bf24cSJohn Garry 
6717c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6718c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6719c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6720c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6721c10fa55fSJohn Garry 		return -EINVAL;
6722c10fa55fSJohn Garry 	}
6723c10fa55fSJohn Garry 
6724c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6725c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6726c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6727c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6728c10fa55fSJohn Garry 			sdebug_max_queue);
6729c10fa55fSJohn Garry 	}
6730c10fa55fSJohn Garry 
6731c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6732c4837394SDouglas Gilbert 			       GFP_KERNEL);
6733c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6734c4837394SDouglas Gilbert 		return -ENOMEM;
6735c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6736c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6737c4837394SDouglas Gilbert 
6738f0d1cf93SDouglas Gilbert 	/*
67399267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
67409267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6741f0d1cf93SDouglas Gilbert 	 */
67429267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
67439267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
67449267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
67459267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
67469267e0ebSDouglas Gilbert 		if (k < 0) {
67479267e0ebSDouglas Gilbert 			ret = k;
67489267e0ebSDouglas Gilbert 			goto free_vm;
67499267e0ebSDouglas Gilbert 		}
67509267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
67519267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
67529267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
675364e14eceSDamien Le Moal 		case BLK_ZONED_HA:
67549267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
67559267e0ebSDouglas Gilbert 			break;
67569267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
67579267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
67589267e0ebSDouglas Gilbert 			break;
67599267e0ebSDouglas Gilbert 		default:
67609267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
67619267e0ebSDouglas Gilbert 			return -EINVAL;
67629267e0ebSDouglas Gilbert 		}
67639267e0ebSDouglas Gilbert 	}
67649267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6765f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
67669267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
67679267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
67689267e0ebSDouglas Gilbert 	}
6769f0d1cf93SDouglas Gilbert 
67709267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
67719267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6772773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6773773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6774773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6775773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
677628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
67771da177e4SLinus Torvalds 
67781da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
67791da177e4SLinus Torvalds 	sdebug_heads = 8;
67801da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6781773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
67821da177e4SLinus Torvalds 		sdebug_heads = 64;
6783773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6784fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
67851da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
67861da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
67871da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
67881da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
67891da177e4SLinus Torvalds 		sdebug_heads = 255;
67901da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
67911da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
67921da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
67931da177e4SLinus Torvalds 	}
67945b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6795773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6796773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
67976014759cSMartin K. Petersen 
6798773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6799773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
68006014759cSMartin K. Petersen 
6801773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6802773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
68036014759cSMartin K. Petersen 
6804773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6805773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6806773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6807c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6808c4837394SDouglas Gilbert 			ret = -EINVAL;
680987c715dcSDouglas Gilbert 			goto free_q_arr;
681044d92694SMartin K. Petersen 		}
681144d92694SMartin K. Petersen 	}
681287c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
681387c715dcSDouglas Gilbert 	if (want_store) {
681487c715dcSDouglas Gilbert 		idx = sdebug_add_store();
681587c715dcSDouglas Gilbert 		if (idx < 0) {
681687c715dcSDouglas Gilbert 			ret = idx;
681787c715dcSDouglas Gilbert 			goto free_q_arr;
681887c715dcSDouglas Gilbert 		}
681944d92694SMartin K. Petersen 	}
682044d92694SMartin K. Petersen 
68219b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
68229b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6823c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
68249b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
68256ecaff7fSRandy Dunlap 		goto free_vm;
68266ecaff7fSRandy Dunlap 	}
68276ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
68286ecaff7fSRandy Dunlap 	if (ret < 0) {
6829c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
68306ecaff7fSRandy Dunlap 		goto dev_unreg;
68316ecaff7fSRandy Dunlap 	}
68326ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
68336ecaff7fSRandy Dunlap 	if (ret < 0) {
6834c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
68356ecaff7fSRandy Dunlap 		goto bus_unreg;
68366ecaff7fSRandy Dunlap 	}
68371da177e4SLinus Torvalds 
683887c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6839773642d9SDouglas Gilbert 	sdebug_add_host = 0;
68401da177e4SLinus Torvalds 
684187c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
684287c715dcSDouglas Gilbert 		if (want_store && k == 0) {
684387c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
684487c715dcSDouglas Gilbert 			if (ret < 0) {
684587c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
684687c715dcSDouglas Gilbert 				       k, -ret);
684787c715dcSDouglas Gilbert 				break;
684887c715dcSDouglas Gilbert 			}
684987c715dcSDouglas Gilbert 		} else {
685087c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
685187c715dcSDouglas Gilbert 						 sdebug_per_host_store);
685287c715dcSDouglas Gilbert 			if (ret < 0) {
685387c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
68541da177e4SLinus Torvalds 				break;
68551da177e4SLinus Torvalds 			}
68561da177e4SLinus Torvalds 		}
685787c715dcSDouglas Gilbert 	}
6858773642d9SDouglas Gilbert 	if (sdebug_verbose)
685987c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6860c1287970STomas Winkler 
68611da177e4SLinus Torvalds 	return 0;
68626ecaff7fSRandy Dunlap 
68636ecaff7fSRandy Dunlap bus_unreg:
68646ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
68656ecaff7fSRandy Dunlap dev_unreg:
68669b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
68676ecaff7fSRandy Dunlap free_vm:
686887c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6869c4837394SDouglas Gilbert free_q_arr:
6870c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
68716ecaff7fSRandy Dunlap 	return ret;
68721da177e4SLinus Torvalds }
68731da177e4SLinus Torvalds 
68741da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
68751da177e4SLinus Torvalds {
687687c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
68771da177e4SLinus Torvalds 
68781da177e4SLinus Torvalds 	stop_all_queued();
68791da177e4SLinus Torvalds 	for (; k; k--)
688087c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
688152ab9768SLuis Henriques 	free_all_queued();
68821da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
68831da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
68849b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
68851da177e4SLinus Torvalds 
688687c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
688787c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
68881da177e4SLinus Torvalds }
68891da177e4SLinus Torvalds 
68901da177e4SLinus Torvalds device_initcall(scsi_debug_init);
68911da177e4SLinus Torvalds module_exit(scsi_debug_exit);
68921da177e4SLinus Torvalds 
68931da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
68941da177e4SLinus Torvalds {
68951da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
68961da177e4SLinus Torvalds 
68971da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
68981da177e4SLinus Torvalds 	kfree(sdbg_host);
68991da177e4SLinus Torvalds }
69001da177e4SLinus Torvalds 
690187c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
690287c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
69031da177e4SLinus Torvalds {
690487c715dcSDouglas Gilbert 	if (idx < 0)
690587c715dcSDouglas Gilbert 		return;
690687c715dcSDouglas Gilbert 	if (!sip) {
690787c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
690887c715dcSDouglas Gilbert 			return;
690987c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
691087c715dcSDouglas Gilbert 		if (!sip)
691187c715dcSDouglas Gilbert 			return;
691287c715dcSDouglas Gilbert 	}
691387c715dcSDouglas Gilbert 	vfree(sip->map_storep);
691487c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
691587c715dcSDouglas Gilbert 	vfree(sip->storep);
691687c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
691787c715dcSDouglas Gilbert 	kfree(sip);
691887c715dcSDouglas Gilbert }
691987c715dcSDouglas Gilbert 
692087c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
692187c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
692287c715dcSDouglas Gilbert {
692387c715dcSDouglas Gilbert 	unsigned long idx;
692487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
692587c715dcSDouglas Gilbert 
692687c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
692787c715dcSDouglas Gilbert 		if (apart_from_first)
692887c715dcSDouglas Gilbert 			apart_from_first = false;
692987c715dcSDouglas Gilbert 		else
693087c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
693187c715dcSDouglas Gilbert 	}
693287c715dcSDouglas Gilbert 	if (apart_from_first)
693387c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
693487c715dcSDouglas Gilbert }
693587c715dcSDouglas Gilbert 
693687c715dcSDouglas Gilbert /*
693787c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
693887c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
693987c715dcSDouglas Gilbert  */
694087c715dcSDouglas Gilbert static int sdebug_add_store(void)
694187c715dcSDouglas Gilbert {
694287c715dcSDouglas Gilbert 	int res;
694387c715dcSDouglas Gilbert 	u32 n_idx;
694487c715dcSDouglas Gilbert 	unsigned long iflags;
694587c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
694687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
694787c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
694887c715dcSDouglas Gilbert 
694987c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
695087c715dcSDouglas Gilbert 	if (!sip)
695187c715dcSDouglas Gilbert 		return -ENOMEM;
695287c715dcSDouglas Gilbert 
695387c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
695487c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
695587c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
695687c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
695787c715dcSDouglas Gilbert 		kfree(sip);
695887c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
695987c715dcSDouglas Gilbert 		return res;
696087c715dcSDouglas Gilbert 	}
696187c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
696287c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
696387c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
696487c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
696587c715dcSDouglas Gilbert 
696687c715dcSDouglas Gilbert 	res = -ENOMEM;
696787c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
696887c715dcSDouglas Gilbert 	if (!sip->storep) {
696987c715dcSDouglas Gilbert 		pr_err("user data oom\n");
697087c715dcSDouglas Gilbert 		goto err;
697187c715dcSDouglas Gilbert 	}
697287c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
697387c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
697487c715dcSDouglas Gilbert 
697587c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
697687c715dcSDouglas Gilbert 	if (sdebug_dix) {
697787c715dcSDouglas Gilbert 		int dif_size;
697887c715dcSDouglas Gilbert 
697987c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
698087c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
698187c715dcSDouglas Gilbert 
698287c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
698387c715dcSDouglas Gilbert 			sip->dif_storep);
698487c715dcSDouglas Gilbert 
698587c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
698687c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
698787c715dcSDouglas Gilbert 			goto err;
698887c715dcSDouglas Gilbert 		}
698987c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
699087c715dcSDouglas Gilbert 	}
699187c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
699287c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
699387c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
699487c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
699587c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
699687c715dcSDouglas Gilbert 
699787c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
699887c715dcSDouglas Gilbert 
699987c715dcSDouglas Gilbert 		if (!sip->map_storep) {
700087c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
700187c715dcSDouglas Gilbert 			goto err;
700287c715dcSDouglas Gilbert 		}
700387c715dcSDouglas Gilbert 
700487c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
700587c715dcSDouglas Gilbert 
700687c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
700787c715dcSDouglas Gilbert 		if (sdebug_num_parts)
700887c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
700987c715dcSDouglas Gilbert 	}
701087c715dcSDouglas Gilbert 
701187c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
701287c715dcSDouglas Gilbert 	return (int)n_idx;
701387c715dcSDouglas Gilbert err:
701487c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
701587c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
701687c715dcSDouglas Gilbert 	return res;
701787c715dcSDouglas Gilbert }
701887c715dcSDouglas Gilbert 
701987c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
702087c715dcSDouglas Gilbert {
702187c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
702287c715dcSDouglas Gilbert 	int error = -ENOMEM;
70231da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
70248b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
70251da177e4SLinus Torvalds 
702624669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
702787c715dcSDouglas Gilbert 	if (!sdbg_host)
70281da177e4SLinus Torvalds 		return -ENOMEM;
702987c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
703087c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
703187c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
703287c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
70331da177e4SLinus Torvalds 
70341da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
70351da177e4SLinus Torvalds 
7036773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
70371da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
70385cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
703987c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
70401da177e4SLinus Torvalds 			goto clean;
70411da177e4SLinus Torvalds 	}
70421da177e4SLinus Torvalds 
70431da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
70441da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
70451da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
70461da177e4SLinus Torvalds 
70471da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
70489b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
70491da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
705087c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
70511da177e4SLinus Torvalds 
70521da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
70531da177e4SLinus Torvalds 	if (error)
70541da177e4SLinus Torvalds 		goto clean;
70551da177e4SLinus Torvalds 
705687c715dcSDouglas Gilbert 	++sdebug_num_hosts;
705787c715dcSDouglas Gilbert 	return 0;
70581da177e4SLinus Torvalds 
70591da177e4SLinus Torvalds clean:
70608b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
70618b40228fSFUJITA Tomonori 				 dev_list) {
70621da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7063f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
70641da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
70651da177e4SLinus Torvalds 	}
70661da177e4SLinus Torvalds 	kfree(sdbg_host);
706787c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
70681da177e4SLinus Torvalds 	return error;
70691da177e4SLinus Torvalds }
70701da177e4SLinus Torvalds 
707187c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
70721da177e4SLinus Torvalds {
707387c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
707487c715dcSDouglas Gilbert 
707587c715dcSDouglas Gilbert 	if (mk_new_store) {
707687c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
707787c715dcSDouglas Gilbert 		if (ph_idx < 0)
707887c715dcSDouglas Gilbert 			return ph_idx;
707987c715dcSDouglas Gilbert 	}
708087c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
708187c715dcSDouglas Gilbert }
708287c715dcSDouglas Gilbert 
708387c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
708487c715dcSDouglas Gilbert {
708587c715dcSDouglas Gilbert 	int idx = -1;
70861da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
708787c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
70881da177e4SLinus Torvalds 
70891da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
70901da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
70911da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
70921da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
709387c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
70941da177e4SLinus Torvalds 	}
709587c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
709687c715dcSDouglas Gilbert 		bool unique = true;
709787c715dcSDouglas Gilbert 
709887c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
709987c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
710087c715dcSDouglas Gilbert 				continue;
710187c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
710287c715dcSDouglas Gilbert 				unique = false;
710387c715dcSDouglas Gilbert 				break;
710487c715dcSDouglas Gilbert 			}
710587c715dcSDouglas Gilbert 		}
710687c715dcSDouglas Gilbert 		if (unique) {
710787c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
710887c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
710987c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
711087c715dcSDouglas Gilbert 		}
711187c715dcSDouglas Gilbert 	}
711287c715dcSDouglas Gilbert 	if (sdbg_host)
711387c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
71141da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
71151da177e4SLinus Torvalds 
71161da177e4SLinus Torvalds 	if (!sdbg_host)
71171da177e4SLinus Torvalds 		return;
71181da177e4SLinus Torvalds 
71191da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
712087c715dcSDouglas Gilbert 	--sdebug_num_hosts;
71211da177e4SLinus Torvalds }
71221da177e4SLinus Torvalds 
7123fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7124cbf67842SDouglas Gilbert {
7125cbf67842SDouglas Gilbert 	int num_in_q = 0;
7126cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7127cbf67842SDouglas Gilbert 
7128c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
7129cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7130cbf67842SDouglas Gilbert 	if (NULL == devip) {
7131c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
7132cbf67842SDouglas Gilbert 		return	-ENODEV;
7133cbf67842SDouglas Gilbert 	}
7134cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7135c40ecc12SChristoph Hellwig 
7136cbf67842SDouglas Gilbert 	if (qdepth < 1)
7137cbf67842SDouglas Gilbert 		qdepth = 1;
7138c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
7139c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
7140c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
7141db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
7142cbf67842SDouglas Gilbert 
7143773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7144c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7145c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7146cbf67842SDouglas Gilbert 	}
7147c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
7148cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7149cbf67842SDouglas Gilbert }
7150cbf67842SDouglas Gilbert 
7151c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7152817fd66bSDouglas Gilbert {
7153c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7154773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7155773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7156773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7157c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7158773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7159817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7160c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7161817fd66bSDouglas Gilbert 	}
7162c4837394SDouglas Gilbert 	return false;
7163817fd66bSDouglas Gilbert }
7164817fd66bSDouglas Gilbert 
7165fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7166fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7167fc13638aSDouglas Gilbert {
7168fc13638aSDouglas Gilbert 	int stopped_state;
7169fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7170fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7171fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7172fc13638aSDouglas Gilbert 
7173fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7174fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7175fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7176fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7177fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7178fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7179fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7180fc13638aSDouglas Gilbert 				return 0;
7181fc13638aSDouglas Gilbert 			}
7182fc13638aSDouglas Gilbert 		}
7183fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7184fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7185fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7186fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7187fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7188fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7189fc13638aSDouglas Gilbert 
7190fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7191fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7192fc13638aSDouglas Gilbert 			else
7193fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7194fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7195fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7196fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7197fc13638aSDouglas Gilbert 						   diff_ns);
7198fc13638aSDouglas Gilbert 			return check_condition_result;
7199fc13638aSDouglas Gilbert 		}
7200fc13638aSDouglas Gilbert 	}
7201fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7202fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7203fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7204fc13638aSDouglas Gilbert 			    my_name);
7205fc13638aSDouglas Gilbert 	return check_condition_result;
7206fc13638aSDouglas Gilbert }
7207fc13638aSDouglas Gilbert 
7208fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7209fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7210c2248fc9SDouglas Gilbert {
7211c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7212c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7213c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7214c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7215c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7216c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7217c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7218f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7219c2248fc9SDouglas Gilbert 	int k, na;
7220c2248fc9SDouglas Gilbert 	int errsts = 0;
7221ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7222c2248fc9SDouglas Gilbert 	u32 flags;
7223c2248fc9SDouglas Gilbert 	u16 sa;
7224c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7225c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
72263a90a63dSDouglas Gilbert 	bool inject_now;
7227c2248fc9SDouglas Gilbert 
7228c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
72293a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7230c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
72313a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
72323a90a63dSDouglas Gilbert 	} else {
72333a90a63dSDouglas Gilbert 		inject_now = false;
72343a90a63dSDouglas Gilbert 	}
7235f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7236f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7237c2248fc9SDouglas Gilbert 		char b[120];
7238c2248fc9SDouglas Gilbert 		int n, len, sb;
7239c2248fc9SDouglas Gilbert 
7240c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7241c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7242c2248fc9SDouglas Gilbert 		if (len > 32)
7243c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7244c2248fc9SDouglas Gilbert 		else {
7245c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7246c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7247c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7248c2248fc9SDouglas Gilbert 		}
7249458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7250458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
7251c2248fc9SDouglas Gilbert 	}
72523a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
72537ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
725434d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7255ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7256f46eb0e9SDouglas Gilbert 		goto err_out;
7257c2248fc9SDouglas Gilbert 
7258c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7259c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7260c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7261f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7262f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7263c2248fc9SDouglas Gilbert 		if (NULL == devip)
7264f46eb0e9SDouglas Gilbert 			goto err_out;
7265c2248fc9SDouglas Gilbert 	}
72663a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
72673a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
72683a90a63dSDouglas Gilbert 
7269c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7270c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7271c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7272c2248fc9SDouglas Gilbert 		r_oip = oip;
7273c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7274c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7275c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7276c2248fc9SDouglas Gilbert 			else
7277c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7278c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7279c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7280c2248fc9SDouglas Gilbert 					break;
7281c2248fc9SDouglas Gilbert 			}
7282c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7283c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7284c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7285c2248fc9SDouglas Gilbert 					break;
7286c2248fc9SDouglas Gilbert 			}
7287c2248fc9SDouglas Gilbert 		}
7288c2248fc9SDouglas Gilbert 		if (k > na) {
7289c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7290c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7291c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7292c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7293c2248fc9SDouglas Gilbert 			else
7294c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7295c2248fc9SDouglas Gilbert 			goto check_cond;
7296c2248fc9SDouglas Gilbert 		}
7297c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7298c2248fc9SDouglas Gilbert 	flags = oip->flags;
7299f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7300c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7301c2248fc9SDouglas Gilbert 		goto check_cond;
7302c2248fc9SDouglas Gilbert 	}
7303f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7304773642d9SDouglas Gilbert 		if (sdebug_verbose)
7305773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7306773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7307c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7308c2248fc9SDouglas Gilbert 		goto check_cond;
7309c2248fc9SDouglas Gilbert 	}
7310f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7311c2248fc9SDouglas Gilbert 		u8 rem;
7312c2248fc9SDouglas Gilbert 		int j;
7313c2248fc9SDouglas Gilbert 
7314c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7315c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7316c2248fc9SDouglas Gilbert 			if (rem) {
7317c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7318c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7319c2248fc9SDouglas Gilbert 						break;
7320c2248fc9SDouglas Gilbert 				}
7321c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7322c2248fc9SDouglas Gilbert 				goto check_cond;
7323c2248fc9SDouglas Gilbert 			}
7324c2248fc9SDouglas Gilbert 		}
7325c2248fc9SDouglas Gilbert 	}
7326f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7327b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7328b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7329f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7330c2248fc9SDouglas Gilbert 		if (errsts)
7331c2248fc9SDouglas Gilbert 			goto check_cond;
7332c2248fc9SDouglas Gilbert 	}
7333fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7334fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7335fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7336fc13638aSDouglas Gilbert 		if (errsts)
7337c2248fc9SDouglas Gilbert 			goto fini;
7338c2248fc9SDouglas Gilbert 	}
7339773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7340c2248fc9SDouglas Gilbert 		goto fini;
7341f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7342c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7343c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7344c2248fc9SDouglas Gilbert 	}
7345f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7346f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7347f66b8517SMartin Wilck 	else
7348f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7349c2248fc9SDouglas Gilbert 
7350c2248fc9SDouglas Gilbert fini:
735167da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7352f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
735375aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
735475aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
735580c49563SDouglas Gilbert 		/*
735675aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
735775aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
735875aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
735975aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
736080c49563SDouglas Gilbert 		 */
736180c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
73624f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
736380c49563SDouglas Gilbert 
73644f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7365f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
736680c49563SDouglas Gilbert 	} else
7367f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
736810bde980SDouglas Gilbert 				     sdebug_ndelay);
7369c2248fc9SDouglas Gilbert check_cond:
7370f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7371f46eb0e9SDouglas Gilbert err_out:
7372f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7373c2248fc9SDouglas Gilbert }
7374c2248fc9SDouglas Gilbert 
73759e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7376c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7377c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
73789e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
73799e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
73809e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
73819e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
73829e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
73839e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
73849e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7385185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7386cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
73879e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
73889e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7389cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7390cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
73919e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7392c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
73939e603ca0SFUJITA Tomonori 	.this_id =		7,
739465e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7395cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
73966bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
739750c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
73989e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7399c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
74009e603ca0SFUJITA Tomonori };
74019e603ca0SFUJITA Tomonori 
74021da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
74031da177e4SLinus Torvalds {
74041da177e4SLinus Torvalds 	int error = 0;
74051da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
74061da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7407f46eb0e9SDouglas Gilbert 	int hprot;
74081da177e4SLinus Torvalds 
74091da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
74101da177e4SLinus Torvalds 
7411c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
7412c10fa55fSJohn Garry 		sdebug_driver_template.can_queue = sdebug_host_max_queue;
7413c10fa55fSJohn Garry 	else
7414773642d9SDouglas Gilbert 		sdebug_driver_template.can_queue = sdebug_max_queue;
74152a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
74164af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
74174af14d11SChristoph Hellwig 
74181da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
74191da177e4SLinus Torvalds 	if (NULL == hpnt) {
7420c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
74211da177e4SLinus Torvalds 		error = -ENODEV;
74221da177e4SLinus Torvalds 		return error;
74231da177e4SLinus Torvalds 	}
7424c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
74259b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7426c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7427c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7428c4837394SDouglas Gilbert 	}
7429c10fa55fSJohn Garry 	/*
7430c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7431c10fa55fSJohn Garry 	 * following should give the same answer for each host. If the host
7432c10fa55fSJohn Garry 	 * has a limit of hostwide max commands, then do not set.
7433c10fa55fSJohn Garry 	 */
7434c10fa55fSJohn Garry 	if (!sdebug_host_max_queue)
7435c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
74361da177e4SLinus Torvalds 
74371da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
74381da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7439773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7440773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
74411da177e4SLinus Torvalds 	else
7442773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7443773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7444f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
74451da177e4SLinus Torvalds 
7446f46eb0e9SDouglas Gilbert 	hprot = 0;
7447c6a44287SMartin K. Petersen 
7448773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7449c6a44287SMartin K. Petersen 
74508475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7451f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7452773642d9SDouglas Gilbert 		if (sdebug_dix)
7453f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7454c6a44287SMartin K. Petersen 		break;
7455c6a44287SMartin K. Petersen 
74568475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7457f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7458773642d9SDouglas Gilbert 		if (sdebug_dix)
7459f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7460c6a44287SMartin K. Petersen 		break;
7461c6a44287SMartin K. Petersen 
74628475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7463f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7464773642d9SDouglas Gilbert 		if (sdebug_dix)
7465f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7466c6a44287SMartin K. Petersen 		break;
7467c6a44287SMartin K. Petersen 
7468c6a44287SMartin K. Petersen 	default:
7469773642d9SDouglas Gilbert 		if (sdebug_dix)
7470f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7471c6a44287SMartin K. Petersen 		break;
7472c6a44287SMartin K. Petersen 	}
7473c6a44287SMartin K. Petersen 
7474f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7475c6a44287SMartin K. Petersen 
7476f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7477c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7478f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7479f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7480f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7481f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7482f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7483f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7484f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7485c6a44287SMartin K. Petersen 
7486773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7487c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7488c6a44287SMartin K. Petersen 	else
7489c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7490c6a44287SMartin K. Petersen 
7491773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7492773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7493c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7494c4837394SDouglas Gilbert 		sdebug_statistics = true;
74951da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
74961da177e4SLinus Torvalds 	if (error) {
7497c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
74981da177e4SLinus Torvalds 		error = -ENODEV;
74991da177e4SLinus Torvalds 		scsi_host_put(hpnt);
750087c715dcSDouglas Gilbert 	} else {
75011da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
750287c715dcSDouglas Gilbert 	}
75031da177e4SLinus Torvalds 
75041da177e4SLinus Torvalds 	return error;
75051da177e4SLinus Torvalds }
75061da177e4SLinus Torvalds 
75071da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
75081da177e4SLinus Torvalds {
75091da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
75108b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
75111da177e4SLinus Torvalds 
75121da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
75131da177e4SLinus Torvalds 
75141da177e4SLinus Torvalds 	if (!sdbg_host) {
7515c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
75161da177e4SLinus Torvalds 		return -ENODEV;
75171da177e4SLinus Torvalds 	}
75181da177e4SLinus Torvalds 
75191da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
75201da177e4SLinus Torvalds 
75218b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
75228b40228fSFUJITA Tomonori 				 dev_list) {
75231da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7524f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
75251da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
75261da177e4SLinus Torvalds 	}
75271da177e4SLinus Torvalds 
75281da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
75291da177e4SLinus Torvalds 	return 0;
75301da177e4SLinus Torvalds }
75311da177e4SLinus Torvalds 
75328dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
75338dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
75341da177e4SLinus Torvalds {
75358dea0d02SFUJITA Tomonori 	return 1;
75368dea0d02SFUJITA Tomonori }
75371da177e4SLinus Torvalds 
75388dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
75398dea0d02SFUJITA Tomonori 	.name = "pseudo",
75408dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
75418dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
75428dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
754382069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
75448dea0d02SFUJITA Tomonori };
7545