xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 771f712b)
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,
3254a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
32610bde980SDouglas Gilbert 
327fd32119bSDouglas Gilbert struct sdebug_defer {
328fd32119bSDouglas Gilbert 	struct hrtimer hrt;
329fd32119bSDouglas Gilbert 	struct execute_work ew;
3304a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
331c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
332c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
333c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
334c4837394SDouglas Gilbert 	int issuing_cpu;
33510bde980SDouglas Gilbert 	bool init_hrt;
33610bde980SDouglas Gilbert 	bool init_wq;
3374a0c6f43SDouglas Gilbert 	bool init_poll;
3387382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
33910bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
340fd32119bSDouglas Gilbert };
341fd32119bSDouglas Gilbert 
342fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
343c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
344c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
345c4837394SDouglas Gilbert 	 */
346fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
347fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
348fd32119bSDouglas Gilbert };
349fd32119bSDouglas Gilbert 
350c4837394SDouglas Gilbert struct sdebug_queue {
351c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
352c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
353c4837394SDouglas Gilbert 	spinlock_t qc_lock;
354c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
355fd32119bSDouglas Gilbert };
356fd32119bSDouglas Gilbert 
357c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
358c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
359c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
360c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3613a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3624a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
363c4837394SDouglas Gilbert 
364fd32119bSDouglas Gilbert struct opcode_info_t {
365b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
366b01f6f83SDouglas Gilbert 				/* for terminating element */
367fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
368fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
369fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
370fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
371fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3729a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3739a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
374fd32119bSDouglas Gilbert };
375fd32119bSDouglas Gilbert 
376fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
377c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
378c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
379c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
380c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
381c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
382c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
383c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
384c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
385c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
386c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
387c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
388c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
389c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39046f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39146f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
392c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
393c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
394c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
395481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
396c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
397c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
398c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
399c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
400c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
401c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
402c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
403c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
404c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
405c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
406c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
407ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
408f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
409f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
410f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
411c2248fc9SDouglas Gilbert };
412c2248fc9SDouglas Gilbert 
413c4837394SDouglas Gilbert 
414c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
415c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
416c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
417c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
418c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
419c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
420c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
421c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
422c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
423c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
424c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
425c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
426ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
427c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
428c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
429c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
430c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
431c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
432c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
433c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
434fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
435c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
436c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
437c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
438c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
439c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
440c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
441c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
442f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
443f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44446f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
445c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
446c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
447c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
44846f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
44946f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
450c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
451c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
452c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
455c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
456c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
457c2248fc9SDouglas Gilbert };
458c2248fc9SDouglas Gilbert 
45980c49563SDouglas Gilbert /*
46080c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46180c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46280c49563SDouglas Gilbert  * command completion, they can mask their return value with
46380c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46480c49563SDouglas Gilbert  */
46580c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46680c49563SDouglas Gilbert 
467c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
468c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
469c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
470c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
476481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
484c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
48738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
488acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
48980c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
490ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
491f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
492f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
493f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
494f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
495f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
496c2248fc9SDouglas Gilbert 
49787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
49887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
49987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50087c715dcSDouglas Gilbert static int sdebug_add_store(void);
50187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50287c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50387c715dcSDouglas Gilbert 
50446f64e70SDouglas Gilbert /*
50546f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50646f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
50746f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
50846f64e70SDouglas Gilbert  */
50946f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
510c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
511c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512c2248fc9SDouglas Gilbert };
513c2248fc9SDouglas Gilbert 
51446f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
515c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
516c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517c2248fc9SDouglas Gilbert };
518c2248fc9SDouglas Gilbert 
51946f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52046f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
521b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
522c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52346f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
524c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52546f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
526b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
527c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
528c2248fc9SDouglas Gilbert };
529c2248fc9SDouglas Gilbert 
53046f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53146f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53246f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53346f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53446f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53546f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53646f64e70SDouglas Gilbert 		   0, 0, 0} },
53746f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
53846f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53946f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
540c2248fc9SDouglas Gilbert };
541c2248fc9SDouglas Gilbert 
542c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
543c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
544c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
545c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
546c3e2fe92SDouglas Gilbert };
547c3e2fe92SDouglas Gilbert 
54846f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
549c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
550c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55146f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
552c2248fc9SDouglas Gilbert };
553c2248fc9SDouglas Gilbert 
55446f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55546f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
556b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
557c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
558481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
559481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
560481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
561c2248fc9SDouglas Gilbert };
562c2248fc9SDouglas Gilbert 
56346f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56438d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
565c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56646f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
56738d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
568c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
56946f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
570c2248fc9SDouglas Gilbert };
571c2248fc9SDouglas Gilbert 
57246f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57346f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
574c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57546f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
576c2248fc9SDouglas Gilbert };
577c2248fc9SDouglas Gilbert 
57846f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
579c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
580c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
581c2248fc9SDouglas Gilbert };
582c2248fc9SDouglas Gilbert 
58346f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
584c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
585c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
586c2248fc9SDouglas Gilbert };
587c2248fc9SDouglas Gilbert 
58880c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5894f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59080c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59180c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59280c49563SDouglas Gilbert };
59380c49563SDouglas Gilbert 
594ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
595b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
596ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
597ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
598ed9f3e25SDouglas Gilbert };
599ed9f3e25SDouglas Gilbert 
600f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
601b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
602f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
604b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
605f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
607b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
608f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
609f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
610f0d1cf93SDouglas Gilbert };
611f0d1cf93SDouglas Gilbert 
612f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
613b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
614f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
615f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
616f0d1cf93SDouglas Gilbert };
617f0d1cf93SDouglas Gilbert 
618c2248fc9SDouglas Gilbert 
619c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
620c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
621c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
622ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
623c2248fc9SDouglas Gilbert /* 0 */
62446f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
625c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62646f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
627c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
628c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
629c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63046f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
631c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
632c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
633c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
634c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63546f64e70SDouglas Gilbert /* 5 */
63646f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
63746f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
63846f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
63946f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64046f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64146f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64246f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
643c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
644c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64546f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
646c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
647c2248fc9SDouglas Gilbert 	     0, 0} },
64846f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
64946f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65046f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
651c2248fc9SDouglas Gilbert /* 10 */
65246f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65346f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65446f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65580c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6564f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
657c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65846f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
65946f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66046f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66146f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
662481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
663481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
664481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66546f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66646f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
66746f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
66846f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
66946f64e70SDouglas Gilbert /* 15 */
670c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
671c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
672c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
673c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
674c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
675c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67646f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
67746f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
67846f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
67946f64e70SDouglas Gilbert 	     0xff, 0xff} },
68046f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68146f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
682c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
683c2248fc9SDouglas Gilbert 	     0} },
68446f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68546f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
686c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
687c2248fc9SDouglas Gilbert 	     0} },
688c2248fc9SDouglas Gilbert /* 20 */
689f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
690f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
691c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
692c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
693c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
694c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
695c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
696c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
69746f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
698b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
69946f64e70SDouglas Gilbert /* 25 */
700acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
701acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
702acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70346f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70446f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70546f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70646f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7074f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
70880c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
709b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71080c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71146f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
712c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
713b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
714b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
715ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
716ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
717ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
718c2248fc9SDouglas Gilbert 
719ed9f3e25SDouglas Gilbert /* 30 */
720b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
721f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
722f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
723f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
724b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
725f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
726f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
727f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
728f0d1cf93SDouglas Gilbert /* sentinel */
729c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
730c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
731c2248fc9SDouglas Gilbert };
732c2248fc9SDouglas Gilbert 
73387c715dcSDouglas Gilbert static int sdebug_num_hosts;
73487c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
735773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7369b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
737c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7389267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
739773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
740773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
741773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
742773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
743773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
744773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
745c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
746773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
747773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
748c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
749d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
750d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
751cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
752c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
753773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
754773642d9SDouglas Gilbert static int sdebug_no_uld;
755773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
756773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
757773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
758773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
759773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76086e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
761b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
762773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
763773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
764fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
765773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
766773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
767773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
768773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
769773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
770773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
771773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
772773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
773773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
775773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
77609ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7770c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
77887c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
779773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
780773642d9SDouglas Gilbert static bool sdebug_clustering;
781773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
782773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
783817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
784773642d9SDouglas Gilbert static bool sdebug_verbose;
785f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7864f2c8bf6SDouglas Gilbert static bool write_since_sync;
787c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7889447b6ceSMartin K. Petersen static bool sdebug_wp;
7899267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7909267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7919267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7921da177e4SLinus Torvalds 
793ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
794ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
795ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
796ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
797ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
798ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
799ad0c7775SDouglas Gilbert 
800c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8011da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8041da177e4SLinus Torvalds    may still need them */
8051da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8061da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8071da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8111da177e4SLinus Torvalds 
81287c715dcSDouglas Gilbert static struct xarray per_store_arr;
81387c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
81487c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
81587c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
81687c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8171da177e4SLinus Torvalds 
81844d92694SMartin K. Petersen static unsigned long map_size;
819cbf67842SDouglas Gilbert static int num_aborts;
820cbf67842SDouglas Gilbert static int num_dev_resets;
821cbf67842SDouglas Gilbert static int num_target_resets;
822cbf67842SDouglas Gilbert static int num_bus_resets;
823cbf67842SDouglas Gilbert static int num_host_resets;
824c6a44287SMartin K. Petersen static int dix_writes;
825c6a44287SMartin K. Petersen static int dix_reads;
826c6a44287SMartin K. Petersen static int dif_errors;
8271da177e4SLinus Torvalds 
828f0d1cf93SDouglas Gilbert /* ZBC global data */
82964e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
83098e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
831380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
832aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
833f0d1cf93SDouglas Gilbert 
834c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
835c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
836c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
837fd32119bSDouglas Gilbert 
8381da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
83987c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84087c715dcSDouglas Gilbert 
84187c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8421da177e4SLinus Torvalds 
843cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
844cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8491da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8501da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8511da177e4SLinus Torvalds };
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds static const int check_condition_result =
8541da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8551da177e4SLinus Torvalds 
856c6a44287SMartin K. Petersen static const int illegal_condition_result =
857c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
858c6a44287SMartin K. Petersen 
859cbf67842SDouglas Gilbert static const int device_qfull_result =
8607a64c814SHannes Reinecke 	(DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
861cbf67842SDouglas Gilbert 
862ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
863ed9f3e25SDouglas Gilbert 
864fd32119bSDouglas Gilbert 
865760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
866760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
867760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
868760f3b03SDouglas Gilbert  */
869760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
870fd32119bSDouglas Gilbert {
871fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
872fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
873fd32119bSDouglas Gilbert }
874c65b1445SDouglas Gilbert 
87587c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
87687c715dcSDouglas Gilbert 			    unsigned long long lba)
87714faa944SAkinobu Mita {
87887c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
87914faa944SAkinobu Mita 
88087c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88187c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88287c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
88387c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
88487c715dcSDouglas Gilbert 	}
88587c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
88614faa944SAkinobu Mita }
88714faa944SAkinobu Mita 
88887c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
88987c715dcSDouglas Gilbert 				      sector_t sector)
89014faa944SAkinobu Mita {
89149413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89214faa944SAkinobu Mita 
89387c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
89414faa944SAkinobu Mita }
89514faa944SAkinobu Mita 
8968dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8978dea0d02SFUJITA Tomonori {
8988dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
8998dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9008dea0d02SFUJITA Tomonori 
9018dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9028dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9038dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9048dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
905773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
906773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9078dea0d02SFUJITA Tomonori 		else
908773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
909773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
910f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9118dea0d02SFUJITA Tomonori 	}
9128dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9138dea0d02SFUJITA Tomonori }
9148dea0d02SFUJITA Tomonori 
91522017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
91622017ed2SDouglas Gilbert 
91722017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
918fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
919fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92022017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92122017ed2SDouglas Gilbert {
92222017ed2SDouglas Gilbert 	unsigned char *sbuff;
92322017ed2SDouglas Gilbert 	u8 sks[4];
92422017ed2SDouglas Gilbert 	int sl, asc;
92522017ed2SDouglas Gilbert 
92622017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
92722017ed2SDouglas Gilbert 	if (!sbuff) {
92822017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
92922017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93022017ed2SDouglas Gilbert 		return;
93122017ed2SDouglas Gilbert 	}
93222017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
93322017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
934773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
93522017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
93622017ed2SDouglas Gilbert 	sks[0] = 0x80;
93722017ed2SDouglas Gilbert 	if (c_d)
93822017ed2SDouglas Gilbert 		sks[0] |= 0x40;
93922017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94022017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94122017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94222017ed2SDouglas Gilbert 	}
94322017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
944773642d9SDouglas Gilbert 	if (sdebug_dsense) {
94522017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
94622017ed2SDouglas Gilbert 		sbuff[7] = sl;
94722017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
94822017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
94922017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95022017ed2SDouglas Gilbert 	} else
95122017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
952773642d9SDouglas Gilbert 	if (sdebug_verbose)
95322017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
95422017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
95522017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
95622017ed2SDouglas Gilbert }
95722017ed2SDouglas Gilbert 
958cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9598dea0d02SFUJITA Tomonori {
9608dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
9618dea0d02SFUJITA Tomonori 
962cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
963cbf67842SDouglas Gilbert 	if (!sbuff) {
964cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
965cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
966cbf67842SDouglas Gilbert 		return;
967cbf67842SDouglas Gilbert 	}
968cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9698dea0d02SFUJITA Tomonori 
970773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9718dea0d02SFUJITA Tomonori 
972773642d9SDouglas Gilbert 	if (sdebug_verbose)
973cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
974cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
975cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9768dea0d02SFUJITA Tomonori }
9771da177e4SLinus Torvalds 
978fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
97922017ed2SDouglas Gilbert {
98022017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98122017ed2SDouglas Gilbert }
98222017ed2SDouglas Gilbert 
9836f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9846f4e626fSNathan Chancellor 			    void __user *arg)
9851da177e4SLinus Torvalds {
986773642d9SDouglas Gilbert 	if (sdebug_verbose) {
987cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
988cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
989cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
990cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
991cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
992cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
993cbf67842SDouglas Gilbert 				    __func__);
994cbf67842SDouglas Gilbert 		else
995cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
996cbf67842SDouglas Gilbert 				    __func__, cmd);
9971da177e4SLinus Torvalds 	}
9981da177e4SLinus Torvalds 	return -EINVAL;
9991da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10001da177e4SLinus Torvalds }
10011da177e4SLinus Torvalds 
10029b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10039b760fd8SDouglas Gilbert {
10049b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10059b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10069b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10079b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10089b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10099b760fd8SDouglas Gilbert 		break;
10109b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10119b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10129b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10149b760fd8SDouglas Gilbert 		break;
10159b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10179b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10199b760fd8SDouglas Gilbert 		break;
10209b760fd8SDouglas Gilbert 	case 16:
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10229b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10239b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10249b760fd8SDouglas Gilbert 		break;
10259b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10279b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10289b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10299b760fd8SDouglas Gilbert 		break;
10309b760fd8SDouglas Gilbert 	default:
10319b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10329b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10339b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10349b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10359b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10369b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10379b760fd8SDouglas Gilbert 		break;
10389b760fd8SDouglas Gilbert 	}
10399b760fd8SDouglas Gilbert }
10409b760fd8SDouglas Gilbert 
10419b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10429b760fd8SDouglas Gilbert {
10439b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10449b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10459b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10469b760fd8SDouglas Gilbert 
10479b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10489b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10499b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10509b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10519b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10529b760fd8SDouglas Gilbert 		}
10539b760fd8SDouglas Gilbert 	}
10549b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10559b760fd8SDouglas Gilbert }
10569b760fd8SDouglas Gilbert 
105719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
105819c8ead7SEwan D. Milne {
105919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106119c8ead7SEwan D. Milne 
106219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
106319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
106519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
106619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
106719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
106819c8ead7SEwan D. Milne 		}
106919c8ead7SEwan D. Milne 	}
107019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107119c8ead7SEwan D. Milne }
107219c8ead7SEwan D. Milne 
1073f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10741da177e4SLinus Torvalds {
1075cbf67842SDouglas Gilbert 	int k;
1076cbf67842SDouglas Gilbert 
1077cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1078cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1079cbf67842SDouglas Gilbert 		const char *cp = NULL;
1080cbf67842SDouglas Gilbert 
1081cbf67842SDouglas Gilbert 		switch (k) {
1082cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1083f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1084f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1085773642d9SDouglas Gilbert 			if (sdebug_verbose)
1086cbf67842SDouglas Gilbert 				cp = "power on reset";
1087cbf67842SDouglas Gilbert 			break;
1088cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1089f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1090f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1091773642d9SDouglas Gilbert 			if (sdebug_verbose)
1092cbf67842SDouglas Gilbert 				cp = "bus reset";
1093cbf67842SDouglas Gilbert 			break;
1094cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1095f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1096f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1097773642d9SDouglas Gilbert 			if (sdebug_verbose)
1098cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1099cbf67842SDouglas Gilbert 			break;
11000d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1101f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1102f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1103773642d9SDouglas Gilbert 			if (sdebug_verbose)
11040d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1105f49accf1SEwan D. Milne 			break;
1106acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1107f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1108b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1109b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1110773642d9SDouglas Gilbert 			if (sdebug_verbose)
1111acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1112acafd0b9SEwan D. Milne 			break;
1113acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1114f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1115acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1116acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1117773642d9SDouglas Gilbert 			if (sdebug_verbose)
1118acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1119acafd0b9SEwan D. Milne 			break;
112019c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
112119c8ead7SEwan D. Milne 			/*
112219c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
112319c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
112419c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
112519c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1126773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
112719c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
112819c8ead7SEwan D. Milne 			 */
1129773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
113019c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1131f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
113219c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
113319c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1134773642d9SDouglas Gilbert 			if (sdebug_verbose)
113519c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
113619c8ead7SEwan D. Milne 			break;
1137cbf67842SDouglas Gilbert 		default:
1138773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1139773642d9SDouglas Gilbert 			if (sdebug_verbose)
1140cbf67842SDouglas Gilbert 				cp = "unknown";
1141cbf67842SDouglas Gilbert 			break;
1142cbf67842SDouglas Gilbert 		}
1143cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1144773642d9SDouglas Gilbert 		if (sdebug_verbose)
1145f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1146cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1147cbf67842SDouglas Gilbert 				   my_name, cp);
11481da177e4SLinus Torvalds 		return check_condition_result;
11491da177e4SLinus Torvalds 	}
11501da177e4SLinus Torvalds 	return 0;
11511da177e4SLinus Torvalds }
11521da177e4SLinus Torvalds 
1153fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11541da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11551da177e4SLinus Torvalds 				int arr_len)
11561da177e4SLinus Torvalds {
115721a61829SFUJITA Tomonori 	int act_len;
1158ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11591da177e4SLinus Torvalds 
1160072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11611da177e4SLinus Torvalds 		return 0;
1162ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1163773642d9SDouglas Gilbert 		return DID_ERROR << 16;
116421a61829SFUJITA Tomonori 
116521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
116621a61829SFUJITA Tomonori 				      arr, arr_len);
116742d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
116821a61829SFUJITA Tomonori 
11691da177e4SLinus Torvalds 	return 0;
11701da177e4SLinus Torvalds }
11711da177e4SLinus Torvalds 
1172fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1173fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1174fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1175fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1176fb0cc8d1SDouglas Gilbert  */
1177fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1178fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1179fb0cc8d1SDouglas Gilbert {
11809237f04eSDamien Le Moal 	unsigned int act_len, n;
1181ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1182fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1183fb0cc8d1SDouglas Gilbert 
1184fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1185fb0cc8d1SDouglas Gilbert 		return 0;
1186ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1187fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1188fb0cc8d1SDouglas Gilbert 
1189fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1190fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1191fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
119242d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
119342d387beSBart Van Assche 		 scsi_get_resid(scp));
11949237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
119587c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1196fb0cc8d1SDouglas Gilbert 	return 0;
1197fb0cc8d1SDouglas Gilbert }
1198fb0cc8d1SDouglas Gilbert 
1199fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1200fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1201fb0cc8d1SDouglas Gilbert  */
12021da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
120321a61829SFUJITA Tomonori 			       int arr_len)
12041da177e4SLinus Torvalds {
120521a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12061da177e4SLinus Torvalds 		return 0;
1207ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12081da177e4SLinus Torvalds 		return -1;
120921a61829SFUJITA Tomonori 
121021a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12111da177e4SLinus Torvalds }
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 
1214e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1215e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12169b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12171b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12181b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12191b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12201b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12211da177e4SLinus Torvalds 
1222cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1223760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12245a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
122509ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1226bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12271da177e4SLinus Torvalds {
1228c65b1445SDouglas Gilbert 	int num, port_a;
1229c65b1445SDouglas Gilbert 	char b[32];
12301da177e4SLinus Torvalds 
1231c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12321da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12331da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12341da177e4SLinus Torvalds 	arr[1] = 0x1;
12351da177e4SLinus Torvalds 	arr[2] = 0x0;
1236e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1237e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12381da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12391da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12401da177e4SLinus Torvalds 	arr[3] = num;
12411da177e4SLinus Torvalds 	num += 4;
1242c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
124309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
124409ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
124509ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
124609ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
124709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124809ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
124909ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
125009ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125109ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
125209ba24c1SDouglas Gilbert 			num += 16;
125309ba24c1SDouglas Gilbert 		} else {
12541b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1255c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1256c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1257c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1258c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12591b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1260773642d9SDouglas Gilbert 			num += 8;
126109ba24c1SDouglas Gilbert 		}
1262c65b1445SDouglas Gilbert 		/* Target relative port number */
1263c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1264c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1265c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1266c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1267c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1268c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1269c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1270c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1271c65b1445SDouglas Gilbert 	}
12721b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1273c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1274c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1275c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1276c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12771b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1278773642d9SDouglas Gilbert 	num += 8;
12791b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12805a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12815a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12825a09e398SHannes Reinecke 	arr[num++] = 0x0;
12835a09e398SHannes Reinecke 	arr[num++] = 0x4;
12845a09e398SHannes Reinecke 	arr[num++] = 0;
12855a09e398SHannes Reinecke 	arr[num++] = 0;
1286773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1287773642d9SDouglas Gilbert 	num += 2;
12881b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1289c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1290c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1291c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1292c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12931b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1294773642d9SDouglas Gilbert 	num += 8;
1295c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1296c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1297c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1298c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1299c65b1445SDouglas Gilbert 	arr[num++] = 24;
13001b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1301c65b1445SDouglas Gilbert 	num += 12;
1302c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1303c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1304c65b1445SDouglas Gilbert 	num += 8;
1305c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1306c65b1445SDouglas Gilbert 	num += 4;
1307c65b1445SDouglas Gilbert 	return num;
1308c65b1445SDouglas Gilbert }
1309c65b1445SDouglas Gilbert 
1310c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1311c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1312c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1313c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1314c65b1445SDouglas Gilbert };
1315c65b1445SDouglas Gilbert 
1316cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1317760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1318c65b1445SDouglas Gilbert {
1319c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1320c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1321c65b1445SDouglas Gilbert }
1322c65b1445SDouglas Gilbert 
1323cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1324760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1325c65b1445SDouglas Gilbert {
1326c65b1445SDouglas Gilbert 	int num = 0;
1327c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1328c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1329c65b1445SDouglas Gilbert 	int plen, olen;
1330c65b1445SDouglas Gilbert 
1331c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1332c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1333c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1334c65b1445SDouglas Gilbert 	olen = strlen(na1);
1335c65b1445SDouglas Gilbert 	plen = olen + 1;
1336c65b1445SDouglas Gilbert 	if (plen % 4)
1337c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1338c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1339c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1340c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1341c65b1445SDouglas Gilbert 	num += plen;
1342c65b1445SDouglas Gilbert 
1343c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1344c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1345c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1346c65b1445SDouglas Gilbert 	olen = strlen(na2);
1347c65b1445SDouglas Gilbert 	plen = olen + 1;
1348c65b1445SDouglas Gilbert 	if (plen % 4)
1349c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1350c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1351c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1352c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1353c65b1445SDouglas Gilbert 	num += plen;
1354c65b1445SDouglas Gilbert 
1355c65b1445SDouglas Gilbert 	return num;
1356c65b1445SDouglas Gilbert }
1357c65b1445SDouglas Gilbert 
1358c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1359760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1360c65b1445SDouglas Gilbert {
1361c65b1445SDouglas Gilbert 	int num = 0;
1362c65b1445SDouglas Gilbert 	int port_a, port_b;
1363c65b1445SDouglas Gilbert 
1364c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1365c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1366c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1367c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1368c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1369c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1370c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1371c65b1445SDouglas Gilbert 	num += 6;
1372c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1373c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1374c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1375c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1376c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13791b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1380773642d9SDouglas Gilbert 	num += 8;
1381c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1385c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1386c65b1445SDouglas Gilbert 	num += 6;
1387c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1388c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1389c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1390c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1393c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13941b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1395773642d9SDouglas Gilbert 	num += 8;
1396c65b1445SDouglas Gilbert 
1397c65b1445SDouglas Gilbert 	return num;
1398c65b1445SDouglas Gilbert }
1399c65b1445SDouglas Gilbert 
1400c65b1445SDouglas Gilbert 
1401c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1402c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1403c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1404c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1405c65b1445SDouglas Gilbert '1','2','3','4',
1406c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1407c65b1445SDouglas Gilbert 0xec,0,0,0,
1408c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1409c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1410c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1411c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1412c65b1445SDouglas Gilbert 0x53,0x41,
1413c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1414c65b1445SDouglas Gilbert 0x20,0x20,
1415c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1416c65b1445SDouglas Gilbert 0x10,0x80,
1417c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1418c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1419c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1420c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1421c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1422c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1423c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1424c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1425c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1426c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1427c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1428c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1429c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1430c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1438c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1441c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1442c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1443c65b1445SDouglas Gilbert };
1444c65b1445SDouglas Gilbert 
1445cbf67842SDouglas Gilbert /* ATA Information VPD page */
1446760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1447c65b1445SDouglas Gilbert {
1448c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1449c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1450c65b1445SDouglas Gilbert }
1451c65b1445SDouglas Gilbert 
1452c65b1445SDouglas Gilbert 
1453c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14541e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14551e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14561e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14571e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1458c65b1445SDouglas Gilbert };
1459c65b1445SDouglas Gilbert 
1460cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1461760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1462c65b1445SDouglas Gilbert {
1463ea61fca5SMartin K. Petersen 	unsigned int gran;
1464ea61fca5SMartin K. Petersen 
1465c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1466e308b3d1SMartin K. Petersen 
1467e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
146886e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
146986e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
147086e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
147186e6828aSLukas Herbolt 	else
1472773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1473773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1474e308b3d1SMartin K. Petersen 
1475e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1476773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1477773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
147844d92694SMartin K. Petersen 
1479e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1480773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1481e308b3d1SMartin K. Petersen 
1482773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1483e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1484773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1485e308b3d1SMartin K. Petersen 
1486e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1487773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
148844d92694SMartin K. Petersen 	}
148944d92694SMartin K. Petersen 
1490e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1491773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1492773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
149344d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
149444d92694SMartin K. Petersen 	}
149544d92694SMartin K. Petersen 
1496e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1497773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14986014759cSMartin K. Petersen 
14995b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1500773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15015b94e232SMartin K. Petersen 
15025b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
150344d92694SMartin K. Petersen 
1504c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15051da177e4SLinus Torvalds }
15061da177e4SLinus Torvalds 
15071e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
150864e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1509eac6e8e4SMatthew Wilcox {
1510eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1511eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15121e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15131e49f785SDouglas Gilbert 	arr[2] = 0;
15141e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
151564e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
151664e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1517eac6e8e4SMatthew Wilcox 
1518eac6e8e4SMatthew Wilcox 	return 0x3c;
1519eac6e8e4SMatthew Wilcox }
15201da177e4SLinus Torvalds 
1521760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1522760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15236014759cSMartin K. Petersen {
15243f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15256014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1526773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15276014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1528773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15296014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1530773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15315b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1532760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1533760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1534760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1535760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1536760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15373f0bc3b3SMartin K. Petersen 	return 0x4;
15386014759cSMartin K. Petersen }
15396014759cSMartin K. Petersen 
1540d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1541f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1542d36da305SDouglas Gilbert {
1543d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1544d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1545d36da305SDouglas Gilbert 	/*
1546d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1547d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1548f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1549f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1550d36da305SDouglas Gilbert 	 */
1551d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1552d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
155364e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1554f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1555f0d1cf93SDouglas Gilbert 	else
1556d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1557d36da305SDouglas Gilbert 	return 0x3c;
1558d36da305SDouglas Gilbert }
1559d36da305SDouglas Gilbert 
15601da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1561c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15621da177e4SLinus Torvalds 
1563c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15641da177e4SLinus Torvalds {
15651da177e4SLinus Torvalds 	unsigned char pq_pdt;
15665a09e398SHannes Reinecke 	unsigned char *arr;
156701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15685a09e398SHannes Reinecke 	int alloc_len, n, ret;
1569d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15701da177e4SLinus Torvalds 
1571773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15726f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15736f3cbf55SDouglas Gilbert 	if (! arr)
15746f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1575760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
157664e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1577d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1578b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1579c2248fc9SDouglas Gilbert 	if (have_wlun)
1580b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1581b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1582b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1583c65b1445SDouglas Gilbert 	else
1584773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15851da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15861da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
158722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15885a09e398SHannes Reinecke 		kfree(arr);
15891da177e4SLinus Torvalds 		return check_condition_result;
15901da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15915a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1592c65b1445SDouglas Gilbert 		char lu_id_str[6];
1593c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
15941da177e4SLinus Torvalds 
15955a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
15965a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1597b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
159823183910SDouglas Gilbert 			host_no = 0;
1599c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1600c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1601c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1602c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1603c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16041da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1605c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1606c65b1445SDouglas Gilbert 			n = 4;
1607c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1608c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1609c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1610c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1611c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1612c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1613c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1615d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1616c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1617760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1618760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1619d36da305SDouglas Gilbert 				if (is_disk)
1620d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
162164e14eceSDamien Le Moal 				if (is_zbc)
1622d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1623760f3b03SDouglas Gilbert 			}
1624c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16251da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1626c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16271da177e4SLinus Torvalds 			arr[3] = len;
1628c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16291da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1630c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1631760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16325a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
163309ba24c1SDouglas Gilbert 						lu_id_str, len,
163409ba24c1SDouglas Gilbert 						&devip->lu_name);
1635c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1636c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1637760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1638c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1639c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1640760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1641c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1642c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1643c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16448475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1645c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1646760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1647c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1648c6a44287SMartin K. Petersen 			else
1649c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1650c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1651c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1652c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1653c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1654c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1655c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1656c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1657c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1658c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1659c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1660760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1661d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1662c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1663760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1664773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1665d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1666c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1667760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1668d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1669eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
167064e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1671760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16726014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1673760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1674d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1675d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1676f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16771da177e4SLinus Torvalds 		} else {
167822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16795a09e398SHannes Reinecke 			kfree(arr);
16801da177e4SLinus Torvalds 			return check_condition_result;
16811da177e4SLinus Torvalds 		}
1682773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
16835a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1684c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
16855a09e398SHannes Reinecke 		kfree(arr);
16865a09e398SHannes Reinecke 		return ret;
16871da177e4SLinus Torvalds 	}
16881da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1689773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1690773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16911da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16921da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1693f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1694b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
169570bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1696c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
16971da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1698c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1699e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1700e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1701e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17029b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17039b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17041da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1705760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1706760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1707c65b1445SDouglas Gilbert 	n = 62;
1708760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1709760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1710760f3b03SDouglas Gilbert 		n += 2;
1711760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1712760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1713760f3b03SDouglas Gilbert 		n += 2;
1714d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1715d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1716d36da305SDouglas Gilbert 		n += 2;
17171da177e4SLinus Torvalds 	}
1718760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17195a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
172087c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
17215a09e398SHannes Reinecke 	kfree(arr);
17225a09e398SHannes Reinecke 	return ret;
17231da177e4SLinus Torvalds }
17241da177e4SLinus Torvalds 
172584905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1726fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1727fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1728fd32119bSDouglas Gilbert 
17291da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17301da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17311da177e4SLinus Torvalds {
173201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
173384905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
173484905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
173584905d34SDouglas Gilbert 	int alloc_len = cmd[4];
17361da177e4SLinus Torvalds 	int len = 18;
173784905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17381da177e4SLinus Torvalds 
1739c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
174084905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
174184905d34SDouglas Gilbert 		if (dsense) {
174284905d34SDouglas Gilbert 			arr[0] = 0x72;
174384905d34SDouglas Gilbert 			arr[1] = NOT_READY;
174484905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
174584905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
174684905d34SDouglas Gilbert 			len = 8;
174784905d34SDouglas Gilbert 		} else {
174884905d34SDouglas Gilbert 			arr[0] = 0x70;
174984905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
175084905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
175184905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
175284905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
175384905d34SDouglas Gilbert 		}
175484905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
175584905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1756c2248fc9SDouglas Gilbert 		if (dsense) {
1757c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1758c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1759c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
176084905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1761c2248fc9SDouglas Gilbert 			len = 8;
1762c65b1445SDouglas Gilbert 		} else {
1763c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1764c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1765c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1766c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
176784905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1768c65b1445SDouglas Gilbert 		}
176984905d34SDouglas Gilbert 	} else {	/* nothing to report */
1770c2248fc9SDouglas Gilbert 		if (dsense) {
1771c2248fc9SDouglas Gilbert 			len = 8;
177284905d34SDouglas Gilbert 			memset(arr, 0, len);
177384905d34SDouglas Gilbert 			arr[0] = 0x72;
1774c2248fc9SDouglas Gilbert 		} else {
177584905d34SDouglas Gilbert 			memset(arr, 0, len);
1776c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1777c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1778c2248fc9SDouglas Gilbert 		}
1779c65b1445SDouglas Gilbert 	}
178084905d34SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
17811da177e4SLinus Torvalds }
17821da177e4SLinus Torvalds 
1783fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1784c65b1445SDouglas Gilbert {
178501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1786fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
17874f2c8bf6SDouglas Gilbert 	bool changing;
1788c65b1445SDouglas Gilbert 
1789c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1790c65b1445SDouglas Gilbert 	if (power_cond) {
179122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1792c65b1445SDouglas Gilbert 		return check_condition_result;
1793c65b1445SDouglas Gilbert 	}
1794fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1795fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1796fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1797fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1798fc13638aSDouglas Gilbert 
1799fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1800fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1801fc13638aSDouglas Gilbert 
1802fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1803fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1804fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1805fc13638aSDouglas Gilbert 				stopped_state = 0;
1806fc13638aSDouglas Gilbert 			}
1807fc13638aSDouglas Gilbert 		}
1808fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1809fc13638aSDouglas Gilbert 			if (want_stop) {
1810fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1811fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1812fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1813fc13638aSDouglas Gilbert 				return check_condition_result;
1814fc13638aSDouglas Gilbert 			}
1815fc13638aSDouglas Gilbert 		}
1816fc13638aSDouglas Gilbert 	}
1817fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1818fc13638aSDouglas Gilbert 	if (changing)
1819fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1820fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18214f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18224f2c8bf6SDouglas Gilbert 	else
18234f2c8bf6SDouglas Gilbert 		return 0;
1824c65b1445SDouglas Gilbert }
1825c65b1445SDouglas Gilbert 
182628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
182728898873SFUJITA Tomonori {
1828773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1829773642d9SDouglas Gilbert 
1830773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1831773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1832773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
183328898873SFUJITA Tomonori 	else
183428898873SFUJITA Tomonori 		return sdebug_store_sectors;
183528898873SFUJITA Tomonori }
183628898873SFUJITA Tomonori 
18371da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18381da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18391da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18401da177e4SLinus Torvalds {
18411da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1842c65b1445SDouglas Gilbert 	unsigned int capac;
18431da177e4SLinus Torvalds 
1844c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
184528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18461da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1847c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1848c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1849773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1850773642d9SDouglas Gilbert 	} else
1851773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1852773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18531da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18541da177e4SLinus Torvalds }
18551da177e4SLinus Torvalds 
1856c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1857c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1858c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1859c65b1445SDouglas Gilbert {
186001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1861c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1862773642d9SDouglas Gilbert 	int alloc_len;
1863c65b1445SDouglas Gilbert 
1864773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1865c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1867c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1868773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1869773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1870773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1871773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
187244d92694SMartin K. Petersen 
1873be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18745b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1875760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1876760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1877760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1878760f3b03SDouglas Gilbert 		 */
1879760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1880760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1881be1dd78dSEric Sandeen 	}
188244d92694SMartin K. Petersen 
1883773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1884c6a44287SMartin K. Petersen 
1885760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1886773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1887c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1888c6a44287SMartin K. Petersen 	}
1889c6a44287SMartin K. Petersen 
1890c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
189187c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1892c65b1445SDouglas Gilbert }
1893c65b1445SDouglas Gilbert 
18945a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18955a09e398SHannes Reinecke 
18965a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18975a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18985a09e398SHannes Reinecke {
189901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19005a09e398SHannes Reinecke 	unsigned char *arr;
19015a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19025a09e398SHannes Reinecke 	int n, ret, alen, rlen;
19035a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
19045a09e398SHannes Reinecke 
1905773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19066f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19076f3cbf55SDouglas Gilbert 	if (! arr)
19086f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19095a09e398SHannes Reinecke 	/*
19105a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19115a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19125a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19135a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19145a09e398SHannes Reinecke 	 */
19155a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19165a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19175a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19185a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19195a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19205a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19215a09e398SHannes Reinecke 
19225a09e398SHannes Reinecke 	/*
19235a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19245a09e398SHannes Reinecke 	 */
19255a09e398SHannes Reinecke 	n = 4;
1926b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19275a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19285a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19295a09e398SHannes Reinecke 	} else {
19305a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1931773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19325a09e398SHannes Reinecke 	}
1933773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1934773642d9SDouglas Gilbert 	n += 2;
19355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19385a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1941773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1942773642d9SDouglas Gilbert 	n += 2;
19435a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19445a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1945773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1946773642d9SDouglas Gilbert 	n += 2;
19475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19505a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1953773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1954773642d9SDouglas Gilbert 	n += 2;
19555a09e398SHannes Reinecke 
19565a09e398SHannes Reinecke 	rlen = n - 4;
1957773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19585a09e398SHannes Reinecke 
19595a09e398SHannes Reinecke 	/*
19605a09e398SHannes Reinecke 	 * Return the smallest value of either
19615a09e398SHannes Reinecke 	 * - The allocated length
19625a09e398SHannes Reinecke 	 * - The constructed command length
19635a09e398SHannes Reinecke 	 * - The maximum array size
19645a09e398SHannes Reinecke 	 */
196587c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
19665a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
196787c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19685a09e398SHannes Reinecke 	kfree(arr);
19695a09e398SHannes Reinecke 	return ret;
19705a09e398SHannes Reinecke }
19715a09e398SHannes Reinecke 
1972fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1973fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
197438d5c833SDouglas Gilbert {
197538d5c833SDouglas Gilbert 	bool rctd;
197638d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
197738d5c833SDouglas Gilbert 	u16 req_sa, u;
197838d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
197938d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
198038d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
198138d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
198238d5c833SDouglas Gilbert 	u8 *arr;
198338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
198438d5c833SDouglas Gilbert 
198538d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
198638d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
198738d5c833SDouglas Gilbert 	req_opcode = cmd[3];
198838d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
198938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19906d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
199138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
199238d5c833SDouglas Gilbert 		return check_condition_result;
199338d5c833SDouglas Gilbert 	}
199438d5c833SDouglas Gilbert 	if (alloc_len > 8192)
199538d5c833SDouglas Gilbert 		a_len = 8192;
199638d5c833SDouglas Gilbert 	else
199738d5c833SDouglas Gilbert 		a_len = alloc_len;
199899531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
199938d5c833SDouglas Gilbert 	if (NULL == arr) {
200038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
200138d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
200238d5c833SDouglas Gilbert 		return check_condition_result;
200338d5c833SDouglas Gilbert 	}
200438d5c833SDouglas Gilbert 	switch (reporting_opts) {
200538d5c833SDouglas Gilbert 	case 0:	/* all commands */
200638d5c833SDouglas Gilbert 		/* count number of commands */
200738d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
200838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
200938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
201038d5c833SDouglas Gilbert 				continue;
201138d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
201238d5c833SDouglas Gilbert 		}
201338d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
201438d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
201538d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
201638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
201738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
201838d5c833SDouglas Gilbert 				continue;
201938d5c833SDouglas Gilbert 			na = oip->num_attached;
202038d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
202138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
202238d5c833SDouglas Gilbert 			if (rctd)
202338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
202438d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
202538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
202638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
202738d5c833SDouglas Gilbert 			if (rctd)
202838d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
202938d5c833SDouglas Gilbert 			r_oip = oip;
203038d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
203138d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
203238d5c833SDouglas Gilbert 					continue;
203338d5c833SDouglas Gilbert 				offset += bump;
203438d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
203538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
203638d5c833SDouglas Gilbert 				if (rctd)
203738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
203838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
203938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
204038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
204138d5c833SDouglas Gilbert 						   arr + offset + 6);
204238d5c833SDouglas Gilbert 				if (rctd)
204338d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
204438d5c833SDouglas Gilbert 							   arr + offset + 8);
204538d5c833SDouglas Gilbert 			}
204638d5c833SDouglas Gilbert 			oip = r_oip;
204738d5c833SDouglas Gilbert 			offset += bump;
204838d5c833SDouglas Gilbert 		}
204938d5c833SDouglas Gilbert 		break;
205038d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
205138d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
205238d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
205338d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
205438d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
205538d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
205638d5c833SDouglas Gilbert 			supp = 1;
205738d5c833SDouglas Gilbert 			offset = 4;
205838d5c833SDouglas Gilbert 		} else {
205938d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
206038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
206138d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
206238d5c833SDouglas Gilbert 							     2, 2);
206338d5c833SDouglas Gilbert 					kfree(arr);
206438d5c833SDouglas Gilbert 					return check_condition_result;
206538d5c833SDouglas Gilbert 				}
206638d5c833SDouglas Gilbert 				req_sa = 0;
206738d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
206838d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
206938d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
207038d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
207138d5c833SDouglas Gilbert 				return check_condition_result;
207238d5c833SDouglas Gilbert 			}
207338d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
207438d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
207538d5c833SDouglas Gilbert 				supp = 3;
207638d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
207738d5c833SDouglas Gilbert 				na = oip->num_attached;
207838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
207938d5c833SDouglas Gilbert 				     ++k, ++oip) {
208038d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
208138d5c833SDouglas Gilbert 						break;
208238d5c833SDouglas Gilbert 				}
208338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208438d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
208538d5c833SDouglas Gilbert 				na = oip->num_attached;
208638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
208738d5c833SDouglas Gilbert 				     ++k, ++oip) {
208838d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
208938d5c833SDouglas Gilbert 						break;
209038d5c833SDouglas Gilbert 				}
209138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
209238d5c833SDouglas Gilbert 			} else
209338d5c833SDouglas Gilbert 				supp = 3;
209438d5c833SDouglas Gilbert 			if (3 == supp) {
209538d5c833SDouglas Gilbert 				u = oip->len_mask[0];
209638d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
209738d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
209838d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
209938d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
210038d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
210138d5c833SDouglas Gilbert 				offset = 4 + u;
210238d5c833SDouglas Gilbert 			} else
210338d5c833SDouglas Gilbert 				offset = 4;
210438d5c833SDouglas Gilbert 		}
210538d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
210638d5c833SDouglas Gilbert 		if (rctd) {
210738d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
210838d5c833SDouglas Gilbert 			offset += 12;
210938d5c833SDouglas Gilbert 		}
211038d5c833SDouglas Gilbert 		break;
211138d5c833SDouglas Gilbert 	default:
211238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
211338d5c833SDouglas Gilbert 		kfree(arr);
211438d5c833SDouglas Gilbert 		return check_condition_result;
211538d5c833SDouglas Gilbert 	}
211638d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
211738d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
211838d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
211938d5c833SDouglas Gilbert 	kfree(arr);
212038d5c833SDouglas Gilbert 	return errsts;
212138d5c833SDouglas Gilbert }
212238d5c833SDouglas Gilbert 
2123fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2124fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
212538d5c833SDouglas Gilbert {
212638d5c833SDouglas Gilbert 	bool repd;
212738d5c833SDouglas Gilbert 	u32 alloc_len, len;
212838d5c833SDouglas Gilbert 	u8 arr[16];
212938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
213038d5c833SDouglas Gilbert 
213138d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
213238d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
213338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
213438d5c833SDouglas Gilbert 	if (alloc_len < 4) {
213538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
213638d5c833SDouglas Gilbert 		return check_condition_result;
213738d5c833SDouglas Gilbert 	}
213838d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
213938d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
214038d5c833SDouglas Gilbert 	if (repd) {
214138d5c833SDouglas Gilbert 		arr[3] = 0xc;
214238d5c833SDouglas Gilbert 		len = 16;
214338d5c833SDouglas Gilbert 	} else
214438d5c833SDouglas Gilbert 		len = 4;
214538d5c833SDouglas Gilbert 
214638d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
214738d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
214838d5c833SDouglas Gilbert }
214938d5c833SDouglas Gilbert 
21501da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21511da177e4SLinus Torvalds 
21521da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21531da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21541da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21551da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21561da177e4SLinus Torvalds 
21571da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21581da177e4SLinus Torvalds 	if (1 == pcontrol)
21591da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21601da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21611da177e4SLinus Torvalds }
21621da177e4SLinus Torvalds 
21631da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21641da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21651da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21661da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21671da177e4SLinus Torvalds 
21681da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21691da177e4SLinus Torvalds 	if (1 == pcontrol)
21701da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21711da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21721da177e4SLinus Torvalds }
21731da177e4SLinus Torvalds 
21741da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21751da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21761da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21771da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21781da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21791da177e4SLinus Torvalds 
21801da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2181773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2182773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2183773642d9SDouglas Gilbert 	if (sdebug_removable)
21841da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21851da177e4SLinus Torvalds 	if (1 == pcontrol)
21861da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21871da177e4SLinus Torvalds 	return sizeof(format_pg);
21881da177e4SLinus Torvalds }
21891da177e4SLinus Torvalds 
2190fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2191fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2192fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2193fd32119bSDouglas Gilbert 
21941da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21951da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2196cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2197cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2198cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21991da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22001da177e4SLinus Torvalds 
2201773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2202cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22031da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22041da177e4SLinus Torvalds 	if (1 == pcontrol)
2205cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2206cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2207cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22081da177e4SLinus Torvalds 	return sizeof(caching_pg);
22091da177e4SLinus Torvalds }
22101da177e4SLinus Torvalds 
2211fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2212fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2213fd32119bSDouglas Gilbert 
22141da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22151da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2216c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2217c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2218c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22191da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22201da177e4SLinus Torvalds 
2221773642d9SDouglas Gilbert 	if (sdebug_dsense)
22221da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2223c65b1445SDouglas Gilbert 	else
2224c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2225c6a44287SMartin K. Petersen 
2226773642d9SDouglas Gilbert 	if (sdebug_ato)
2227c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2228c6a44287SMartin K. Petersen 
22291da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22301da177e4SLinus Torvalds 	if (1 == pcontrol)
2231c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2232c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2233c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22341da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22351da177e4SLinus Torvalds }
22361da177e4SLinus Torvalds 
2237c65b1445SDouglas Gilbert 
22381da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22391da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2240c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22411da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2242c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2243c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2244c65b1445SDouglas Gilbert 
22451da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22461da177e4SLinus Torvalds 	if (1 == pcontrol)
2247c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2248c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2249c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22501da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22511da177e4SLinus Torvalds }
22521da177e4SLinus Torvalds 
2253c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2254c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2255c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2256c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2257c65b1445SDouglas Gilbert 
2258c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2259c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2260c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2261c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2262c65b1445SDouglas Gilbert }
2263c65b1445SDouglas Gilbert 
2264c65b1445SDouglas Gilbert 
2265c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2266c65b1445SDouglas Gilbert 			      int target_dev_id)
2267c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2268c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2269c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2270773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2271773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2272c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2273c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2274c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2275c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2276773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2277773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2278c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2279c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2280c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2281c65b1445SDouglas Gilbert 		};
2282c65b1445SDouglas Gilbert 	int port_a, port_b;
2283c65b1445SDouglas Gilbert 
22841b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22851b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22861b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22871b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2288c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2289c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2290c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2291773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2292773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2293c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2294c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2295c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2296c65b1445SDouglas Gilbert }
2297c65b1445SDouglas Gilbert 
2298c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2299c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2300c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2301c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2302c65b1445SDouglas Gilbert 		};
2303c65b1445SDouglas Gilbert 
2304c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2305c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2306c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2307c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2308c65b1445SDouglas Gilbert }
2309c65b1445SDouglas Gilbert 
23101da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23111da177e4SLinus Torvalds 
2312fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2313fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23141da177e4SLinus Torvalds {
231523183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23161da177e4SLinus Torvalds 	unsigned char dev_spec;
2317760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2318c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23191da177e4SLinus Torvalds 	unsigned char *ap;
23201da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
232101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2322d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23231da177e4SLinus Torvalds 
2324760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23251da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23261da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23271da177e4SLinus Torvalds 	subpcode = cmd[3];
23281da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2329760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2330760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
233164e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2332d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
233323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
233423183910SDouglas Gilbert 	else
233523183910SDouglas Gilbert 		bd_len = 0;
2336773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23371da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23381da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2339cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23401da177e4SLinus Torvalds 		return check_condition_result;
23411da177e4SLinus Torvalds 	}
2342c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2343c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2344d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2345d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2346b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23479447b6ceSMartin K. Petersen 		if (sdebug_wp)
23489447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23499447b6ceSMartin K. Petersen 	} else
235023183910SDouglas Gilbert 		dev_spec = 0x0;
23511da177e4SLinus Torvalds 	if (msense_6) {
23521da177e4SLinus Torvalds 		arr[2] = dev_spec;
235323183910SDouglas Gilbert 		arr[3] = bd_len;
23541da177e4SLinus Torvalds 		offset = 4;
23551da177e4SLinus Torvalds 	} else {
23561da177e4SLinus Torvalds 		arr[3] = dev_spec;
235723183910SDouglas Gilbert 		if (16 == bd_len)
235823183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
235923183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23601da177e4SLinus Torvalds 		offset = 8;
23611da177e4SLinus Torvalds 	}
23621da177e4SLinus Torvalds 	ap = arr + offset;
236328898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
236428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
236528898873SFUJITA Tomonori 
236623183910SDouglas Gilbert 	if (8 == bd_len) {
2367773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2368773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2369773642d9SDouglas Gilbert 		else
2370773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2371773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
237223183910SDouglas Gilbert 		offset += bd_len;
237323183910SDouglas Gilbert 		ap = arr + offset;
237423183910SDouglas Gilbert 	} else if (16 == bd_len) {
2375773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2376773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
237723183910SDouglas Gilbert 		offset += bd_len;
237823183910SDouglas Gilbert 		ap = arr + offset;
237923183910SDouglas Gilbert 	}
23801da177e4SLinus Torvalds 
2381c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2382c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
238322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23841da177e4SLinus Torvalds 		return check_condition_result;
23851da177e4SLinus Torvalds 	}
2386760f3b03SDouglas Gilbert 	bad_pcode = false;
2387760f3b03SDouglas Gilbert 
23881da177e4SLinus Torvalds 	switch (pcode) {
23891da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23901da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23911da177e4SLinus Torvalds 		offset += len;
23921da177e4SLinus Torvalds 		break;
23931da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23941da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23951da177e4SLinus Torvalds 		offset += len;
23961da177e4SLinus Torvalds 		break;
23971da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2398760f3b03SDouglas Gilbert 		if (is_disk) {
23991da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24001da177e4SLinus Torvalds 			offset += len;
2401760f3b03SDouglas Gilbert 		} else
2402760f3b03SDouglas Gilbert 			bad_pcode = true;
24031da177e4SLinus Torvalds 		break;
24041da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2405d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24061da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24071da177e4SLinus Torvalds 			offset += len;
2408760f3b03SDouglas Gilbert 		} else
2409760f3b03SDouglas Gilbert 			bad_pcode = true;
24101da177e4SLinus Torvalds 		break;
24111da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24121da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24131da177e4SLinus Torvalds 		offset += len;
24141da177e4SLinus Torvalds 		break;
2415c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2416c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
241722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2418c65b1445SDouglas Gilbert 			return check_condition_result;
2419c65b1445SDouglas Gilbert 		}
2420c65b1445SDouglas Gilbert 		len = 0;
2421c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2422c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2423c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2424c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2425c65b1445SDouglas Gilbert 						  target_dev_id);
2426c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2427c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2428c65b1445SDouglas Gilbert 		offset += len;
2429c65b1445SDouglas Gilbert 		break;
24301da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24311da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24321da177e4SLinus Torvalds 		offset += len;
24331da177e4SLinus Torvalds 		break;
24341da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2435c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24361da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24371da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2438760f3b03SDouglas Gilbert 			if (is_disk) {
2439760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2440760f3b03SDouglas Gilbert 						      target);
2441760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2442760f3b03SDouglas Gilbert 						       target);
2443d36da305SDouglas Gilbert 			} else if (is_zbc) {
2444d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2445d36da305SDouglas Gilbert 						       target);
2446760f3b03SDouglas Gilbert 			}
24471da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2448c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2449c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2450c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2451c65b1445SDouglas Gilbert 						  target, target_dev_id);
2452c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2453c65b1445SDouglas Gilbert 			}
24541da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2455760f3b03SDouglas Gilbert 			offset += len;
2456c65b1445SDouglas Gilbert 		} else {
245722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2458c65b1445SDouglas Gilbert 			return check_condition_result;
2459c65b1445SDouglas Gilbert 		}
24601da177e4SLinus Torvalds 		break;
24611da177e4SLinus Torvalds 	default:
2462760f3b03SDouglas Gilbert 		bad_pcode = true;
2463760f3b03SDouglas Gilbert 		break;
2464760f3b03SDouglas Gilbert 	}
2465760f3b03SDouglas Gilbert 	if (bad_pcode) {
246622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24671da177e4SLinus Torvalds 		return check_condition_result;
24681da177e4SLinus Torvalds 	}
24691da177e4SLinus Torvalds 	if (msense_6)
24701da177e4SLinus Torvalds 		arr[0] = offset - 1;
2471773642d9SDouglas Gilbert 	else
2472773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
247387c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24741da177e4SLinus Torvalds }
24751da177e4SLinus Torvalds 
2476c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2477c65b1445SDouglas Gilbert 
2478fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2479fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2480c65b1445SDouglas Gilbert {
2481c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2482c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2483c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
248401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2485c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2486c65b1445SDouglas Gilbert 
2487c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2488c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2489c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2490773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2491c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
249222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2493c65b1445SDouglas Gilbert 		return check_condition_result;
2494c65b1445SDouglas Gilbert 	}
2495c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2496c65b1445SDouglas Gilbert 	if (-1 == res)
2497773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2498773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2499cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2500cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2501cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2502773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2503773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
250423183910SDouglas Gilbert 	if (md_len > 2) {
250522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2506c65b1445SDouglas Gilbert 		return check_condition_result;
2507c65b1445SDouglas Gilbert 	}
2508c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2509c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2510c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2511c65b1445SDouglas Gilbert 	if (ps) {
251222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2513c65b1445SDouglas Gilbert 		return check_condition_result;
2514c65b1445SDouglas Gilbert 	}
2515c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2516773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2517c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2518c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2519cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2520c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2521c65b1445SDouglas Gilbert 		return check_condition_result;
2522c65b1445SDouglas Gilbert 	}
2523c65b1445SDouglas Gilbert 	switch (mpage) {
2524cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2525cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2526cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2527cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2528cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2529cbf67842SDouglas Gilbert 		}
2530cbf67842SDouglas Gilbert 		break;
2531c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2532c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2533c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2534c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25359447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25369447b6ceSMartin K. Petersen 				sdebug_wp = true;
25379447b6ceSMartin K. Petersen 			else
25389447b6ceSMartin K. Petersen 				sdebug_wp = false;
2539773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2540cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2541c65b1445SDouglas Gilbert 		}
2542c65b1445SDouglas Gilbert 		break;
2543c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2544c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2545c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2546c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2547cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2548c65b1445SDouglas Gilbert 		}
2549c65b1445SDouglas Gilbert 		break;
2550c65b1445SDouglas Gilbert 	default:
2551c65b1445SDouglas Gilbert 		break;
2552c65b1445SDouglas Gilbert 	}
255322017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2554c65b1445SDouglas Gilbert 	return check_condition_result;
2555cbf67842SDouglas Gilbert set_mode_changed_ua:
2556cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2557cbf67842SDouglas Gilbert 	return 0;
2558c65b1445SDouglas Gilbert }
2559c65b1445SDouglas Gilbert 
2560c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2561c65b1445SDouglas Gilbert {
2562c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2563c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2564c65b1445SDouglas Gilbert 		};
2565c65b1445SDouglas Gilbert 
2566c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2567c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2568c65b1445SDouglas Gilbert }
2569c65b1445SDouglas Gilbert 
2570c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2571c65b1445SDouglas Gilbert {
2572c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2573c65b1445SDouglas Gilbert 		};
2574c65b1445SDouglas Gilbert 
2575c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2576c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2577c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2578c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2579c65b1445SDouglas Gilbert 	}
2580c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2581c65b1445SDouglas Gilbert }
2582c65b1445SDouglas Gilbert 
2583c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2584c65b1445SDouglas Gilbert 
2585c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2586c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2587c65b1445SDouglas Gilbert {
2588ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2589c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
259001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2591c65b1445SDouglas Gilbert 
2592c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2593c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2594c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2595c65b1445SDouglas Gilbert 	if (ppc || sp) {
259622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2597c65b1445SDouglas Gilbert 		return check_condition_result;
2598c65b1445SDouglas Gilbert 	}
2599c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
260023183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2601773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2602c65b1445SDouglas Gilbert 	arr[0] = pcode;
260323183910SDouglas Gilbert 	if (0 == subpcode) {
2604c65b1445SDouglas Gilbert 		switch (pcode) {
2605c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2606c65b1445SDouglas Gilbert 			n = 4;
2607c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2608c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2609c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2610c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2611c65b1445SDouglas Gilbert 			break;
2612c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2613c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2614c65b1445SDouglas Gilbert 			break;
2615c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2616c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2617c65b1445SDouglas Gilbert 			break;
2618c65b1445SDouglas Gilbert 		default:
261922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2620c65b1445SDouglas Gilbert 			return check_condition_result;
2621c65b1445SDouglas Gilbert 		}
262223183910SDouglas Gilbert 	} else if (0xff == subpcode) {
262323183910SDouglas Gilbert 		arr[0] |= 0x40;
262423183910SDouglas Gilbert 		arr[1] = subpcode;
262523183910SDouglas Gilbert 		switch (pcode) {
262623183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
262723183910SDouglas Gilbert 			n = 4;
262823183910SDouglas Gilbert 			arr[n++] = 0x0;
262923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
263023183910SDouglas Gilbert 			arr[n++] = 0x0;
263123183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
263223183910SDouglas Gilbert 			arr[n++] = 0xd;
263323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
263423183910SDouglas Gilbert 			arr[n++] = 0x2f;
263523183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
263623183910SDouglas Gilbert 			arr[3] = n - 4;
263723183910SDouglas Gilbert 			break;
263823183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
263923183910SDouglas Gilbert 			n = 4;
264023183910SDouglas Gilbert 			arr[n++] = 0xd;
264123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
264223183910SDouglas Gilbert 			arr[3] = n - 4;
264323183910SDouglas Gilbert 			break;
264423183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
264523183910SDouglas Gilbert 			n = 4;
264623183910SDouglas Gilbert 			arr[n++] = 0x2f;
264723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
264823183910SDouglas Gilbert 			arr[3] = n - 4;
264923183910SDouglas Gilbert 			break;
265023183910SDouglas Gilbert 		default:
265122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
265223183910SDouglas Gilbert 			return check_condition_result;
265323183910SDouglas Gilbert 		}
265423183910SDouglas Gilbert 	} else {
265522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
265623183910SDouglas Gilbert 		return check_condition_result;
265723183910SDouglas Gilbert 	}
265887c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2659c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
266087c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2661c65b1445SDouglas Gilbert }
2662c65b1445SDouglas Gilbert 
2663f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2664f0d1cf93SDouglas Gilbert {
2665f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2666f0d1cf93SDouglas Gilbert }
2667f0d1cf93SDouglas Gilbert 
2668f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2669f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2670f0d1cf93SDouglas Gilbert {
2671108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2672f0d1cf93SDouglas Gilbert }
2673f0d1cf93SDouglas Gilbert 
2674f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2675f0d1cf93SDouglas Gilbert {
267664e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2677f0d1cf93SDouglas Gilbert }
2678f0d1cf93SDouglas Gilbert 
2679f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2680f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2681f0d1cf93SDouglas Gilbert {
2682f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2683f0d1cf93SDouglas Gilbert 
2684f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2685f0d1cf93SDouglas Gilbert 		return;
2686f0d1cf93SDouglas Gilbert 
2687f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2688f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2689f0d1cf93SDouglas Gilbert 		return;
2690f0d1cf93SDouglas Gilbert 
2691f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2692f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2693f0d1cf93SDouglas Gilbert 	else
2694f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2695f0d1cf93SDouglas Gilbert 
2696f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2697f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2698f0d1cf93SDouglas Gilbert 	} else {
2699f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2700f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2701f0d1cf93SDouglas Gilbert 	}
2702f0d1cf93SDouglas Gilbert }
2703f0d1cf93SDouglas Gilbert 
2704f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2705f0d1cf93SDouglas Gilbert {
2706f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2707f0d1cf93SDouglas Gilbert 	unsigned int i;
2708f0d1cf93SDouglas Gilbert 
2709f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2710f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2711f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2712f0d1cf93SDouglas Gilbert 			return;
2713f0d1cf93SDouglas Gilbert 		}
2714f0d1cf93SDouglas Gilbert 	}
2715f0d1cf93SDouglas Gilbert }
2716f0d1cf93SDouglas Gilbert 
2717f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2718f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2719f0d1cf93SDouglas Gilbert {
2720f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2721f0d1cf93SDouglas Gilbert 
2722f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2723f0d1cf93SDouglas Gilbert 		return;
2724f0d1cf93SDouglas Gilbert 
2725f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2726f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2727f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2728f0d1cf93SDouglas Gilbert 		return;
2729f0d1cf93SDouglas Gilbert 
2730f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2731f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2732f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2733f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2734f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2735f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2736f0d1cf93SDouglas Gilbert 
2737f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2738f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2739f0d1cf93SDouglas Gilbert 	if (explicit) {
2740f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2741f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2742f0d1cf93SDouglas Gilbert 	} else {
2743f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2744f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2745f0d1cf93SDouglas Gilbert 	}
2746f0d1cf93SDouglas Gilbert }
2747f0d1cf93SDouglas Gilbert 
2748f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2749f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2750f0d1cf93SDouglas Gilbert {
2751f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
275264e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2753f0d1cf93SDouglas Gilbert 
2754f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2755f0d1cf93SDouglas Gilbert 		return;
2756f0d1cf93SDouglas Gilbert 
275764e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2758f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
275964e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2760f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
276164e14eceSDamien Le Moal 		return;
276264e14eceSDamien Le Moal 	}
276364e14eceSDamien Le Moal 
276464e14eceSDamien Le Moal 	while (num) {
276564e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
276664e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
276764e14eceSDamien Le Moal 
276864e14eceSDamien Le Moal 		end = lba + num;
276964e14eceSDamien Le Moal 		if (end >= zend) {
277064e14eceSDamien Le Moal 			n = zend - lba;
277164e14eceSDamien Le Moal 			zsp->z_wp = zend;
277264e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
277364e14eceSDamien Le Moal 			n = num;
277464e14eceSDamien Le Moal 			zsp->z_wp = end;
277564e14eceSDamien Le Moal 		} else {
277664e14eceSDamien Le Moal 			n = num;
277764e14eceSDamien Le Moal 		}
277864e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
277964e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
278064e14eceSDamien Le Moal 
278164e14eceSDamien Le Moal 		num -= n;
278264e14eceSDamien Le Moal 		lba += n;
278364e14eceSDamien Le Moal 		if (num) {
278464e14eceSDamien Le Moal 			zsp++;
278564e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
278664e14eceSDamien Le Moal 		}
278764e14eceSDamien Le Moal 	}
2788f0d1cf93SDouglas Gilbert }
2789f0d1cf93SDouglas Gilbert 
2790f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27919447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27921da177e4SLinus Torvalds {
2793f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2794f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2795f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2796f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2797f0d1cf93SDouglas Gilbert 
2798f0d1cf93SDouglas Gilbert 	if (!write) {
279964e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
280064e14eceSDamien Le Moal 			return 0;
280164e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2802f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2803f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2804f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2805f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2806f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2807f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2808f0d1cf93SDouglas Gilbert 			return check_condition_result;
2809f0d1cf93SDouglas Gilbert 		}
2810f0d1cf93SDouglas Gilbert 		return 0;
2811f0d1cf93SDouglas Gilbert 	}
2812f0d1cf93SDouglas Gilbert 
2813f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2814f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2815f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2816f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2817f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2818f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2819f0d1cf93SDouglas Gilbert 			return check_condition_result;
2820f0d1cf93SDouglas Gilbert 		}
2821f0d1cf93SDouglas Gilbert 		return 0;
2822f0d1cf93SDouglas Gilbert 	}
2823f0d1cf93SDouglas Gilbert 
282464e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2825f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2826f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2827f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2828f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2829f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2830f0d1cf93SDouglas Gilbert 			return check_condition_result;
2831f0d1cf93SDouglas Gilbert 		}
2832f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2833f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2834f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2835f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2836f0d1cf93SDouglas Gilbert 			return check_condition_result;
2837f0d1cf93SDouglas Gilbert 		}
2838f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2839f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2840f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2841f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2842f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2843f0d1cf93SDouglas Gilbert 			return check_condition_result;
2844f0d1cf93SDouglas Gilbert 		}
284564e14eceSDamien Le Moal 	}
2846f0d1cf93SDouglas Gilbert 
2847f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2848f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2849f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2850f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2851f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2852f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2853f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2854f0d1cf93SDouglas Gilbert 			return check_condition_result;
2855f0d1cf93SDouglas Gilbert 		}
2856f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2857f0d1cf93SDouglas Gilbert 	}
2858f0d1cf93SDouglas Gilbert 
2859f0d1cf93SDouglas Gilbert 	return 0;
2860f0d1cf93SDouglas Gilbert }
2861f0d1cf93SDouglas Gilbert 
2862f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2863f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2864f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2865f0d1cf93SDouglas Gilbert {
2866f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2867f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2868f0d1cf93SDouglas Gilbert 
2869c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
287022017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28711da177e4SLinus Torvalds 		return check_condition_result;
28721da177e4SLinus Torvalds 	}
2873c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2874c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
287522017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2876cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2877c65b1445SDouglas Gilbert 		return check_condition_result;
2878c65b1445SDouglas Gilbert 	}
28799447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28809447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28819447b6ceSMartin K. Petersen 		return check_condition_result;
28829447b6ceSMartin K. Petersen 	}
2883f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2884f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2885f0d1cf93SDouglas Gilbert 
288619789100SFUJITA Tomonori 	return 0;
288719789100SFUJITA Tomonori }
288819789100SFUJITA Tomonori 
2889b6ff8ca7SDouglas Gilbert /*
2890b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2891b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2892b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2893b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2894b6ff8ca7SDouglas Gilbert  */
2895b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2896b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
289787c715dcSDouglas Gilbert {
2898b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2899b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2900b6ff8ca7SDouglas Gilbert 		return NULL;
2901b6ff8ca7SDouglas Gilbert 	}
2902b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
290387c715dcSDouglas Gilbert }
290487c715dcSDouglas Gilbert 
2905a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
290687c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
290787c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
290819789100SFUJITA Tomonori {
290919789100SFUJITA Tomonori 	int ret;
2910c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2911a4517511SAkinobu Mita 	enum dma_data_direction dir;
291287c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
291387c715dcSDouglas Gilbert 	u8 *fsp;
291419789100SFUJITA Tomonori 
2915c2248fc9SDouglas Gilbert 	if (do_write) {
2916a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
29174f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2918a4517511SAkinobu Mita 	} else {
2919a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2920a4517511SAkinobu Mita 	}
2921a4517511SAkinobu Mita 
292287c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2923a4517511SAkinobu Mita 		return 0;
292487c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2925a4517511SAkinobu Mita 		return -1;
292687c715dcSDouglas Gilbert 	fsp = sip->storep;
292719789100SFUJITA Tomonori 
292819789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
292919789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
293019789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
293119789100SFUJITA Tomonori 
2932386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
293387c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29340a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2935773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2936a4517511SAkinobu Mita 		return ret;
2937a4517511SAkinobu Mita 
2938a4517511SAkinobu Mita 	if (rest) {
2939386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
294087c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29410a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29420a7e69c7SDouglas Gilbert 			    do_write);
2943a4517511SAkinobu Mita 	}
294419789100SFUJITA Tomonori 
294519789100SFUJITA Tomonori 	return ret;
294619789100SFUJITA Tomonori }
294719789100SFUJITA Tomonori 
294887c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
294987c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
295087c715dcSDouglas Gilbert {
295187c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
295287c715dcSDouglas Gilbert 
295387c715dcSDouglas Gilbert 	if (!sdb->length)
295487c715dcSDouglas Gilbert 		return 0;
295587c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
295687c715dcSDouglas Gilbert 		return -1;
295787c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
295887c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
295987c715dcSDouglas Gilbert }
296087c715dcSDouglas Gilbert 
296187c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
296287c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
296338d5c833SDouglas Gilbert  * return false. */
296487c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2965c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
296638d5c833SDouglas Gilbert {
296738d5c833SDouglas Gilbert 	bool res;
296838d5c833SDouglas Gilbert 	u64 block, rest = 0;
296938d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2970773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
297187c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
297238d5c833SDouglas Gilbert 
297338d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
297438d5c833SDouglas Gilbert 	if (block + num > store_blks)
297538d5c833SDouglas Gilbert 		rest = block + num - store_blks;
297638d5c833SDouglas Gilbert 
297787c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
297838d5c833SDouglas Gilbert 	if (!res)
297938d5c833SDouglas Gilbert 		return res;
298038d5c833SDouglas Gilbert 	if (rest)
298187c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
298238d5c833SDouglas Gilbert 			     rest * lb_size);
298338d5c833SDouglas Gilbert 	if (!res)
298438d5c833SDouglas Gilbert 		return res;
2985c3e2fe92SDouglas Gilbert 	if (compare_only)
2986c3e2fe92SDouglas Gilbert 		return true;
298738d5c833SDouglas Gilbert 	arr += num * lb_size;
298887c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
298938d5c833SDouglas Gilbert 	if (rest)
299087c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
299138d5c833SDouglas Gilbert 	return res;
299238d5c833SDouglas Gilbert }
299338d5c833SDouglas Gilbert 
299451d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2995beb40ea4SAkinobu Mita {
299651d648afSAkinobu Mita 	__be16 csum;
2997beb40ea4SAkinobu Mita 
2998773642d9SDouglas Gilbert 	if (sdebug_guard)
299951d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
300051d648afSAkinobu Mita 	else
3001beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
300251d648afSAkinobu Mita 
3003beb40ea4SAkinobu Mita 	return csum;
3004beb40ea4SAkinobu Mita }
3005beb40ea4SAkinobu Mita 
30066ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3007beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3008beb40ea4SAkinobu Mita {
3009773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3010beb40ea4SAkinobu Mita 
3011beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3012c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3013beb40ea4SAkinobu Mita 			(unsigned long)sector,
3014beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3015beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3016beb40ea4SAkinobu Mita 		return 0x01;
3017beb40ea4SAkinobu Mita 	}
30188475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3019beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3020c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3021c1287970STomas Winkler 			(unsigned long)sector);
3022beb40ea4SAkinobu Mita 		return 0x03;
3023beb40ea4SAkinobu Mita 	}
30248475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3025beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3026c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3027c1287970STomas Winkler 			(unsigned long)sector);
3028beb40ea4SAkinobu Mita 		return 0x03;
3029beb40ea4SAkinobu Mita 	}
3030beb40ea4SAkinobu Mita 	return 0;
3031beb40ea4SAkinobu Mita }
3032beb40ea4SAkinobu Mita 
303387c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
303465f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3035c6a44287SMartin K. Petersen {
3036be4e11beSAkinobu Mita 	size_t resid;
3037c6a44287SMartin K. Petersen 	void *paddr;
303887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3039b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
304087c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
304114faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3042be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3043c6a44287SMartin K. Petersen 
3044e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3045e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3046c6a44287SMartin K. Petersen 
304787c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
304887c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3049be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3050be4e11beSAkinobu Mita 
3051be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
305287c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
305387c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3054be4e11beSAkinobu Mita 		size_t rest = 0;
305514faa944SAkinobu Mita 
305614faa944SAkinobu Mita 		if (dif_store_end < start + len)
305714faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3058c6a44287SMartin K. Petersen 
3059be4e11beSAkinobu Mita 		paddr = miter.addr;
306014faa944SAkinobu Mita 
306165f72f2aSAkinobu Mita 		if (read)
306265f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
306365f72f2aSAkinobu Mita 		else
306465f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
306565f72f2aSAkinobu Mita 
306665f72f2aSAkinobu Mita 		if (rest) {
306765f72f2aSAkinobu Mita 			if (read)
306814faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
306965f72f2aSAkinobu Mita 			else
307065f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
307165f72f2aSAkinobu Mita 		}
3072c6a44287SMartin K. Petersen 
3073e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3074c6a44287SMartin K. Petersen 		resid -= len;
3075c6a44287SMartin K. Petersen 	}
3076be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3077bb8c063cSAkinobu Mita }
3078c6a44287SMartin K. Petersen 
307987c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3080bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3081bb8c063cSAkinobu Mita {
3082bb8c063cSAkinobu Mita 	unsigned int i;
3083bb8c063cSAkinobu Mita 	sector_t sector;
308487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3085b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
308687c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3087bb8c063cSAkinobu Mita 
3088c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3089bb8c063cSAkinobu Mita 		int ret;
3090bb8c063cSAkinobu Mita 
3091bb8c063cSAkinobu Mita 		sector = start_sec + i;
309287c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3093bb8c063cSAkinobu Mita 
309451d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3095bb8c063cSAkinobu Mita 			continue;
3096bb8c063cSAkinobu Mita 
309787c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
309887c715dcSDouglas Gilbert 				 ei_lba);
3099bb8c063cSAkinobu Mita 		if (ret) {
3100bb8c063cSAkinobu Mita 			dif_errors++;
3101bb8c063cSAkinobu Mita 			return ret;
3102bb8c063cSAkinobu Mita 		}
3103bb8c063cSAkinobu Mita 	}
3104bb8c063cSAkinobu Mita 
310587c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3106c6a44287SMartin K. Petersen 	dix_reads++;
3107c6a44287SMartin K. Petersen 
3108c6a44287SMartin K. Petersen 	return 0;
3109c6a44287SMartin K. Petersen }
3110c6a44287SMartin K. Petersen 
3111fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
311219789100SFUJITA Tomonori {
311387c715dcSDouglas Gilbert 	bool check_prot;
3114c2248fc9SDouglas Gilbert 	u32 num;
3115c2248fc9SDouglas Gilbert 	u32 ei_lba;
311619789100SFUJITA Tomonori 	int ret;
311787c715dcSDouglas Gilbert 	u64 lba;
3118b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
311987c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
312087c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
312119789100SFUJITA Tomonori 
3122c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3123c2248fc9SDouglas Gilbert 	case READ_16:
3124c2248fc9SDouglas Gilbert 		ei_lba = 0;
3125c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3126c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3127c2248fc9SDouglas Gilbert 		check_prot = true;
3128c2248fc9SDouglas Gilbert 		break;
3129c2248fc9SDouglas Gilbert 	case READ_10:
3130c2248fc9SDouglas Gilbert 		ei_lba = 0;
3131c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3132c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3133c2248fc9SDouglas Gilbert 		check_prot = true;
3134c2248fc9SDouglas Gilbert 		break;
3135c2248fc9SDouglas Gilbert 	case READ_6:
3136c2248fc9SDouglas Gilbert 		ei_lba = 0;
3137c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3138c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3139c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3140c2248fc9SDouglas Gilbert 		check_prot = true;
3141c2248fc9SDouglas Gilbert 		break;
3142c2248fc9SDouglas Gilbert 	case READ_12:
3143c2248fc9SDouglas Gilbert 		ei_lba = 0;
3144c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3145c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3146c2248fc9SDouglas Gilbert 		check_prot = true;
3147c2248fc9SDouglas Gilbert 		break;
3148c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3149c2248fc9SDouglas Gilbert 		ei_lba = 0;
3150c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3151c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3152c2248fc9SDouglas Gilbert 		check_prot = false;
3153c2248fc9SDouglas Gilbert 		break;
3154c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3155c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3156c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3157c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3158c2248fc9SDouglas Gilbert 		check_prot = false;
3159c2248fc9SDouglas Gilbert 		break;
3160c2248fc9SDouglas Gilbert 	}
3161f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31628475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3163c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3164c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3165c2248fc9SDouglas Gilbert 			return check_condition_result;
3166c2248fc9SDouglas Gilbert 		}
31678475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31688475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3169c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3170c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3171c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3172c2248fc9SDouglas Gilbert 	}
31733a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
31743a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3175c2248fc9SDouglas Gilbert 		num /= 2;
31763a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3177c2248fc9SDouglas Gilbert 	}
3178c2248fc9SDouglas Gilbert 
31799447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31809447b6ceSMartin K. Petersen 	if (ret)
31819447b6ceSMartin K. Petersen 		return ret;
3182f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3183d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3184d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3185c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3186c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3187c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3188c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3189c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
319032f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
319132f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3192c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3193c65b1445SDouglas Gilbert 		}
3194c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
31951da177e4SLinus Torvalds 		return check_condition_result;
31961da177e4SLinus Torvalds 	}
3197c6a44287SMartin K. Petersen 
319867da413fSDouglas Gilbert 	read_lock(macc_lckp);
31996c78cc06SAkinobu Mita 
3200c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3201f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3202c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
3203c6a44287SMartin K. Petersen 
3204c6a44287SMartin K. Petersen 		if (prot_ret) {
320567da413fSDouglas Gilbert 			read_unlock(macc_lckp);
3206c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
3207c6a44287SMartin K. Petersen 			return illegal_condition_result;
3208c6a44287SMartin K. Petersen 		}
3209c6a44287SMartin K. Petersen 	}
3210c6a44287SMartin K. Petersen 
321187c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
321267da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3213f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3214a4517511SAkinobu Mita 		return DID_ERROR << 16;
3215a4517511SAkinobu Mita 
321642d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3217a4517511SAkinobu Mita 
32183a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
32193a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
32203a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
32213a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
32223a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3223c2248fc9SDouglas Gilbert 			return check_condition_result;
32243a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3225c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3226c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
32273a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3228c2248fc9SDouglas Gilbert 			return illegal_condition_result;
32293a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3230c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
32313a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3232c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3233c2248fc9SDouglas Gilbert 		}
3234c2248fc9SDouglas Gilbert 	}
3235a4517511SAkinobu Mita 	return 0;
32361da177e4SLinus Torvalds }
32371da177e4SLinus Torvalds 
323858a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
3239c6a44287SMartin K. Petersen {
3240cbf67842SDouglas Gilbert 	int i, j, n;
3241c6a44287SMartin K. Petersen 
3242cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
3243c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
3244cbf67842SDouglas Gilbert 		char b[128];
3245c6a44287SMartin K. Petersen 
3246cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
3247c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
3248c6a44287SMartin K. Petersen 
3249cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
3250cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3251cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
3252cbf67842SDouglas Gilbert 			else
3253cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3254cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
3255cbf67842SDouglas Gilbert 		}
3256cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
3257c6a44287SMartin K. Petersen 	}
3258c6a44287SMartin K. Petersen }
3259c6a44287SMartin K. Petersen 
3260c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3261395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3262c6a44287SMartin K. Petersen {
3263be4e11beSAkinobu Mita 	int ret;
32646ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3265be4e11beSAkinobu Mita 	void *daddr;
326665f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3267c6a44287SMartin K. Petersen 	int ppage_offset;
3268be4e11beSAkinobu Mita 	int dpage_offset;
3269be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3270be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3271c6a44287SMartin K. Petersen 
3272c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3273c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3274c6a44287SMartin K. Petersen 
3275be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3276be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3277be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3278be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3279be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3280c6a44287SMartin K. Petersen 
3281be4e11beSAkinobu Mita 	/* For each protection page */
3282be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3283be4e11beSAkinobu Mita 		dpage_offset = 0;
3284be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3285be4e11beSAkinobu Mita 			ret = 0x01;
3286be4e11beSAkinobu Mita 			goto out;
3287c6a44287SMartin K. Petersen 		}
3288c6a44287SMartin K. Petersen 
3289be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32906ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3291be4e11beSAkinobu Mita 			/* If we're at the end of the current
3292be4e11beSAkinobu Mita 			 * data page advance to the next one
3293be4e11beSAkinobu Mita 			 */
3294be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3295be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3296be4e11beSAkinobu Mita 					ret = 0x01;
3297be4e11beSAkinobu Mita 					goto out;
3298be4e11beSAkinobu Mita 				}
3299be4e11beSAkinobu Mita 				dpage_offset = 0;
3300be4e11beSAkinobu Mita 			}
3301c6a44287SMartin K. Petersen 
3302be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3303be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3304be4e11beSAkinobu Mita 
3305be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
3306beb40ea4SAkinobu Mita 			if (ret) {
3307773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
3308395cef03SMartin K. Petersen 				goto out;
3309395cef03SMartin K. Petersen 			}
3310395cef03SMartin K. Petersen 
3311c6a44287SMartin K. Petersen 			sector++;
3312395cef03SMartin K. Petersen 			ei_lba++;
3313773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3314c6a44287SMartin K. Petersen 		}
3315be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3316be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3317c6a44287SMartin K. Petersen 	}
3318be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3319c6a44287SMartin K. Petersen 
332065f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3321c6a44287SMartin K. Petersen 	dix_writes++;
3322c6a44287SMartin K. Petersen 
3323c6a44287SMartin K. Petersen 	return 0;
3324c6a44287SMartin K. Petersen 
3325c6a44287SMartin K. Petersen out:
3326c6a44287SMartin K. Petersen 	dif_errors++;
3327be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3328be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3329c6a44287SMartin K. Petersen 	return ret;
3330c6a44287SMartin K. Petersen }
3331c6a44287SMartin K. Petersen 
3332b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3333b90ebc3dSAkinobu Mita {
3334773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3335773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3336773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3337b90ebc3dSAkinobu Mita 	return lba;
3338b90ebc3dSAkinobu Mita }
3339b90ebc3dSAkinobu Mita 
3340b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3341b90ebc3dSAkinobu Mita {
3342773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3343a027b5b9SAkinobu Mita 
3344773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3345773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3346a027b5b9SAkinobu Mita 	return lba;
3347a027b5b9SAkinobu Mita }
3348a027b5b9SAkinobu Mita 
334987c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
335087c715dcSDouglas Gilbert 			      unsigned int *num)
335144d92694SMartin K. Petersen {
3352b90ebc3dSAkinobu Mita 	sector_t end;
3353b90ebc3dSAkinobu Mita 	unsigned int mapped;
3354b90ebc3dSAkinobu Mita 	unsigned long index;
3355b90ebc3dSAkinobu Mita 	unsigned long next;
335644d92694SMartin K. Petersen 
3357b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
335887c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
335944d92694SMartin K. Petersen 
336044d92694SMartin K. Petersen 	if (mapped)
336187c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
336244d92694SMartin K. Petersen 	else
336387c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
336444d92694SMartin K. Petersen 
3365b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
336644d92694SMartin K. Petersen 	*num = end - lba;
336744d92694SMartin K. Petersen 	return mapped;
336844d92694SMartin K. Petersen }
336944d92694SMartin K. Petersen 
337087c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
337187c715dcSDouglas Gilbert 		       unsigned int len)
337244d92694SMartin K. Petersen {
337344d92694SMartin K. Petersen 	sector_t end = lba + len;
337444d92694SMartin K. Petersen 
337544d92694SMartin K. Petersen 	while (lba < end) {
3376b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
337744d92694SMartin K. Petersen 
3378b90ebc3dSAkinobu Mita 		if (index < map_size)
337987c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
338044d92694SMartin K. Petersen 
3381b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
338244d92694SMartin K. Petersen 	}
338344d92694SMartin K. Petersen }
338444d92694SMartin K. Petersen 
338587c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
338687c715dcSDouglas Gilbert 			 unsigned int len)
338744d92694SMartin K. Petersen {
338844d92694SMartin K. Petersen 	sector_t end = lba + len;
338987c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
339044d92694SMartin K. Petersen 
339144d92694SMartin K. Petersen 	while (lba < end) {
3392b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
339344d92694SMartin K. Petersen 
3394b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3395773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3396b90ebc3dSAkinobu Mita 		    index < map_size) {
339787c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3398760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
339987c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3400760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3401773642d9SDouglas Gilbert 				       sdebug_sector_size *
3402773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3403be1dd78dSEric Sandeen 			}
340487c715dcSDouglas Gilbert 			if (sip->dif_storep) {
340587c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
340687c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3407773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3408e9926b43SAkinobu Mita 			}
3409b90ebc3dSAkinobu Mita 		}
3410b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
341144d92694SMartin K. Petersen 	}
341244d92694SMartin K. Petersen }
341344d92694SMartin K. Petersen 
3414fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34151da177e4SLinus Torvalds {
341687c715dcSDouglas Gilbert 	bool check_prot;
3417c2248fc9SDouglas Gilbert 	u32 num;
3418c2248fc9SDouglas Gilbert 	u32 ei_lba;
341919789100SFUJITA Tomonori 	int ret;
342087c715dcSDouglas Gilbert 	u64 lba;
3421b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3422b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
342387c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
34241da177e4SLinus Torvalds 
3425c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3426c2248fc9SDouglas Gilbert 	case WRITE_16:
3427c2248fc9SDouglas Gilbert 		ei_lba = 0;
3428c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3429c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3430c2248fc9SDouglas Gilbert 		check_prot = true;
3431c2248fc9SDouglas Gilbert 		break;
3432c2248fc9SDouglas Gilbert 	case WRITE_10:
3433c2248fc9SDouglas Gilbert 		ei_lba = 0;
3434c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3435c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3436c2248fc9SDouglas Gilbert 		check_prot = true;
3437c2248fc9SDouglas Gilbert 		break;
3438c2248fc9SDouglas Gilbert 	case WRITE_6:
3439c2248fc9SDouglas Gilbert 		ei_lba = 0;
3440c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3441c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3442c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3443c2248fc9SDouglas Gilbert 		check_prot = true;
3444c2248fc9SDouglas Gilbert 		break;
3445c2248fc9SDouglas Gilbert 	case WRITE_12:
3446c2248fc9SDouglas Gilbert 		ei_lba = 0;
3447c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3448c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3449c2248fc9SDouglas Gilbert 		check_prot = true;
3450c2248fc9SDouglas Gilbert 		break;
3451c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3452c2248fc9SDouglas Gilbert 		ei_lba = 0;
3453c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3454c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3455c2248fc9SDouglas Gilbert 		check_prot = false;
3456c2248fc9SDouglas Gilbert 		break;
3457c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3458c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3459c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3460c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3461c2248fc9SDouglas Gilbert 		check_prot = false;
3462c2248fc9SDouglas Gilbert 		break;
3463c2248fc9SDouglas Gilbert 	}
3464f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34658475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3466c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3467c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3468c2248fc9SDouglas Gilbert 			return check_condition_result;
3469c2248fc9SDouglas Gilbert 		}
34708475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34718475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3472c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3473c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3474c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3475c2248fc9SDouglas Gilbert 	}
3476f0d1cf93SDouglas Gilbert 
347767da413fSDouglas Gilbert 	write_lock(macc_lckp);
3478f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3479f0d1cf93SDouglas Gilbert 	if (ret) {
3480f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3481f0d1cf93SDouglas Gilbert 		return ret;
3482f0d1cf93SDouglas Gilbert 	}
34836c78cc06SAkinobu Mita 
3484c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3485f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3486c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3487c6a44287SMartin K. Petersen 
3488c6a44287SMartin K. Petersen 		if (prot_ret) {
348967da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3490c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3491c6a44287SMartin K. Petersen 			return illegal_condition_result;
3492c6a44287SMartin K. Petersen 		}
3493c6a44287SMartin K. Petersen 	}
3494c6a44287SMartin K. Petersen 
349587c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3496f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
349787c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3498f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3499f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3500f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
350167da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3502f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3503773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3504c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3505c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3506c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3507cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3508773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
350944d92694SMartin K. Petersen 
35103a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
35113a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
35123a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
35133a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
35143a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3515c2248fc9SDouglas Gilbert 			return check_condition_result;
35163a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3517c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3518c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
35193a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3520c2248fc9SDouglas Gilbert 			return illegal_condition_result;
35213a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3522c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
35233a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3524c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3525c2248fc9SDouglas Gilbert 		}
3526c2248fc9SDouglas Gilbert 	}
35271da177e4SLinus Torvalds 	return 0;
35281da177e4SLinus Torvalds }
35291da177e4SLinus Torvalds 
3530481b5e5cSDouglas Gilbert /*
3531481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3532481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3533481b5e5cSDouglas Gilbert  */
3534481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3535481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3536481b5e5cSDouglas Gilbert {
3537481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3538481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3539481b5e5cSDouglas Gilbert 	u8 *up;
3540b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3541b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
3542481b5e5cSDouglas Gilbert 	u8 wrprotect;
3543481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3544481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3545481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3546481b5e5cSDouglas Gilbert 	u32 ei_lba;
3547481b5e5cSDouglas Gilbert 	u64 lba;
3548481b5e5cSDouglas Gilbert 	int ret, res;
3549481b5e5cSDouglas Gilbert 	bool is_16;
3550481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3551481b5e5cSDouglas Gilbert 
3552481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3553481b5e5cSDouglas Gilbert 		is_16 = false;
3554481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3555481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3556481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3557481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3558481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3559481b5e5cSDouglas Gilbert 		is_16 = true;
3560481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3561481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3562481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3563481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3564481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3565481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3566481b5e5cSDouglas Gilbert 			    wrprotect) {
3567481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3568481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3569481b5e5cSDouglas Gilbert 			}
3570481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3571481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3572481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3573481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3574481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3575481b5e5cSDouglas Gilbert 		}
3576481b5e5cSDouglas Gilbert 	}
3577481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3578481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3579481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3580481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3581481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3582481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3583481b5e5cSDouglas Gilbert 				my_name, __func__);
3584481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3585481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3586481b5e5cSDouglas Gilbert 	}
3587481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3588481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3589481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3590481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3591481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3592481b5e5cSDouglas Gilbert 				my_name, __func__);
3593481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3594481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3595481b5e5cSDouglas Gilbert 	}
3596481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3597481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3598481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3599481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3600481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3601481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3602481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3603481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3604481b5e5cSDouglas Gilbert 	if (res == -1) {
3605481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3606481b5e5cSDouglas Gilbert 		goto err_out;
3607481b5e5cSDouglas Gilbert 	}
3608481b5e5cSDouglas Gilbert 
360967da413fSDouglas Gilbert 	write_lock(macc_lckp);
3610481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3611481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3612481b5e5cSDouglas Gilbert 	cum_lb = 0;
3613481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3614481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3615481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3616481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3617481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3618481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3619481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3620481b5e5cSDouglas Gilbert 		if (num == 0)
3621481b5e5cSDouglas Gilbert 			continue;
36229447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3623481b5e5cSDouglas Gilbert 		if (ret)
3624481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3625481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3626481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3627481b5e5cSDouglas Gilbert 
3628481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3629481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3630481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3631481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3632481b5e5cSDouglas Gilbert 				    my_name, __func__);
3633481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3634481b5e5cSDouglas Gilbert 					0);
3635481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3636481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3637481b5e5cSDouglas Gilbert 		}
3638481b5e5cSDouglas Gilbert 
3639481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3640481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3641481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3642481b5e5cSDouglas Gilbert 							 ei_lba);
3643481b5e5cSDouglas Gilbert 
3644481b5e5cSDouglas Gilbert 			if (prot_ret) {
3645481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3646481b5e5cSDouglas Gilbert 						prot_ret);
3647481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3648481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3649481b5e5cSDouglas Gilbert 			}
3650481b5e5cSDouglas Gilbert 		}
3651481b5e5cSDouglas Gilbert 
365287c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3653f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3654f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3655f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3656481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
365787c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3658481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3659481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3660481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3661481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3662481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3663481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3664481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3665481b5e5cSDouglas Gilbert 
36663a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36673a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
36683a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36693a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36703a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
36713a90a63dSDouglas Gilbert 				ret = check_condition_result;
3672481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36733a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3674481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
36753a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
36763a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3677481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3678481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36793a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
36803a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
36813a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3682481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3683481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3684481b5e5cSDouglas Gilbert 			}
3685481b5e5cSDouglas Gilbert 		}
3686481b5e5cSDouglas Gilbert 		sg_off += num_by;
3687481b5e5cSDouglas Gilbert 		cum_lb += num;
3688481b5e5cSDouglas Gilbert 	}
3689481b5e5cSDouglas Gilbert 	ret = 0;
3690481b5e5cSDouglas Gilbert err_out_unlock:
369167da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3692481b5e5cSDouglas Gilbert err_out:
3693481b5e5cSDouglas Gilbert 	kfree(lrdp);
3694481b5e5cSDouglas Gilbert 	return ret;
3695481b5e5cSDouglas Gilbert }
3696481b5e5cSDouglas Gilbert 
3697fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3698fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
369944d92694SMartin K. Petersen {
3700f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3701f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
370244d92694SMartin K. Petersen 	unsigned long long i;
370340d07b52SDouglas Gilbert 	u64 block, lbaa;
370487c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
370587c715dcSDouglas Gilbert 	int ret;
370687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3707b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
3708b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
370940d07b52SDouglas Gilbert 	u8 *fs1p;
371087c715dcSDouglas Gilbert 	u8 *fsp;
371144d92694SMartin K. Petersen 
371267da413fSDouglas Gilbert 	write_lock(macc_lckp);
371344d92694SMartin K. Petersen 
3714f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3715f0d1cf93SDouglas Gilbert 	if (ret) {
3716f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3717f0d1cf93SDouglas Gilbert 		return ret;
3718f0d1cf93SDouglas Gilbert 	}
3719f0d1cf93SDouglas Gilbert 
37209ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
372187c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
372244d92694SMartin K. Petersen 		goto out;
372344d92694SMartin K. Petersen 	}
372440d07b52SDouglas Gilbert 	lbaa = lba;
372540d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3726c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
372787c715dcSDouglas Gilbert 	fsp = sip->storep;
372887c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3729c2248fc9SDouglas Gilbert 	if (ndob) {
373040d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3731c2248fc9SDouglas Gilbert 		ret = 0;
3732c2248fc9SDouglas Gilbert 	} else
373340d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
373444d92694SMartin K. Petersen 
373544d92694SMartin K. Petersen 	if (-1 == ret) {
373667da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3737773642d9SDouglas Gilbert 		return DID_ERROR << 16;
373840d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3739c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3740e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
374140d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
374244d92694SMartin K. Petersen 
374344d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
374440d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
374540d07b52SDouglas Gilbert 		lbaa = lba + i;
374640d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
374787c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
374840d07b52SDouglas Gilbert 	}
37499ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
375087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3751f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3752f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3753f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
375444d92694SMartin K. Petersen out:
375567da413fSDouglas Gilbert 	write_unlock(macc_lckp);
375644d92694SMartin K. Petersen 
375744d92694SMartin K. Petersen 	return 0;
375844d92694SMartin K. Petersen }
375944d92694SMartin K. Petersen 
3760fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3761fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3762c2248fc9SDouglas Gilbert {
3763c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3764c2248fc9SDouglas Gilbert 	u32 lba;
3765c2248fc9SDouglas Gilbert 	u16 num;
3766c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3767c2248fc9SDouglas Gilbert 	bool unmap = false;
3768c2248fc9SDouglas Gilbert 
3769c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3770773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3771c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3772c2248fc9SDouglas Gilbert 			return check_condition_result;
3773c2248fc9SDouglas Gilbert 		} else
3774c2248fc9SDouglas Gilbert 			unmap = true;
3775c2248fc9SDouglas Gilbert 	}
3776c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3777c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3778773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3779c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3780c2248fc9SDouglas Gilbert 		return check_condition_result;
3781c2248fc9SDouglas Gilbert 	}
3782c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3783c2248fc9SDouglas Gilbert }
3784c2248fc9SDouglas Gilbert 
3785fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3786fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3787c2248fc9SDouglas Gilbert {
3788c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3789c2248fc9SDouglas Gilbert 	u64 lba;
3790c2248fc9SDouglas Gilbert 	u32 num;
3791c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3792c2248fc9SDouglas Gilbert 	bool unmap = false;
3793c2248fc9SDouglas Gilbert 	bool ndob = false;
3794c2248fc9SDouglas Gilbert 
3795c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3796773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3797c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3798c2248fc9SDouglas Gilbert 			return check_condition_result;
3799c2248fc9SDouglas Gilbert 		} else
3800c2248fc9SDouglas Gilbert 			unmap = true;
3801c2248fc9SDouglas Gilbert 	}
3802c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3803c2248fc9SDouglas Gilbert 		ndob = true;
3804c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3805c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3806773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3807c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3808c2248fc9SDouglas Gilbert 		return check_condition_result;
3809c2248fc9SDouglas Gilbert 	}
3810c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3811c2248fc9SDouglas Gilbert }
3812c2248fc9SDouglas Gilbert 
3813acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3814acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3815acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3816fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3817fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3818acafd0b9SEwan D. Milne {
3819acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3820acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3821acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3822acafd0b9SEwan D. Milne 	u8 mode;
3823acafd0b9SEwan D. Milne 
3824acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3825acafd0b9SEwan D. Milne 	switch (mode) {
3826acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3827acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3828acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3829acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3830acafd0b9SEwan D. Milne 		break;
3831acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3832acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3833acafd0b9SEwan D. Milne 		break;
3834acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3835acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3836acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3837acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3838acafd0b9SEwan D. Milne 				    dev_list)
3839acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3840acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3841acafd0b9SEwan D. Milne 				if (devip != dp)
3842acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3843acafd0b9SEwan D. Milne 						dp->uas_bm);
3844acafd0b9SEwan D. Milne 			}
3845acafd0b9SEwan D. Milne 		break;
3846acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3847acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3848acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3849acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3850acafd0b9SEwan D. Milne 				    dev_list)
3851acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3852acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3853acafd0b9SEwan D. Milne 					dp->uas_bm);
3854acafd0b9SEwan D. Milne 		break;
3855acafd0b9SEwan D. Milne 	default:
3856acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3857acafd0b9SEwan D. Milne 		break;
3858acafd0b9SEwan D. Milne 	}
3859acafd0b9SEwan D. Milne 	return 0;
3860acafd0b9SEwan D. Milne }
3861acafd0b9SEwan D. Milne 
3862fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3863fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
386438d5c833SDouglas Gilbert {
386538d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
386638d5c833SDouglas Gilbert 	u8 *arr;
3867b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3868b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
386938d5c833SDouglas Gilbert 	u64 lba;
387038d5c833SDouglas Gilbert 	u32 dnum;
3871773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
387238d5c833SDouglas Gilbert 	u8 num;
387338d5c833SDouglas Gilbert 	int ret;
3874d467d31fSDouglas Gilbert 	int retval = 0;
387538d5c833SDouglas Gilbert 
3876d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
387738d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
387838d5c833SDouglas Gilbert 	if (0 == num)
387938d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38808475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
388138d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
388238d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
388338d5c833SDouglas Gilbert 		return check_condition_result;
388438d5c833SDouglas Gilbert 	}
38858475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
38868475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
388738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
388838d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
388938d5c833SDouglas Gilbert 			    "to DIF device\n");
38909447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
38919447b6ceSMartin K. Petersen 	if (ret)
38929447b6ceSMartin K. Petersen 		return ret;
3893d467d31fSDouglas Gilbert 	dnum = 2 * num;
38946396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3895d467d31fSDouglas Gilbert 	if (NULL == arr) {
3896d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3897d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3898d467d31fSDouglas Gilbert 		return check_condition_result;
3899d467d31fSDouglas Gilbert 	}
390038d5c833SDouglas Gilbert 
390167da413fSDouglas Gilbert 	write_lock(macc_lckp);
390238d5c833SDouglas Gilbert 
390387c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
390438d5c833SDouglas Gilbert 	if (ret == -1) {
3905d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3906d467d31fSDouglas Gilbert 		goto cleanup;
3907773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
390838d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
390938d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
391038d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3911c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
391238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3913d467d31fSDouglas Gilbert 		retval = check_condition_result;
3914d467d31fSDouglas Gilbert 		goto cleanup;
391538d5c833SDouglas Gilbert 	}
391638d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
391787c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3918d467d31fSDouglas Gilbert cleanup:
391967da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3920d467d31fSDouglas Gilbert 	kfree(arr);
3921d467d31fSDouglas Gilbert 	return retval;
392238d5c833SDouglas Gilbert }
392338d5c833SDouglas Gilbert 
392444d92694SMartin K. Petersen struct unmap_block_desc {
392544d92694SMartin K. Petersen 	__be64	lba;
392644d92694SMartin K. Petersen 	__be32	blocks;
392744d92694SMartin K. Petersen 	__be32	__reserved;
392844d92694SMartin K. Petersen };
392944d92694SMartin K. Petersen 
3930fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
393144d92694SMartin K. Petersen {
393244d92694SMartin K. Petersen 	unsigned char *buf;
393344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
3934b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3935b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
393644d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
393744d92694SMartin K. Petersen 	int ret;
393844d92694SMartin K. Petersen 
3939c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3940c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3941c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3942c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
394344d92694SMartin K. Petersen 
394444d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3945773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3946c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
394744d92694SMartin K. Petersen 		return check_condition_result;
3948c2248fc9SDouglas Gilbert 	}
394944d92694SMartin K. Petersen 
3950b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3951c2248fc9SDouglas Gilbert 	if (!buf) {
3952c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3953c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3954c2248fc9SDouglas Gilbert 		return check_condition_result;
3955c2248fc9SDouglas Gilbert 	}
3956c2248fc9SDouglas Gilbert 
3957c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
395844d92694SMartin K. Petersen 
395944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
396044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
396144d92694SMartin K. Petersen 
396244d92694SMartin K. Petersen 	desc = (void *)&buf[8];
396344d92694SMartin K. Petersen 
396467da413fSDouglas Gilbert 	write_lock(macc_lckp);
39656c78cc06SAkinobu Mita 
396644d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
396744d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
396844d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
396944d92694SMartin K. Petersen 
39709447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
397144d92694SMartin K. Petersen 		if (ret)
397244d92694SMartin K. Petersen 			goto out;
397344d92694SMartin K. Petersen 
397487c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
397544d92694SMartin K. Petersen 	}
397644d92694SMartin K. Petersen 
397744d92694SMartin K. Petersen 	ret = 0;
397844d92694SMartin K. Petersen 
397944d92694SMartin K. Petersen out:
398067da413fSDouglas Gilbert 	write_unlock(macc_lckp);
398144d92694SMartin K. Petersen 	kfree(buf);
398244d92694SMartin K. Petersen 
398344d92694SMartin K. Petersen 	return ret;
398444d92694SMartin K. Petersen }
398544d92694SMartin K. Petersen 
398644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
398744d92694SMartin K. Petersen 
3988fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3989fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
399044d92694SMartin K. Petersen {
3991c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3992c2248fc9SDouglas Gilbert 	u64 lba;
3993c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
399444d92694SMartin K. Petersen 	int ret;
399587c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
399644d92694SMartin K. Petersen 
3997c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3998c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
399944d92694SMartin K. Petersen 
400044d92694SMartin K. Petersen 	if (alloc_len < 24)
400144d92694SMartin K. Petersen 		return 0;
400244d92694SMartin K. Petersen 
40039447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
400444d92694SMartin K. Petersen 	if (ret)
400544d92694SMartin K. Petersen 		return ret;
400644d92694SMartin K. Petersen 
4007b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4008b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4009b6ff8ca7SDouglas Gilbert 
401087c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4011b6ff8ca7SDouglas Gilbert 	} else {
4012c2248fc9SDouglas Gilbert 		mapped = 1;
4013c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4014c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4015c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4016c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4017c2248fc9SDouglas Gilbert 		else
4018c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4019c2248fc9SDouglas Gilbert 	}
402044d92694SMartin K. Petersen 
402144d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4022c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4023c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4024c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4025c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
402644d92694SMartin K. Petersen 
4027c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
402844d92694SMartin K. Petersen }
402944d92694SMartin K. Petersen 
403080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
403180c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
403280c49563SDouglas Gilbert {
40334f2c8bf6SDouglas Gilbert 	int res = 0;
403480c49563SDouglas Gilbert 	u64 lba;
403580c49563SDouglas Gilbert 	u32 num_blocks;
403680c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
403780c49563SDouglas Gilbert 
403880c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
403980c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
404080c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
404180c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
404280c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
404380c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
404480c49563SDouglas Gilbert 	}
404580c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
404680c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
404780c49563SDouglas Gilbert 		return check_condition_result;
404880c49563SDouglas Gilbert 	}
4049fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
40504f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40514f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40524f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40534f2c8bf6SDouglas Gilbert 	return res;
405480c49563SDouglas Gilbert }
405580c49563SDouglas Gilbert 
4056ed9f3e25SDouglas Gilbert /*
4057ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4058ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4059ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4060ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4061ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4062ed9f3e25SDouglas Gilbert  */
4063ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4064ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4065ed9f3e25SDouglas Gilbert {
4066ed9f3e25SDouglas Gilbert 	int res = 0;
4067ed9f3e25SDouglas Gilbert 	u64 lba;
4068ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4069ed9f3e25SDouglas Gilbert 	u32 nblks;
4070ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4071b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4072b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4073b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4074ed9f3e25SDouglas Gilbert 
4075ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4076ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4077ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4078ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4079ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4080ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4081ed9f3e25SDouglas Gilbert 	}
4082ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4083ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4084ed9f3e25SDouglas Gilbert 		return check_condition_result;
4085ed9f3e25SDouglas Gilbert 	}
4086ed9f3e25SDouglas Gilbert 	if (!fsp)
4087ed9f3e25SDouglas Gilbert 		goto fini;
4088ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4089ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4090ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4091ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4092ed9f3e25SDouglas Gilbert 
4093ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4094ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4095ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4096ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4097ed9f3e25SDouglas Gilbert 	if (rest)
4098ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4099ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4100ed9f3e25SDouglas Gilbert fini:
4101ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4102ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4103ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4104ed9f3e25SDouglas Gilbert }
4105ed9f3e25SDouglas Gilbert 
4106fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4107fb0cc8d1SDouglas Gilbert 
41088d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
41098d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
41108d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
41118d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41128d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
41138d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
41148d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
41158d039e22SDouglas Gilbert  */
41161da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
41171da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
41181da177e4SLinus Torvalds {
411901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
41208d039e22SDouglas Gilbert 	unsigned int alloc_len;
41218d039e22SDouglas Gilbert 	unsigned char select_report;
41228d039e22SDouglas Gilbert 	u64 lun;
41238d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4124fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41258d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41268d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
41278d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
41288d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4129fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4130fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4131fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41321da177e4SLinus Torvalds 
413319c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41348d039e22SDouglas Gilbert 
41358d039e22SDouglas Gilbert 	select_report = cmd[2];
41368d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41378d039e22SDouglas Gilbert 
41388d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41398d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41408d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41411da177e4SLinus Torvalds 		return check_condition_result;
41421da177e4SLinus Torvalds 	}
41438d039e22SDouglas Gilbert 
41448d039e22SDouglas Gilbert 	switch (select_report) {
41458d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4146773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41478d039e22SDouglas Gilbert 		wlun_cnt = 0;
41488d039e22SDouglas Gilbert 		break;
41498d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4150c65b1445SDouglas Gilbert 		lun_cnt = 0;
41518d039e22SDouglas Gilbert 		wlun_cnt = 1;
41528d039e22SDouglas Gilbert 		break;
41538d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41548d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41558d039e22SDouglas Gilbert 		wlun_cnt = 1;
41568d039e22SDouglas Gilbert 		break;
41578d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41588d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41598d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41608d039e22SDouglas Gilbert 	default:
41618d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41628d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41638d039e22SDouglas Gilbert 		return check_condition_result;
41648d039e22SDouglas Gilbert 	}
41658d039e22SDouglas Gilbert 
41668d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4167c65b1445SDouglas Gilbert 		--lun_cnt;
41688d039e22SDouglas Gilbert 
41698d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4170fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4171fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41728d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41738d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41748d039e22SDouglas Gilbert 
4175fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41768d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4177fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4178fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4179fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4180fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4181fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4182fb0cc8d1SDouglas Gilbert 			++lun_p;
4183fb0cc8d1SDouglas Gilbert 			j = 1;
4184fb0cc8d1SDouglas Gilbert 		}
4185fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4186fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4187fb0cc8d1SDouglas Gilbert 				break;
4188fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4189ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4190ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4191fb0cc8d1SDouglas Gilbert 		}
4192fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4193fb0cc8d1SDouglas Gilbert 			break;
4194fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4195fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4196fb0cc8d1SDouglas Gilbert 		if (res)
4197fb0cc8d1SDouglas Gilbert 			return res;
4198fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4199fb0cc8d1SDouglas Gilbert 	}
4200fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4201fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4202fb0cc8d1SDouglas Gilbert 		++j;
4203fb0cc8d1SDouglas Gilbert 	}
4204fb0cc8d1SDouglas Gilbert 	if (j > 0)
4205fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
42068d039e22SDouglas Gilbert 	return res;
42071da177e4SLinus Torvalds }
42081da177e4SLinus Torvalds 
4209c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4210c3e2fe92SDouglas Gilbert {
4211c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4212c3e2fe92SDouglas Gilbert 	u8 bytchk;
4213c3e2fe92SDouglas Gilbert 	int ret, j;
4214c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4215c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4216c3e2fe92SDouglas Gilbert 	u64 lba;
4217c3e2fe92SDouglas Gilbert 	u8 *arr;
4218c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4219b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4220b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4221c3e2fe92SDouglas Gilbert 
4222c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4223c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4224c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4225c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4226c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4227c3e2fe92SDouglas Gilbert 		return check_condition_result;
4228c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4229c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4230c3e2fe92SDouglas Gilbert 	}
4231c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4232c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4233c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4234c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4235c3e2fe92SDouglas Gilbert 		break;
4236c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4237c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4238c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4239c3e2fe92SDouglas Gilbert 		break;
4240c3e2fe92SDouglas Gilbert 	default:
4241c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4242c3e2fe92SDouglas Gilbert 		return check_condition_result;
4243c3e2fe92SDouglas Gilbert 	}
4244c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4245c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4246c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4247c3e2fe92SDouglas Gilbert 	if (ret)
4248c3e2fe92SDouglas Gilbert 		return ret;
4249c3e2fe92SDouglas Gilbert 
4250c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4251c3e2fe92SDouglas Gilbert 	if (!arr) {
4252c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4253c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4254c3e2fe92SDouglas Gilbert 		return check_condition_result;
4255c3e2fe92SDouglas Gilbert 	}
4256c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
425767da413fSDouglas Gilbert 	read_lock(macc_lckp);
4258c3e2fe92SDouglas Gilbert 
4259c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4260c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4261c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4262c3e2fe92SDouglas Gilbert 		goto cleanup;
4263c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4264c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4265c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4266c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4267c3e2fe92SDouglas Gilbert 	}
4268c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4269c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4270c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4271c3e2fe92SDouglas Gilbert 	}
4272c3e2fe92SDouglas Gilbert 	ret = 0;
4273c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4274c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4275c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4276c3e2fe92SDouglas Gilbert 		goto cleanup;
4277c3e2fe92SDouglas Gilbert 	}
4278c3e2fe92SDouglas Gilbert cleanup:
427967da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4280c3e2fe92SDouglas Gilbert 	kfree(arr);
4281c3e2fe92SDouglas Gilbert 	return ret;
4282c3e2fe92SDouglas Gilbert }
4283c3e2fe92SDouglas Gilbert 
4284f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4285f0d1cf93SDouglas Gilbert 
4286f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4287f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4288f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4289f0d1cf93SDouglas Gilbert {
4290f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4291f0d1cf93SDouglas Gilbert 	int ret = 0;
4292f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4293f0d1cf93SDouglas Gilbert 	bool partial;
4294f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4295f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4296f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4297f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4298b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4299f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4300f0d1cf93SDouglas Gilbert 
4301f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4302f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4303f0d1cf93SDouglas Gilbert 		return check_condition_result;
4304f0d1cf93SDouglas Gilbert 	}
4305f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4306f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4307f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4308f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4309f0d1cf93SDouglas Gilbert 
4310f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4311f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4312f0d1cf93SDouglas Gilbert 		return check_condition_result;
4313f0d1cf93SDouglas Gilbert 	}
4314f0d1cf93SDouglas Gilbert 
4315108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4316f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4317f0d1cf93SDouglas Gilbert 			    max_zones);
4318f0d1cf93SDouglas Gilbert 
4319f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4320f0d1cf93SDouglas Gilbert 	if (!arr) {
4321f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4322f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4323f0d1cf93SDouglas Gilbert 		return check_condition_result;
4324f0d1cf93SDouglas Gilbert 	}
4325f0d1cf93SDouglas Gilbert 
4326f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4327f0d1cf93SDouglas Gilbert 
4328f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4329f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4330f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4331f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4332f0d1cf93SDouglas Gilbert 			break;
4333f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4334f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4335f0d1cf93SDouglas Gilbert 		case 0x00:
4336f0d1cf93SDouglas Gilbert 			/* All zones */
4337f0d1cf93SDouglas Gilbert 			break;
4338f0d1cf93SDouglas Gilbert 		case 0x01:
4339f0d1cf93SDouglas Gilbert 			/* Empty zones */
4340f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4341f0d1cf93SDouglas Gilbert 				continue;
4342f0d1cf93SDouglas Gilbert 			break;
4343f0d1cf93SDouglas Gilbert 		case 0x02:
4344f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4345f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4346f0d1cf93SDouglas Gilbert 				continue;
4347f0d1cf93SDouglas Gilbert 			break;
4348f0d1cf93SDouglas Gilbert 		case 0x03:
4349f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4350f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4351f0d1cf93SDouglas Gilbert 				continue;
4352f0d1cf93SDouglas Gilbert 			break;
4353f0d1cf93SDouglas Gilbert 		case 0x04:
4354f0d1cf93SDouglas Gilbert 			/* Closed zones */
4355f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4356f0d1cf93SDouglas Gilbert 				continue;
4357f0d1cf93SDouglas Gilbert 			break;
4358f0d1cf93SDouglas Gilbert 		case 0x05:
4359f0d1cf93SDouglas Gilbert 			/* Full zones */
4360f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4361f0d1cf93SDouglas Gilbert 				continue;
4362f0d1cf93SDouglas Gilbert 			break;
4363f0d1cf93SDouglas Gilbert 		case 0x06:
4364f0d1cf93SDouglas Gilbert 		case 0x07:
4365f0d1cf93SDouglas Gilbert 		case 0x10:
4366f0d1cf93SDouglas Gilbert 			/*
436764e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
436864e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4369f0d1cf93SDouglas Gilbert 			 */
4370f0d1cf93SDouglas Gilbert 			continue;
437164e14eceSDamien Le Moal 		case 0x11:
437264e14eceSDamien Le Moal 			/* non-seq-resource set */
437364e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
437464e14eceSDamien Le Moal 				continue;
437564e14eceSDamien Le Moal 			break;
4376f0d1cf93SDouglas Gilbert 		case 0x3f:
4377f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4378f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4379f0d1cf93SDouglas Gilbert 				continue;
4380f0d1cf93SDouglas Gilbert 			break;
4381f0d1cf93SDouglas Gilbert 		default:
4382f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4383f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4384f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4385f0d1cf93SDouglas Gilbert 			goto fini;
4386f0d1cf93SDouglas Gilbert 		}
4387f0d1cf93SDouglas Gilbert 
4388f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4389f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
439064e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4391f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
439264e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
439364e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4394f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4395f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4396f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4397f0d1cf93SDouglas Gilbert 			desc += 64;
4398f0d1cf93SDouglas Gilbert 		}
4399f0d1cf93SDouglas Gilbert 
4400f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4401f0d1cf93SDouglas Gilbert 			break;
4402f0d1cf93SDouglas Gilbert 
4403f0d1cf93SDouglas Gilbert 		nrz++;
4404f0d1cf93SDouglas Gilbert 	}
4405f0d1cf93SDouglas Gilbert 
4406f0d1cf93SDouglas Gilbert 	/* Report header */
4407f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4408f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4409f0d1cf93SDouglas Gilbert 
4410f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4411f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4412f0d1cf93SDouglas Gilbert 
4413f0d1cf93SDouglas Gilbert fini:
4414f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4415f0d1cf93SDouglas Gilbert 	kfree(arr);
4416f0d1cf93SDouglas Gilbert 	return ret;
4417f0d1cf93SDouglas Gilbert }
4418f0d1cf93SDouglas Gilbert 
4419f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4420f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4421f0d1cf93SDouglas Gilbert {
4422f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4423f0d1cf93SDouglas Gilbert 	unsigned int i;
4424f0d1cf93SDouglas Gilbert 
4425f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4426f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4427f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4428f0d1cf93SDouglas Gilbert 	}
4429f0d1cf93SDouglas Gilbert }
4430f0d1cf93SDouglas Gilbert 
4431f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4432f0d1cf93SDouglas Gilbert {
4433f0d1cf93SDouglas Gilbert 	int res = 0;
4434f0d1cf93SDouglas Gilbert 	u64 z_id;
4435f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4436f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4437f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4438f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4439b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4440f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4441f0d1cf93SDouglas Gilbert 
4442f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4443f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4444f0d1cf93SDouglas Gilbert 		return check_condition_result;
4445f0d1cf93SDouglas Gilbert 	}
4446f0d1cf93SDouglas Gilbert 
4447f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4448f0d1cf93SDouglas Gilbert 
4449f0d1cf93SDouglas Gilbert 	if (all) {
4450f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4451f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4452f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4453f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4454f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4455f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4456f0d1cf93SDouglas Gilbert 			goto fini;
4457f0d1cf93SDouglas Gilbert 		}
4458f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4459f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4460f0d1cf93SDouglas Gilbert 		goto fini;
4461f0d1cf93SDouglas Gilbert 	}
4462f0d1cf93SDouglas Gilbert 
4463f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4464f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4465f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4466f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4467f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4468f0d1cf93SDouglas Gilbert 		goto fini;
4469f0d1cf93SDouglas Gilbert 	}
4470f0d1cf93SDouglas Gilbert 
4471f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4472f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4473f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4474f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4475f0d1cf93SDouglas Gilbert 		goto fini;
4476f0d1cf93SDouglas Gilbert 	}
4477f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4478f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4479f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4480f0d1cf93SDouglas Gilbert 		goto fini;
4481f0d1cf93SDouglas Gilbert 	}
4482f0d1cf93SDouglas Gilbert 
4483f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4484f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4485f0d1cf93SDouglas Gilbert 		goto fini;
4486f0d1cf93SDouglas Gilbert 
4487f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4488f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4489f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4490f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4491f0d1cf93SDouglas Gilbert 		goto fini;
4492f0d1cf93SDouglas Gilbert 	}
4493f0d1cf93SDouglas Gilbert 
4494f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4495f0d1cf93SDouglas Gilbert fini:
4496f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4497f0d1cf93SDouglas Gilbert 	return res;
4498f0d1cf93SDouglas Gilbert }
4499f0d1cf93SDouglas Gilbert 
4500f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4501f0d1cf93SDouglas Gilbert {
4502f0d1cf93SDouglas Gilbert 	unsigned int i;
4503f0d1cf93SDouglas Gilbert 
4504f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4505f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4506f0d1cf93SDouglas Gilbert }
4507f0d1cf93SDouglas Gilbert 
4508f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4509f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4510f0d1cf93SDouglas Gilbert {
4511f0d1cf93SDouglas Gilbert 	int res = 0;
4512f0d1cf93SDouglas Gilbert 	u64 z_id;
4513f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4514f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4515f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4516b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4517f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4518f0d1cf93SDouglas Gilbert 
4519f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4520f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4521f0d1cf93SDouglas Gilbert 		return check_condition_result;
4522f0d1cf93SDouglas Gilbert 	}
4523f0d1cf93SDouglas Gilbert 
4524f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4525f0d1cf93SDouglas Gilbert 
4526f0d1cf93SDouglas Gilbert 	if (all) {
4527f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4528f0d1cf93SDouglas Gilbert 		goto fini;
4529f0d1cf93SDouglas Gilbert 	}
4530f0d1cf93SDouglas Gilbert 
4531f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4532f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4533f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4534f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4535f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4536f0d1cf93SDouglas Gilbert 		goto fini;
4537f0d1cf93SDouglas Gilbert 	}
4538f0d1cf93SDouglas Gilbert 
4539f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4540f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4541f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4542f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4543f0d1cf93SDouglas Gilbert 		goto fini;
4544f0d1cf93SDouglas Gilbert 	}
4545f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4546f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4547f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4548f0d1cf93SDouglas Gilbert 		goto fini;
4549f0d1cf93SDouglas Gilbert 	}
4550f0d1cf93SDouglas Gilbert 
4551f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4552f0d1cf93SDouglas Gilbert fini:
4553f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4554f0d1cf93SDouglas Gilbert 	return res;
4555f0d1cf93SDouglas Gilbert }
4556f0d1cf93SDouglas Gilbert 
4557f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4558f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4559f0d1cf93SDouglas Gilbert {
4560f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4561f0d1cf93SDouglas Gilbert 
4562f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4563f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4564f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4565f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4566f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4567f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4568f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4569f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4570f0d1cf93SDouglas Gilbert 	}
4571f0d1cf93SDouglas Gilbert }
4572f0d1cf93SDouglas Gilbert 
4573f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4574f0d1cf93SDouglas Gilbert {
4575f0d1cf93SDouglas Gilbert 	unsigned int i;
4576f0d1cf93SDouglas Gilbert 
4577f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4578f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4579f0d1cf93SDouglas Gilbert }
4580f0d1cf93SDouglas Gilbert 
4581f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4582f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4583f0d1cf93SDouglas Gilbert {
4584f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4585f0d1cf93SDouglas Gilbert 	int res = 0;
4586f0d1cf93SDouglas Gilbert 	u64 z_id;
4587f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4588f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4589b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4590f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4591f0d1cf93SDouglas Gilbert 
4592f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4593f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4594f0d1cf93SDouglas Gilbert 		return check_condition_result;
4595f0d1cf93SDouglas Gilbert 	}
4596f0d1cf93SDouglas Gilbert 
4597f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4598f0d1cf93SDouglas Gilbert 
4599f0d1cf93SDouglas Gilbert 	if (all) {
4600f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4601f0d1cf93SDouglas Gilbert 		goto fini;
4602f0d1cf93SDouglas Gilbert 	}
4603f0d1cf93SDouglas Gilbert 
4604f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4605f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4606f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4607f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4608f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4609f0d1cf93SDouglas Gilbert 		goto fini;
4610f0d1cf93SDouglas Gilbert 	}
4611f0d1cf93SDouglas Gilbert 
4612f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4613f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4614f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4615f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4616f0d1cf93SDouglas Gilbert 		goto fini;
4617f0d1cf93SDouglas Gilbert 	}
4618f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4619f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4620f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4621f0d1cf93SDouglas Gilbert 		goto fini;
4622f0d1cf93SDouglas Gilbert 	}
4623f0d1cf93SDouglas Gilbert 
4624f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4625f0d1cf93SDouglas Gilbert fini:
4626f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4627f0d1cf93SDouglas Gilbert 	return res;
4628f0d1cf93SDouglas Gilbert }
4629f0d1cf93SDouglas Gilbert 
4630f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4631f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4632f0d1cf93SDouglas Gilbert {
4633f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4634f0d1cf93SDouglas Gilbert 
4635f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4636f0d1cf93SDouglas Gilbert 		return;
4637f0d1cf93SDouglas Gilbert 
4638f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4639f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4640f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4641f0d1cf93SDouglas Gilbert 
4642f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4643f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4644f0d1cf93SDouglas Gilbert 
464564e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4646f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4647f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4648f0d1cf93SDouglas Gilbert }
4649f0d1cf93SDouglas Gilbert 
4650f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4651f0d1cf93SDouglas Gilbert {
4652f0d1cf93SDouglas Gilbert 	unsigned int i;
4653f0d1cf93SDouglas Gilbert 
4654f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4655f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4656f0d1cf93SDouglas Gilbert }
4657f0d1cf93SDouglas Gilbert 
4658f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4659f0d1cf93SDouglas Gilbert {
4660f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4661f0d1cf93SDouglas Gilbert 	int res = 0;
4662f0d1cf93SDouglas Gilbert 	u64 z_id;
4663f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4664f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4665b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4666f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4667f0d1cf93SDouglas Gilbert 
4668f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4669f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4670f0d1cf93SDouglas Gilbert 		return check_condition_result;
4671f0d1cf93SDouglas Gilbert 	}
4672f0d1cf93SDouglas Gilbert 
4673f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4674f0d1cf93SDouglas Gilbert 
4675f0d1cf93SDouglas Gilbert 	if (all) {
4676f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4677f0d1cf93SDouglas Gilbert 		goto fini;
4678f0d1cf93SDouglas Gilbert 	}
4679f0d1cf93SDouglas Gilbert 
4680f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4681f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4682f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4683f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4684f0d1cf93SDouglas Gilbert 		goto fini;
4685f0d1cf93SDouglas Gilbert 	}
4686f0d1cf93SDouglas Gilbert 
4687f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4688f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4689f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4690f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4691f0d1cf93SDouglas Gilbert 		goto fini;
4692f0d1cf93SDouglas Gilbert 	}
4693f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4694f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4695f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4696f0d1cf93SDouglas Gilbert 		goto fini;
4697f0d1cf93SDouglas Gilbert 	}
4698f0d1cf93SDouglas Gilbert 
4699f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4700f0d1cf93SDouglas Gilbert fini:
4701f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4702f0d1cf93SDouglas Gilbert 	return res;
4703f0d1cf93SDouglas Gilbert }
4704f0d1cf93SDouglas Gilbert 
4705c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4706c4837394SDouglas Gilbert {
4707c10fa55fSJohn Garry 	u16 hwq;
4708c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
4709c10fa55fSJohn Garry 
4710c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4711c4837394SDouglas Gilbert 
4712458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4713458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4714458df78bSBart Van Assche 		hwq = 0;
4715f7c4cdc7SJohn Garry 
4716458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4717c4837394SDouglas Gilbert }
4718c4837394SDouglas Gilbert 
4719c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4720c10fa55fSJohn Garry {
4721c10fa55fSJohn Garry 	return blk_mq_unique_tag(cmnd->request);
4722c10fa55fSJohn Garry }
4723c10fa55fSJohn Garry 
4724c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4725fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47261da177e4SLinus Torvalds {
47277382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4728c4837394SDouglas Gilbert 	int qc_idx;
4729cbf67842SDouglas Gilbert 	int retiring = 0;
47301da177e4SLinus Torvalds 	unsigned long iflags;
4731c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4732cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4733cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4734cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47351da177e4SLinus Torvalds 
47367382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47377382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4738c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4739c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4740c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4741cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4742c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4743c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4744c4837394SDouglas Gilbert 	}
4745c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4746c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47471da177e4SLinus Torvalds 		return;
47481da177e4SLinus Torvalds 	}
4749c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
47504a0c6f43SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
4751c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4752cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4753b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4754c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4755c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4756c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
47571da177e4SLinus Torvalds 		return;
47581da177e4SLinus Torvalds 	}
4759cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4760f46eb0e9SDouglas Gilbert 	if (likely(devip))
4761cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4762cbf67842SDouglas Gilbert 	else
4763c1287970STomas Winkler 		pr_err("devip=NULL\n");
4764f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4765cbf67842SDouglas Gilbert 		retiring = 1;
4766cbf67842SDouglas Gilbert 
4767cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4768c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4769c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4770c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4771cbf67842SDouglas Gilbert 		return;
47721da177e4SLinus Torvalds 	}
47731da177e4SLinus Torvalds 
4774cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4775cbf67842SDouglas Gilbert 		int k, retval;
4776cbf67842SDouglas Gilbert 
4777cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4778c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4779c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4780c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4781cbf67842SDouglas Gilbert 			return;
4782cbf67842SDouglas Gilbert 		}
4783c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4784773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4785cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4786cbf67842SDouglas Gilbert 		else
4787cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4788cbf67842SDouglas Gilbert 	}
4789c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47907382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
47917382f9d8SDouglas Gilbert 		if (sdebug_verbose)
47927382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
47937382f9d8SDouglas Gilbert 		return;
47947382f9d8SDouglas Gilbert 	}
4795cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4796cbf67842SDouglas Gilbert }
4797cbf67842SDouglas Gilbert 
4798cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4799fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4800cbf67842SDouglas Gilbert {
4801a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4802a10bc12aSDouglas Gilbert 						  hrt);
4803a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4804cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4805cbf67842SDouglas Gilbert }
48061da177e4SLinus Torvalds 
4807a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4808fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4809a10bc12aSDouglas Gilbert {
4810a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4811a10bc12aSDouglas Gilbert 						  ew.work);
4812a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4813a10bc12aSDouglas Gilbert }
4814a10bc12aSDouglas Gilbert 
481509ba24c1SDouglas Gilbert static bool got_shared_uuid;
4816bf476433SChristoph Hellwig static uuid_t shared_uuid;
481709ba24c1SDouglas Gilbert 
4818f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4819f0d1cf93SDouglas Gilbert {
4820f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4821f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4822f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4823f0d1cf93SDouglas Gilbert 	unsigned int i;
4824f0d1cf93SDouglas Gilbert 
4825f0d1cf93SDouglas Gilbert 	/*
482698e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
482798e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4828f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4829f0d1cf93SDouglas Gilbert 	 * created for the device.
4830f0d1cf93SDouglas Gilbert 	 */
483198e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4832f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4833f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4834f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4835f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4836f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4837f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4838f0d1cf93SDouglas Gilbert 			return -EINVAL;
4839f0d1cf93SDouglas Gilbert 		}
4840f0d1cf93SDouglas Gilbert 	} else {
4841108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4842108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4843108e36f0SDamien Le Moal 			return -EINVAL;
4844108e36f0SDamien Le Moal 		}
484598e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4846f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4847f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4848f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4849f0d1cf93SDouglas Gilbert 			return -EINVAL;
4850f0d1cf93SDouglas Gilbert 		}
4851f0d1cf93SDouglas Gilbert 	}
4852f0d1cf93SDouglas Gilbert 
4853f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4854f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4855f0d1cf93SDouglas Gilbert 
4856aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4857aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4858aa8fecf9SDamien Le Moal 		return -EINVAL;
4859aa8fecf9SDamien Le Moal 	}
4860aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4861aa8fecf9SDamien Le Moal 
486264e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
486364e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4864380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4865f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4866f0d1cf93SDouglas Gilbert 		else
4867380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
486864e14eceSDamien Le Moal 	}
4869f0d1cf93SDouglas Gilbert 
4870f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4871f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4872f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4873f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4874f0d1cf93SDouglas Gilbert 
4875f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4876f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4877f0d1cf93SDouglas Gilbert 
4878f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4879f0d1cf93SDouglas Gilbert 
4880aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
488164e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4882f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4883f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4884f0d1cf93SDouglas Gilbert 		} else {
488564e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
488664e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
488764e14eceSDamien Le Moal 			else
488864e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4889f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4890f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4891f0d1cf93SDouglas Gilbert 		}
4892f0d1cf93SDouglas Gilbert 
4893f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4894f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4895f0d1cf93SDouglas Gilbert 		else
4896f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4897f0d1cf93SDouglas Gilbert 
4898f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4899f0d1cf93SDouglas Gilbert 	}
4900f0d1cf93SDouglas Gilbert 
4901f0d1cf93SDouglas Gilbert 	return 0;
4902f0d1cf93SDouglas Gilbert }
4903f0d1cf93SDouglas Gilbert 
4904fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4905fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
49065cb2fc06SFUJITA Tomonori {
49075cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
49085cb2fc06SFUJITA Tomonori 
49095cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
49105cb2fc06SFUJITA Tomonori 	if (devip) {
491109ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4912bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
491309ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
491409ba24c1SDouglas Gilbert 			if (got_shared_uuid)
491509ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
491609ba24c1SDouglas Gilbert 			else {
4917bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
491809ba24c1SDouglas Gilbert 				got_shared_uuid = true;
491909ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
492009ba24c1SDouglas Gilbert 			}
492109ba24c1SDouglas Gilbert 		}
49225cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4923f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
492464e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4925f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4926f0d1cf93SDouglas Gilbert 				kfree(devip);
4927f0d1cf93SDouglas Gilbert 				return NULL;
4928f0d1cf93SDouglas Gilbert 			}
492964e14eceSDamien Le Moal 		} else {
493064e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4931f0d1cf93SDouglas Gilbert 		}
4932f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
4933fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
4934fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
49355cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49365cb2fc06SFUJITA Tomonori 	}
49375cb2fc06SFUJITA Tomonori 	return devip;
49385cb2fc06SFUJITA Tomonori }
49395cb2fc06SFUJITA Tomonori 
4940f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49411da177e4SLinus Torvalds {
49421da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49431da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4944f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49451da177e4SLinus Torvalds 
4946d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49471da177e4SLinus Torvalds 	if (!sdbg_host) {
4948c1287970STomas Winkler 		pr_err("Host info NULL\n");
49491da177e4SLinus Torvalds 		return NULL;
49501da177e4SLinus Torvalds 	}
4951ad0c7775SDouglas Gilbert 
49521da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49531da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49541da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49551da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49561da177e4SLinus Torvalds 			return devip;
49571da177e4SLinus Torvalds 		else {
49581da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49591da177e4SLinus Torvalds 				open_devip = devip;
49601da177e4SLinus Torvalds 		}
49611da177e4SLinus Torvalds 	}
49625cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49635cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49645cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4965c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49661da177e4SLinus Torvalds 			return NULL;
49671da177e4SLinus Torvalds 		}
49681da177e4SLinus Torvalds 	}
4969a75869d1SFUJITA Tomonori 
49701da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
49711da177e4SLinus Torvalds 	open_devip->target = sdev->id;
49721da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
49731da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4974cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4975cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4976c2248fc9SDouglas Gilbert 	open_devip->used = true;
49771da177e4SLinus Torvalds 	return open_devip;
49781da177e4SLinus Torvalds }
49791da177e4SLinus Torvalds 
49808dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
49811da177e4SLinus Torvalds {
4982773642d9SDouglas Gilbert 	if (sdebug_verbose)
4983c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
49848dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49858dea0d02SFUJITA Tomonori 	return 0;
49868dea0d02SFUJITA Tomonori }
49871da177e4SLinus Torvalds 
49888dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
49898dea0d02SFUJITA Tomonori {
4990f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4991f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4992a34c4e98SFUJITA Tomonori 
4993773642d9SDouglas Gilbert 	if (sdebug_verbose)
4994c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
49958dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4996b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4997b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4998b01f6f83SDouglas Gilbert 	if (devip == NULL) {
4999f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5000b01f6f83SDouglas Gilbert 		if (devip == NULL)
50018dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5002f46eb0e9SDouglas Gilbert 	}
5003c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5004773642d9SDouglas Gilbert 	if (sdebug_no_uld)
500578d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
50069b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
50078dea0d02SFUJITA Tomonori 	return 0;
50088dea0d02SFUJITA Tomonori }
50098dea0d02SFUJITA Tomonori 
50108dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
50118dea0d02SFUJITA Tomonori {
50128dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
50138dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
50148dea0d02SFUJITA Tomonori 
5015773642d9SDouglas Gilbert 	if (sdebug_verbose)
5016c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
50178dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50188dea0d02SFUJITA Tomonori 	if (devip) {
501925985edcSLucas De Marchi 		/* make this slot available for re-use */
5020c2248fc9SDouglas Gilbert 		devip->used = false;
50218dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
50228dea0d02SFUJITA Tomonori 	}
50238dea0d02SFUJITA Tomonori }
50248dea0d02SFUJITA Tomonori 
502510bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
502610bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5027c4837394SDouglas Gilbert {
5028c4837394SDouglas Gilbert 	if (!sd_dp)
5029c4837394SDouglas Gilbert 		return;
503010bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5031c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
503210bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5033c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5034c4837394SDouglas Gilbert }
5035c4837394SDouglas Gilbert 
5036a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5037a10bc12aSDouglas Gilbert    returns false */
5038a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50398dea0d02SFUJITA Tomonori {
50408dea0d02SFUJITA Tomonori 	unsigned long iflags;
5041c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
504210bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5043c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50448dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5045cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5046a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50478dea0d02SFUJITA Tomonori 
5048c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5049c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5050773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5051cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5052cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5053cbf67842SDouglas Gilbert 			qmax = r_qmax;
5054cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5055c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5056c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5057a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5058a10bc12aSDouglas Gilbert 					continue;
5059c4837394SDouglas Gilbert 				/* found */
5060db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5061db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5062db525fceSDouglas Gilbert 				if (devip)
5063db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5064db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5065a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
506610bde980SDouglas Gilbert 				if (sd_dp) {
506710bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
506810bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
506910bde980SDouglas Gilbert 				} else
507010bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5071c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
507210bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5073c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5074a10bc12aSDouglas Gilbert 				return true;
50758dea0d02SFUJITA Tomonori 			}
5076cbf67842SDouglas Gilbert 		}
5077c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5078c4837394SDouglas Gilbert 	}
5079a10bc12aSDouglas Gilbert 	return false;
50808dea0d02SFUJITA Tomonori }
50818dea0d02SFUJITA Tomonori 
5082a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
50838dea0d02SFUJITA Tomonori static void stop_all_queued(void)
50848dea0d02SFUJITA Tomonori {
50858dea0d02SFUJITA Tomonori 	unsigned long iflags;
5086c4837394SDouglas Gilbert 	int j, k;
508710bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5088c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50898dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5090cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5091a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50928dea0d02SFUJITA Tomonori 
5093c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5094c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5095c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5096c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5097c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5098c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5099a10bc12aSDouglas Gilbert 					continue;
5100db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5101db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5102db525fceSDouglas Gilbert 				if (devip)
5103db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5104db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5105a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
510610bde980SDouglas Gilbert 				if (sd_dp) {
510710bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
510810bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
510910bde980SDouglas Gilbert 				} else
511010bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5111c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
511210bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5113c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5114c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
51158dea0d02SFUJITA Tomonori 			}
51168dea0d02SFUJITA Tomonori 		}
5117c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5118c4837394SDouglas Gilbert 	}
5119cbf67842SDouglas Gilbert }
5120cbf67842SDouglas Gilbert 
5121cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5122cbf67842SDouglas Gilbert static void free_all_queued(void)
5123cbf67842SDouglas Gilbert {
5124c4837394SDouglas Gilbert 	int j, k;
5125c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5126cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5127cbf67842SDouglas Gilbert 
5128c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5129c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5130c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5131a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5132a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5133cbf67842SDouglas Gilbert 		}
51341da177e4SLinus Torvalds 	}
5135c4837394SDouglas Gilbert }
51361da177e4SLinus Torvalds 
51371da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51381da177e4SLinus Torvalds {
5139a10bc12aSDouglas Gilbert 	bool ok;
5140a10bc12aSDouglas Gilbert 
51411da177e4SLinus Torvalds 	++num_aborts;
5142cbf67842SDouglas Gilbert 	if (SCpnt) {
5143a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5144a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5145a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5146a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5147a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5148cbf67842SDouglas Gilbert 	}
51491da177e4SLinus Torvalds 	return SUCCESS;
51501da177e4SLinus Torvalds }
51511da177e4SLinus Torvalds 
51521da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51531da177e4SLinus Torvalds {
51541da177e4SLinus Torvalds 	++num_dev_resets;
5155cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5156cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5157f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5158f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5159cbf67842SDouglas Gilbert 
5160773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5161cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51621da177e4SLinus Torvalds 		if (devip)
5163cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51641da177e4SLinus Torvalds 	}
51651da177e4SLinus Torvalds 	return SUCCESS;
51661da177e4SLinus Torvalds }
51671da177e4SLinus Torvalds 
5168cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5169cbf67842SDouglas Gilbert {
5170cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5171cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5172cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5173cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5174cbf67842SDouglas Gilbert 	int k = 0;
5175cbf67842SDouglas Gilbert 
5176cbf67842SDouglas Gilbert 	++num_target_resets;
5177cbf67842SDouglas Gilbert 	if (!SCpnt)
5178cbf67842SDouglas Gilbert 		goto lie;
5179cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5180cbf67842SDouglas Gilbert 	if (!sdp)
5181cbf67842SDouglas Gilbert 		goto lie;
5182773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5183cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5184cbf67842SDouglas Gilbert 	hp = sdp->host;
5185cbf67842SDouglas Gilbert 	if (!hp)
5186cbf67842SDouglas Gilbert 		goto lie;
5187cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5188cbf67842SDouglas Gilbert 	if (sdbg_host) {
5189cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5190cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5191cbf67842SDouglas Gilbert 				    dev_list)
5192cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5193cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5194cbf67842SDouglas Gilbert 				++k;
5195cbf67842SDouglas Gilbert 			}
5196cbf67842SDouglas Gilbert 	}
5197773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5198cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5199cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5200cbf67842SDouglas Gilbert lie:
5201cbf67842SDouglas Gilbert 	return SUCCESS;
5202cbf67842SDouglas Gilbert }
5203cbf67842SDouglas Gilbert 
52041da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
52051da177e4SLinus Torvalds {
52061da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5207cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
52081da177e4SLinus Torvalds 	struct scsi_device *sdp;
52091da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5210cbf67842SDouglas Gilbert 	int k = 0;
52111da177e4SLinus Torvalds 
52121da177e4SLinus Torvalds 	++num_bus_resets;
5213cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5214cbf67842SDouglas Gilbert 		goto lie;
5215cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5216773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5217cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5218cbf67842SDouglas Gilbert 	hp = sdp->host;
5219cbf67842SDouglas Gilbert 	if (hp) {
5220d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52211da177e4SLinus Torvalds 		if (sdbg_host) {
5222cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
52231da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5224cbf67842SDouglas Gilbert 					    dev_list) {
5225cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5226cbf67842SDouglas Gilbert 				++k;
52271da177e4SLinus Torvalds 			}
52281da177e4SLinus Torvalds 		}
5229cbf67842SDouglas Gilbert 	}
5230773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5231cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5232cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5233cbf67842SDouglas Gilbert lie:
52341da177e4SLinus Torvalds 	return SUCCESS;
52351da177e4SLinus Torvalds }
52361da177e4SLinus Torvalds 
52371da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52381da177e4SLinus Torvalds {
52391da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5240cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5241cbf67842SDouglas Gilbert 	int k = 0;
52421da177e4SLinus Torvalds 
52431da177e4SLinus Torvalds 	++num_host_resets;
5244773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5245cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52461da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52471da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5248cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5249cbf67842SDouglas Gilbert 				    dev_list) {
5250cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5251cbf67842SDouglas Gilbert 			++k;
5252cbf67842SDouglas Gilbert 		}
52531da177e4SLinus Torvalds 	}
52541da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52551da177e4SLinus Torvalds 	stop_all_queued();
5256773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5257cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5258cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
52591da177e4SLinus Torvalds 	return SUCCESS;
52601da177e4SLinus Torvalds }
52611da177e4SLinus Torvalds 
526287c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52631da177e4SLinus Torvalds {
52641442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5265979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
52661da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
52671da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
52681da177e4SLinus Torvalds 
52691da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5270773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
52711da177e4SLinus Torvalds 		return;
5272773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5273773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5274c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
52751da177e4SLinus Torvalds 	}
52768c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
52771da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5278773642d9SDouglas Gilbert 			   / sdebug_num_parts;
52791da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
52801da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5281979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5282979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
52831da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
52841da177e4SLinus Torvalds 			    * heads_by_sects;
5285979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5286979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5287979e0dc3SJohn Pittman 	}
5288773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5289773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
52901da177e4SLinus Torvalds 
52911da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
52921da177e4SLinus Torvalds 	ramp[511] = 0xAA;
52931442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
52941da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
52951da177e4SLinus Torvalds 		start_sec = starts[k];
5296979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
52971da177e4SLinus Torvalds 		pp->boot_ind = 0;
52981da177e4SLinus Torvalds 
52991da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
53001da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
53011da177e4SLinus Torvalds 			   / sdebug_sectors_per;
53021da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
53031da177e4SLinus Torvalds 
53041da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
53051da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
53061da177e4SLinus Torvalds 			       / sdebug_sectors_per;
53071da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
53081da177e4SLinus Torvalds 
5309150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5310150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
53111da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
53121da177e4SLinus Torvalds 	}
53131da177e4SLinus Torvalds }
53141da177e4SLinus Torvalds 
5315c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5316c4837394SDouglas Gilbert {
5317c4837394SDouglas Gilbert 	int j;
5318c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5319c4837394SDouglas Gilbert 
5320c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5321c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5322c4837394SDouglas Gilbert }
5323c4837394SDouglas Gilbert 
5324c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5325c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5326c4837394SDouglas Gilbert  */
5327c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5328c4837394SDouglas Gilbert {
5329c4837394SDouglas Gilbert 	int count, modulo;
5330c4837394SDouglas Gilbert 
5331c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5332c4837394SDouglas Gilbert 	if (modulo < 2)
5333c4837394SDouglas Gilbert 		return;
5334c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5335c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5336c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5337c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5338c4837394SDouglas Gilbert }
5339c4837394SDouglas Gilbert 
5340c4837394SDouglas Gilbert static void clear_queue_stats(void)
5341c4837394SDouglas Gilbert {
5342c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5343c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5344c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5345c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5346c4837394SDouglas Gilbert }
5347c4837394SDouglas Gilbert 
53483a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5349c4837394SDouglas Gilbert {
53503a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
53513a90a63dSDouglas Gilbert 		return false;
53523a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5353c4837394SDouglas Gilbert }
5354c4837394SDouglas Gilbert 
5355a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5356a2aede97SDouglas Gilbert 
5357c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5358c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5359c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5360c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5361c4837394SDouglas Gilbert  */
5362fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5363f66b8517SMartin Wilck 			 int scsi_result,
5364f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5365f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5366f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
53671da177e4SLinus Torvalds {
5368a2aede97SDouglas Gilbert 	bool new_sd_dp;
53693a90a63dSDouglas Gilbert 	bool inject = false;
5370*771f712bSDouglas Gilbert 	bool hipri = (cmnd->request->cmd_flags & REQ_HIPRI);
53713a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5372a2aede97SDouglas Gilbert 	unsigned long iflags;
5373a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5374c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5375c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5376299b6c07STomas Winkler 	struct scsi_device *sdp;
5377a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53781da177e4SLinus Torvalds 
5379b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5380b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5381f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5382f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
53831da177e4SLinus Torvalds 	}
5384299b6c07STomas Winkler 	sdp = cmnd->device;
5385299b6c07STomas Winkler 
5386cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5387cd62b7daSDouglas Gilbert 		goto respond_in_thread;
53881da177e4SLinus Torvalds 
5389c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5390c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5391c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5392c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5393c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5394c4837394SDouglas Gilbert 	}
5395cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5396cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5397f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5398cd62b7daSDouglas Gilbert 		if (scsi_result) {
5399c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5400cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5401cd62b7daSDouglas Gilbert 		} else
5402cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5403c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5404773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5405f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5406cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5407cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5408773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5409cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
54103a90a63dSDouglas Gilbert 			inject = true;
5411cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
54121da177e4SLinus Torvalds 		}
5413cbf67842SDouglas Gilbert 	}
5414cbf67842SDouglas Gilbert 
5415c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5416f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5417c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5418cd62b7daSDouglas Gilbert 		if (scsi_result)
5419cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5420773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5421cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5422773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5423cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5424cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5425773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5426cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5427cbf67842SDouglas Gilbert 						    "report: host busy"));
5428cd62b7daSDouglas Gilbert 		if (scsi_result)
5429cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5430cd62b7daSDouglas Gilbert 		else
5431cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
54321da177e4SLinus Torvalds 	}
543374595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5434cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5435c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
54361da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5437c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5438a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5439c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5440c4b57d89SKashyap Desai 
544174595c04SDouglas Gilbert 	if (!sd_dp) {
544210bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
544374595c04SDouglas Gilbert 		if (!sd_dp) {
544474595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
544574595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
544610bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
544774595c04SDouglas Gilbert 		}
5448a2aede97SDouglas Gilbert 		new_sd_dp = true;
5449a2aede97SDouglas Gilbert 	} else {
5450a2aede97SDouglas Gilbert 		new_sd_dp = false;
545110bde980SDouglas Gilbert 	}
5452f66b8517SMartin Wilck 
5453c10fa55fSJohn Garry 	/* Set the hostwide tag */
5454c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5455c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5456c10fa55fSJohn Garry 
5457*771f712bSDouglas Gilbert 	if (hipri)
5458a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5459a2aede97SDouglas Gilbert 
5460a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
54613a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5462f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5463f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5464f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5465f66b8517SMartin Wilck 	}
5466f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5467f66b8517SMartin Wilck 		cmnd->result = scsi_result;
54683a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
54693a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
54703a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
54713a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
54723a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
54733a90a63dSDouglas Gilbert 		}
54743a90a63dSDouglas Gilbert 	}
5475f66b8517SMartin Wilck 
5476f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5477f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5478f66b8517SMartin Wilck 			    __func__, cmnd->result);
5479f66b8517SMartin Wilck 
548010bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5481b333a819SDouglas Gilbert 		ktime_t kt;
5482cbf67842SDouglas Gilbert 
5483b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
54840c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
54850c4bc91dSDouglas Gilbert 
54860c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
54870c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
54880c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
54890c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
54900c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
54910c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
54920c4bc91dSDouglas Gilbert 				ns <<= 12;
54930c4bc91dSDouglas Gilbert 			}
54940c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
54950c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
54960c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
54970c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5498a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5499a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5500a2aede97SDouglas Gilbert 
5501a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5502223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5503a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5504a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5505a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5506223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5507a2aede97SDouglas Gilbert 					if (new_sd_dp)
5508a2aede97SDouglas Gilbert 						kfree(sd_dp);
5509a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
5510a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
5511a2aede97SDouglas Gilbert 					return 0;
5512a2aede97SDouglas Gilbert 				}
5513a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5514a2aede97SDouglas Gilbert 				kt -= d;
5515a2aede97SDouglas Gilbert 			}
55160c4bc91dSDouglas Gilbert 		}
5517*771f712bSDouglas Gilbert 		if (hipri) {
55184a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
55194a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
55204a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
55214a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
55224a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
55234a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
55244a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
55254a0c6f43SDouglas Gilbert 			}
55264a0c6f43SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_POLL;
55274a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
55284a0c6f43SDouglas Gilbert 		} else {
552910bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
553010bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5531a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5532a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5533c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5534a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5535c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5536c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5537cbf67842SDouglas Gilbert 			}
553810bde980SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_HRT;
5539a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5540c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
55414a0c6f43SDouglas Gilbert 		}
55424a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
55434a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5544c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
55454a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55464a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
55474a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
5548*771f712bSDouglas Gilbert 		if (hipri) {
55494a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
55504a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
55514a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
55524a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
55534a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
55544a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
55554a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
55564a0c6f43SDouglas Gilbert 			}
55574a0c6f43SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_POLL;
55584a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
55594a0c6f43SDouglas Gilbert 		} else {
556010bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
556110bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5562a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5563c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5564c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5565a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5566cbf67842SDouglas Gilbert 			}
55674a0c6f43SDouglas Gilbert 			sd_dp->defer_t = SDEB_DEFER_WQ;
55684a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
55694a0c6f43SDouglas Gilbert 		}
5570c4837394SDouglas Gilbert 		if (sdebug_statistics)
5571c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
55724a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
55733a90a63dSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
55747382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
55753a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
55764a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
55777382f9d8SDouglas Gilbert 		}
5578cbf67842SDouglas Gilbert 	}
55793a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
55803a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
55813a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
55821da177e4SLinus Torvalds 	return 0;
5583cd62b7daSDouglas Gilbert 
5584cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5585f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5586f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5587f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5588cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
5589cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
5590cd62b7daSDouglas Gilbert 	return 0;
55911da177e4SLinus Torvalds }
5592cbf67842SDouglas Gilbert 
559323183910SDouglas Gilbert /* Note: The following macros create attribute files in the
559423183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
559523183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
559623183910SDouglas Gilbert    as it can when the corresponding attribute in the
559723183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
559823183910SDouglas Gilbert  */
5599773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5600773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
56019b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5602773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5603c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5604773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5605773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5606773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5607773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5608773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5609773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5610773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5611773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5612c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5613e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5614e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5615e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5616e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
56175d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
56185d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
56195d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5620773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5621773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5622773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5623773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5624ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5625773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5626773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
56275d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
56285d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56295d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
56305d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5631773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5632773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5633773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5634773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5635773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5636773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
56375d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5638773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
563987c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
564087c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5641773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5642773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
56430c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5644773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5645773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5646773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5647c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5648773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5649c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5650c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5651fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5652773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5653773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5654773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5655773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
565609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
56575d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5658773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
565923183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56609447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5661773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
56625b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
56639267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5664380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5665aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
566698e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56671da177e4SLinus Torvalds 
56681da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56691da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
56701da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5671b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
56721da177e4SLinus Torvalds 
56735d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56745b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56759b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56760759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5677cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5678c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
56795b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
56805b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5681c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5682beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
568323183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
56845b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5685185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5686c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5687c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5688e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
56899b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
56909b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
56915d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
56925d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
56935d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
56945b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
56955b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
56965b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
56975b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5698c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5699ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5700cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5701d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
57025d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5703cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5704c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
570578d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
57061da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5707c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
570832c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
570986e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
57105d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
57115d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
57125d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5713c4b57d89SKashyap Desai MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1)");
57141da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
57150c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5716d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5717760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5718ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5719c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5720c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5721c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5722fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
57235b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
57245b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
57256014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
57266014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
572709ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
572809ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5729c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
57305b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
57319447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
57325b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
57339267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5734380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5735aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
573698e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
57371da177e4SLinus Torvalds 
5738760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5739760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
57401da177e4SLinus Torvalds 
57411da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
57421da177e4SLinus Torvalds {
5743c4837394SDouglas Gilbert 	int k;
5744c4837394SDouglas Gilbert 
5745760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5746760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5747760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5748c4837394SDouglas Gilbert 		return sdebug_info;
5749760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5750760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5751760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5752760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
57531da177e4SLinus Torvalds 	return sdebug_info;
57541da177e4SLinus Torvalds }
57551da177e4SLinus Torvalds 
5756cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5757fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5758fd32119bSDouglas Gilbert 				 int length)
57591da177e4SLinus Torvalds {
57601da177e4SLinus Torvalds 	char arr[16];
5761c8ed555aSAl Viro 	int opts;
57621da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
57631da177e4SLinus Torvalds 
57641da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
57651da177e4SLinus Torvalds 		return -EACCES;
57661da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
57671da177e4SLinus Torvalds 	arr[minLen] = '\0';
5768c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
57691da177e4SLinus Torvalds 		return -EINVAL;
5770773642d9SDouglas Gilbert 	sdebug_opts = opts;
5771773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5772773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5773773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5774c4837394SDouglas Gilbert 		tweak_cmnd_count();
57751da177e4SLinus Torvalds 	return length;
57761da177e4SLinus Torvalds }
5777c8ed555aSAl Viro 
5778cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5779cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5780cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5781c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5782c8ed555aSAl Viro {
5783c4837394SDouglas Gilbert 	int f, j, l;
5784c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
578587c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5786cbf67842SDouglas Gilbert 
5787c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5788c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5789c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5790c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5791c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5792c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5793c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5794c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5795c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5796c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5797c4837394SDouglas Gilbert 		   num_aborts);
5798c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5799c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5800c4837394SDouglas Gilbert 		   num_host_resets);
5801c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5802c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5803458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5804458df78bSBart Van Assche 		   sdebug_statistics);
58054a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
5806c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5807c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5808c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
58094a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
58104a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
5811cbf67842SDouglas Gilbert 
5812c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5813c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5814c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5815c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5816773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5817c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5818c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5819c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5820c4837394SDouglas Gilbert 		}
5821cbf67842SDouglas Gilbert 	}
582287c715dcSDouglas Gilbert 
582387c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
582487c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
582587c715dcSDouglas Gilbert 		bool niu;
582687c715dcSDouglas Gilbert 		int idx;
582787c715dcSDouglas Gilbert 		unsigned long l_idx;
582887c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
582987c715dcSDouglas Gilbert 
583087c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
583187c715dcSDouglas Gilbert 		j = 0;
583287c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
583387c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
583487c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
583587c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
583687c715dcSDouglas Gilbert 			++j;
583787c715dcSDouglas Gilbert 		}
583887c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
583987c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
584087c715dcSDouglas Gilbert 		j = 0;
584187c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
584287c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
584387c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
584487c715dcSDouglas Gilbert 			idx = (int)l_idx;
584587c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
584687c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
584787c715dcSDouglas Gilbert 			++j;
584887c715dcSDouglas Gilbert 		}
584987c715dcSDouglas Gilbert 	}
5850c8ed555aSAl Viro 	return 0;
58511da177e4SLinus Torvalds }
58521da177e4SLinus Torvalds 
585382069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
58541da177e4SLinus Torvalds {
5855c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
58561da177e4SLinus Torvalds }
5857c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5858c4837394SDouglas Gilbert  * of delay is jiffies.
5859c4837394SDouglas Gilbert  */
586082069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
586182069379SAkinobu Mita 			   size_t count)
58621da177e4SLinus Torvalds {
5863c2206098SDouglas Gilbert 	int jdelay, res;
58641da177e4SLinus Torvalds 
5865b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5866cbf67842SDouglas Gilbert 		res = count;
5867c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5868c4837394SDouglas Gilbert 			int j, k;
5869c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5870cbf67842SDouglas Gilbert 
5871c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5872c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5873c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5874c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5875c4837394SDouglas Gilbert 						   sdebug_max_queue);
5876c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5877c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5878c4837394SDouglas Gilbert 					break;
5879c4837394SDouglas Gilbert 				}
5880c4837394SDouglas Gilbert 			}
5881c4837394SDouglas Gilbert 			if (res > 0) {
5882c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5883773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
58841da177e4SLinus Torvalds 			}
5885c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5886cbf67842SDouglas Gilbert 		}
5887cbf67842SDouglas Gilbert 		return res;
58881da177e4SLinus Torvalds 	}
58891da177e4SLinus Torvalds 	return -EINVAL;
58901da177e4SLinus Torvalds }
589182069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
58921da177e4SLinus Torvalds 
5893cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5894cbf67842SDouglas Gilbert {
5895773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5896cbf67842SDouglas Gilbert }
5897cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5898c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5899cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5900cbf67842SDouglas Gilbert 			    size_t count)
5901cbf67842SDouglas Gilbert {
5902c4837394SDouglas Gilbert 	int ndelay, res;
5903cbf67842SDouglas Gilbert 
5904cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5905c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5906cbf67842SDouglas Gilbert 		res = count;
5907773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5908c4837394SDouglas Gilbert 			int j, k;
5909c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5910c4837394SDouglas Gilbert 
5911c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5912c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5913c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5914c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5915c4837394SDouglas Gilbert 						   sdebug_max_queue);
5916c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5917c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5918c4837394SDouglas Gilbert 					break;
5919c4837394SDouglas Gilbert 				}
5920c4837394SDouglas Gilbert 			}
5921c4837394SDouglas Gilbert 			if (res > 0) {
5922773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5923c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5924c2206098SDouglas Gilbert 							: DEF_JDELAY;
5925cbf67842SDouglas Gilbert 			}
5926c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5927cbf67842SDouglas Gilbert 		}
5928cbf67842SDouglas Gilbert 		return res;
5929cbf67842SDouglas Gilbert 	}
5930cbf67842SDouglas Gilbert 	return -EINVAL;
5931cbf67842SDouglas Gilbert }
5932cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5933cbf67842SDouglas Gilbert 
593482069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
59351da177e4SLinus Torvalds {
5936773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
59371da177e4SLinus Torvalds }
59381da177e4SLinus Torvalds 
593982069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
594082069379SAkinobu Mita 			  size_t count)
59411da177e4SLinus Torvalds {
59421da177e4SLinus Torvalds 	int opts;
59431da177e4SLinus Torvalds 	char work[20];
59441da177e4SLinus Torvalds 
59459a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
59469a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
59479a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
59481da177e4SLinus Torvalds 				goto opts_done;
59491da177e4SLinus Torvalds 		} else {
59509a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
59511da177e4SLinus Torvalds 				goto opts_done;
59521da177e4SLinus Torvalds 		}
59531da177e4SLinus Torvalds 	}
59541da177e4SLinus Torvalds 	return -EINVAL;
59551da177e4SLinus Torvalds opts_done:
5956773642d9SDouglas Gilbert 	sdebug_opts = opts;
5957773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5958773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5959c4837394SDouglas Gilbert 	tweak_cmnd_count();
59601da177e4SLinus Torvalds 	return count;
59611da177e4SLinus Torvalds }
596282069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
59631da177e4SLinus Torvalds 
596482069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
59651da177e4SLinus Torvalds {
5966773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
59671da177e4SLinus Torvalds }
596882069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
596982069379SAkinobu Mita 			   size_t count)
59701da177e4SLinus Torvalds {
59711da177e4SLinus Torvalds 	int n;
59721da177e4SLinus Torvalds 
5973f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5974f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5975f0d1cf93SDouglas Gilbert 		return -EINVAL;
5976f0d1cf93SDouglas Gilbert 
59771da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5978f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
5979f0d1cf93SDouglas Gilbert 			return -EINVAL;
5980773642d9SDouglas Gilbert 		sdebug_ptype = n;
59811da177e4SLinus Torvalds 		return count;
59821da177e4SLinus Torvalds 	}
59831da177e4SLinus Torvalds 	return -EINVAL;
59841da177e4SLinus Torvalds }
598582069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
59861da177e4SLinus Torvalds 
598782069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
59881da177e4SLinus Torvalds {
5989773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
59901da177e4SLinus Torvalds }
599182069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
599282069379SAkinobu Mita 			    size_t count)
59931da177e4SLinus Torvalds {
59941da177e4SLinus Torvalds 	int n;
59951da177e4SLinus Torvalds 
59961da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5997773642d9SDouglas Gilbert 		sdebug_dsense = n;
59981da177e4SLinus Torvalds 		return count;
59991da177e4SLinus Torvalds 	}
60001da177e4SLinus Torvalds 	return -EINVAL;
60011da177e4SLinus Torvalds }
600282069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
60031da177e4SLinus Torvalds 
600482069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
600523183910SDouglas Gilbert {
6006773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
600723183910SDouglas Gilbert }
600882069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
600982069379SAkinobu Mita 			     size_t count)
601023183910SDouglas Gilbert {
601187c715dcSDouglas Gilbert 	int n, idx;
601223183910SDouglas Gilbert 
601323183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
601487c715dcSDouglas Gilbert 		bool want_store = (n == 0);
601587c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
601687c715dcSDouglas Gilbert 
6017cbf67842SDouglas Gilbert 		n = (n > 0);
6018773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
601987c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
602087c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6021cbf67842SDouglas Gilbert 
602287c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
602387c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
602487c715dcSDouglas Gilbert 				idx = sdebug_add_store();
602587c715dcSDouglas Gilbert 				if (idx < 0)
602687c715dcSDouglas Gilbert 					return idx;
602787c715dcSDouglas Gilbert 			} else {
602887c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
602987c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
603087c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6031cbf67842SDouglas Gilbert 			}
603287c715dcSDouglas Gilbert 			/* make all hosts use same store */
603387c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
603487c715dcSDouglas Gilbert 					    host_list) {
603587c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
603687c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
603787c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
603887c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
603987c715dcSDouglas Gilbert 				}
604087c715dcSDouglas Gilbert 			}
604187c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
604287c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
604387c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6044cbf67842SDouglas Gilbert 		}
6045773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
604623183910SDouglas Gilbert 		return count;
604723183910SDouglas Gilbert 	}
604823183910SDouglas Gilbert 	return -EINVAL;
604923183910SDouglas Gilbert }
605082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
605123183910SDouglas Gilbert 
605282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6053c65b1445SDouglas Gilbert {
6054773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6055c65b1445SDouglas Gilbert }
605682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
605782069379SAkinobu Mita 			      size_t count)
6058c65b1445SDouglas Gilbert {
6059c65b1445SDouglas Gilbert 	int n;
6060c65b1445SDouglas Gilbert 
6061c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6062773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6063c65b1445SDouglas Gilbert 		return count;
6064c65b1445SDouglas Gilbert 	}
6065c65b1445SDouglas Gilbert 	return -EINVAL;
6066c65b1445SDouglas Gilbert }
606782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6068c65b1445SDouglas Gilbert 
606982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
60701da177e4SLinus Torvalds {
6071773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60721da177e4SLinus Torvalds }
607382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
607482069379SAkinobu Mita 			      size_t count)
60751da177e4SLinus Torvalds {
60761da177e4SLinus Torvalds 	int n;
60771da177e4SLinus Torvalds 
60781da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6079773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
60801da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
60811da177e4SLinus Torvalds 		return count;
60821da177e4SLinus Torvalds 	}
60831da177e4SLinus Torvalds 	return -EINVAL;
60841da177e4SLinus Torvalds }
608582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
60861da177e4SLinus Torvalds 
608782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
60881da177e4SLinus Torvalds {
6089773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
60901da177e4SLinus Torvalds }
609182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
60921da177e4SLinus Torvalds 
609387c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
609487c715dcSDouglas Gilbert {
609587c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
609687c715dcSDouglas Gilbert }
609787c715dcSDouglas Gilbert 
609887c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
609987c715dcSDouglas Gilbert 				    size_t count)
610087c715dcSDouglas Gilbert {
610187c715dcSDouglas Gilbert 	bool v;
610287c715dcSDouglas Gilbert 
610387c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
610487c715dcSDouglas Gilbert 		return -EINVAL;
610587c715dcSDouglas Gilbert 
610687c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
610787c715dcSDouglas Gilbert 	return count;
610887c715dcSDouglas Gilbert }
610987c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
611087c715dcSDouglas Gilbert 
611182069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
61121da177e4SLinus Torvalds {
6113773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
61141da177e4SLinus Torvalds }
611582069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
61161da177e4SLinus Torvalds 
611782069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
61181da177e4SLinus Torvalds {
6119773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
61201da177e4SLinus Torvalds }
612182069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
612282069379SAkinobu Mita 			       size_t count)
61231da177e4SLinus Torvalds {
61241da177e4SLinus Torvalds 	int nth;
61253a90a63dSDouglas Gilbert 	char work[20];
61261da177e4SLinus Torvalds 
61273a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61283a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61293a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
61303a90a63dSDouglas Gilbert 				goto every_nth_done;
61313a90a63dSDouglas Gilbert 		} else {
61323a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
61333a90a63dSDouglas Gilbert 				goto every_nth_done;
61343a90a63dSDouglas Gilbert 		}
61353a90a63dSDouglas Gilbert 	}
61363a90a63dSDouglas Gilbert 	return -EINVAL;
61373a90a63dSDouglas Gilbert 
61383a90a63dSDouglas Gilbert every_nth_done:
6139773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6140c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6141c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6142c4837394SDouglas Gilbert 		sdebug_statistics = true;
6143c4837394SDouglas Gilbert 	}
6144c4837394SDouglas Gilbert 	tweak_cmnd_count();
61451da177e4SLinus Torvalds 	return count;
61461da177e4SLinus Torvalds }
614782069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
61481da177e4SLinus Torvalds 
6149ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6150ad0c7775SDouglas Gilbert {
6151ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6152ad0c7775SDouglas Gilbert }
6153ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6154ad0c7775SDouglas Gilbert 				size_t count)
6155ad0c7775SDouglas Gilbert {
6156ad0c7775SDouglas Gilbert 	int n;
6157ad0c7775SDouglas Gilbert 	bool changed;
6158ad0c7775SDouglas Gilbert 
6159ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6160ad0c7775SDouglas Gilbert 		return -EINVAL;
6161ad0c7775SDouglas Gilbert 	if (n >= 0) {
6162ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6163ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6164ad0c7775SDouglas Gilbert 			return -EINVAL;
6165ad0c7775SDouglas Gilbert 		}
6166ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6167ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6168ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6169ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6170ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6171ad0c7775SDouglas Gilbert 
6172ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6173ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6174ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6175ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6176ad0c7775SDouglas Gilbert 				}
6177ad0c7775SDouglas Gilbert 			}
6178ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6179ad0c7775SDouglas Gilbert 		}
6180ad0c7775SDouglas Gilbert 		return count;
6181ad0c7775SDouglas Gilbert 	}
6182ad0c7775SDouglas Gilbert 	return -EINVAL;
6183ad0c7775SDouglas Gilbert }
6184ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6185ad0c7775SDouglas Gilbert 
618682069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
61871da177e4SLinus Torvalds {
6188773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
61891da177e4SLinus Torvalds }
619082069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
619182069379SAkinobu Mita 			      size_t count)
61921da177e4SLinus Torvalds {
61931da177e4SLinus Torvalds 	int n;
619419c8ead7SEwan D. Milne 	bool changed;
61951da177e4SLinus Torvalds 
61961da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
61978d039e22SDouglas Gilbert 		if (n > 256) {
61988d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
61998d039e22SDouglas Gilbert 			return -EINVAL;
62008d039e22SDouglas Gilbert 		}
6201773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6202773642d9SDouglas Gilbert 		sdebug_max_luns = n;
62031da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6204773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
620519c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
620619c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
620719c8ead7SEwan D. Milne 
620819c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
620919c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
621019c8ead7SEwan D. Milne 					    host_list) {
621119c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
621219c8ead7SEwan D. Milne 						    dev_list) {
621319c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
621419c8ead7SEwan D. Milne 						dp->uas_bm);
621519c8ead7SEwan D. Milne 				}
621619c8ead7SEwan D. Milne 			}
621719c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
621819c8ead7SEwan D. Milne 		}
62191da177e4SLinus Torvalds 		return count;
62201da177e4SLinus Torvalds 	}
62211da177e4SLinus Torvalds 	return -EINVAL;
62221da177e4SLinus Torvalds }
622382069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
62241da177e4SLinus Torvalds 
622582069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
622678d4e5a0SDouglas Gilbert {
6227773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
622878d4e5a0SDouglas Gilbert }
6229cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6230cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
623182069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
623282069379SAkinobu Mita 			       size_t count)
623378d4e5a0SDouglas Gilbert {
6234c4837394SDouglas Gilbert 	int j, n, k, a;
6235c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
623678d4e5a0SDouglas Gilbert 
623778d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6238c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6239c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6240c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6241c4837394SDouglas Gilbert 		k = 0;
6242c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6243c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6244c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6245c4837394SDouglas Gilbert 			if (a > k)
6246c4837394SDouglas Gilbert 				k = a;
6247c4837394SDouglas Gilbert 		}
6248773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6249c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6250cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6251cbf67842SDouglas Gilbert 		else if (k >= n)
6252cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6253cbf67842SDouglas Gilbert 		else
6254cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6255c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
625678d4e5a0SDouglas Gilbert 		return count;
625778d4e5a0SDouglas Gilbert 	}
625878d4e5a0SDouglas Gilbert 	return -EINVAL;
625978d4e5a0SDouglas Gilbert }
626082069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
626178d4e5a0SDouglas Gilbert 
6262c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6263c10fa55fSJohn Garry {
6264c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6265c10fa55fSJohn Garry }
6266c10fa55fSJohn Garry 
6267c10fa55fSJohn Garry /*
6268c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6269c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6270c10fa55fSJohn Garry  */
6271c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6272c10fa55fSJohn Garry 
627382069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
627478d4e5a0SDouglas Gilbert {
6275773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
627678d4e5a0SDouglas Gilbert }
627782069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
627878d4e5a0SDouglas Gilbert 
627982069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
62801da177e4SLinus Torvalds {
6281773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
62821da177e4SLinus Torvalds }
628382069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
62841da177e4SLinus Torvalds 
628582069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6286c65b1445SDouglas Gilbert {
6287773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6288c65b1445SDouglas Gilbert }
628982069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
629082069379SAkinobu Mita 				size_t count)
6291c65b1445SDouglas Gilbert {
6292c65b1445SDouglas Gilbert 	int n;
62930d01c5dfSDouglas Gilbert 	bool changed;
6294c65b1445SDouglas Gilbert 
6295f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6296f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6297f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6298f0d1cf93SDouglas Gilbert 
6299c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6300773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6301773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
630228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
63030d01c5dfSDouglas Gilbert 		if (changed) {
63040d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
63050d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
630628898873SFUJITA Tomonori 
63074bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
63080d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
63090d01c5dfSDouglas Gilbert 					    host_list) {
63100d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
63110d01c5dfSDouglas Gilbert 						    dev_list) {
63120d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
63130d01c5dfSDouglas Gilbert 						dp->uas_bm);
63140d01c5dfSDouglas Gilbert 				}
63150d01c5dfSDouglas Gilbert 			}
63164bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
63170d01c5dfSDouglas Gilbert 		}
6318c65b1445SDouglas Gilbert 		return count;
6319c65b1445SDouglas Gilbert 	}
6320c65b1445SDouglas Gilbert 	return -EINVAL;
6321c65b1445SDouglas Gilbert }
632282069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6323c65b1445SDouglas Gilbert 
632482069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
63251da177e4SLinus Torvalds {
632687c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
632787c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
63281da177e4SLinus Torvalds }
63291da177e4SLinus Torvalds 
633082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
633182069379SAkinobu Mita 			      size_t count)
63321da177e4SLinus Torvalds {
633387c715dcSDouglas Gilbert 	bool found;
633487c715dcSDouglas Gilbert 	unsigned long idx;
633587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
633687c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
63371da177e4SLinus Torvalds 	int delta_hosts;
63381da177e4SLinus Torvalds 
6339f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
63401da177e4SLinus Torvalds 		return -EINVAL;
63411da177e4SLinus Torvalds 	if (delta_hosts > 0) {
63421da177e4SLinus Torvalds 		do {
634387c715dcSDouglas Gilbert 			found = false;
634487c715dcSDouglas Gilbert 			if (want_phs) {
634587c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
634687c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
634787c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
634887c715dcSDouglas Gilbert 					found = true;
634987c715dcSDouglas Gilbert 					break;
635087c715dcSDouglas Gilbert 				}
635187c715dcSDouglas Gilbert 				if (found)	/* re-use case */
635287c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
635387c715dcSDouglas Gilbert 				else
635487c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
635587c715dcSDouglas Gilbert 			} else {
635687c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
635787c715dcSDouglas Gilbert 			}
63581da177e4SLinus Torvalds 		} while (--delta_hosts);
63591da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
63601da177e4SLinus Torvalds 		do {
636187c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
63621da177e4SLinus Torvalds 		} while (++delta_hosts);
63631da177e4SLinus Torvalds 	}
63641da177e4SLinus Torvalds 	return count;
63651da177e4SLinus Torvalds }
636682069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
63671da177e4SLinus Torvalds 
636882069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
636923183910SDouglas Gilbert {
6370773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
637123183910SDouglas Gilbert }
637282069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
637382069379SAkinobu Mita 				    size_t count)
637423183910SDouglas Gilbert {
637523183910SDouglas Gilbert 	int n;
637623183910SDouglas Gilbert 
637723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6378773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
637923183910SDouglas Gilbert 		return count;
638023183910SDouglas Gilbert 	}
638123183910SDouglas Gilbert 	return -EINVAL;
638223183910SDouglas Gilbert }
638382069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
638423183910SDouglas Gilbert 
6385c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6386c4837394SDouglas Gilbert {
6387c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6388c4837394SDouglas Gilbert }
6389c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6390c4837394SDouglas Gilbert 				size_t count)
6391c4837394SDouglas Gilbert {
6392c4837394SDouglas Gilbert 	int n;
6393c4837394SDouglas Gilbert 
6394c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6395c4837394SDouglas Gilbert 		if (n > 0)
6396c4837394SDouglas Gilbert 			sdebug_statistics = true;
6397c4837394SDouglas Gilbert 		else {
6398c4837394SDouglas Gilbert 			clear_queue_stats();
6399c4837394SDouglas Gilbert 			sdebug_statistics = false;
6400c4837394SDouglas Gilbert 		}
6401c4837394SDouglas Gilbert 		return count;
6402c4837394SDouglas Gilbert 	}
6403c4837394SDouglas Gilbert 	return -EINVAL;
6404c4837394SDouglas Gilbert }
6405c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6406c4837394SDouglas Gilbert 
640782069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6408597136abSMartin K. Petersen {
6409773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6410597136abSMartin K. Petersen }
641182069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6412597136abSMartin K. Petersen 
6413c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6414c4837394SDouglas Gilbert {
6415c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6416c4837394SDouglas Gilbert }
6417c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6418c4837394SDouglas Gilbert 
641982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6420c6a44287SMartin K. Petersen {
6421773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6422c6a44287SMartin K. Petersen }
642382069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6424c6a44287SMartin K. Petersen 
642582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6426c6a44287SMartin K. Petersen {
6427773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6428c6a44287SMartin K. Petersen }
642982069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6430c6a44287SMartin K. Petersen 
643182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6432c6a44287SMartin K. Petersen {
6433773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6434c6a44287SMartin K. Petersen }
643582069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6436c6a44287SMartin K. Petersen 
643782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6438c6a44287SMartin K. Petersen {
6439773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6440c6a44287SMartin K. Petersen }
644182069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6442c6a44287SMartin K. Petersen 
644382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
644444d92694SMartin K. Petersen {
644587c715dcSDouglas Gilbert 	ssize_t count = 0;
644644d92694SMartin K. Petersen 
64475b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
644844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
644944d92694SMartin K. Petersen 				 sdebug_store_sectors);
645044d92694SMartin K. Petersen 
645187c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
645287c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
645387c715dcSDouglas Gilbert 
645487c715dcSDouglas Gilbert 		if (sip)
6455c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
645687c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
645787c715dcSDouglas Gilbert 	}
645844d92694SMartin K. Petersen 	buf[count++] = '\n';
6459c7badc90STejun Heo 	buf[count] = '\0';
646044d92694SMartin K. Petersen 
646144d92694SMartin K. Petersen 	return count;
646244d92694SMartin K. Petersen }
646382069379SAkinobu Mita static DRIVER_ATTR_RO(map);
646444d92694SMartin K. Petersen 
64650c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
64660c4bc91dSDouglas Gilbert {
64670c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
64680c4bc91dSDouglas Gilbert }
64690c4bc91dSDouglas Gilbert 
64700c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
64710c4bc91dSDouglas Gilbert 			    size_t count)
64720c4bc91dSDouglas Gilbert {
64730c4bc91dSDouglas Gilbert 	bool v;
64740c4bc91dSDouglas Gilbert 
64750c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
64760c4bc91dSDouglas Gilbert 		return -EINVAL;
64770c4bc91dSDouglas Gilbert 
64780c4bc91dSDouglas Gilbert 	sdebug_random = v;
64790c4bc91dSDouglas Gilbert 	return count;
64800c4bc91dSDouglas Gilbert }
64810c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
64820c4bc91dSDouglas Gilbert 
648382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6484d986788bSMartin Pitt {
6485773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6486d986788bSMartin Pitt }
648782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
648882069379SAkinobu Mita 			       size_t count)
6489d986788bSMartin Pitt {
6490d986788bSMartin Pitt 	int n;
6491d986788bSMartin Pitt 
6492d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6493773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6494d986788bSMartin Pitt 		return count;
6495d986788bSMartin Pitt 	}
6496d986788bSMartin Pitt 	return -EINVAL;
6497d986788bSMartin Pitt }
649882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6499d986788bSMartin Pitt 
6500cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6501cbf67842SDouglas Gilbert {
6502773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6503cbf67842SDouglas Gilbert }
6504185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6505cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6506cbf67842SDouglas Gilbert 			       size_t count)
6507cbf67842SDouglas Gilbert {
6508185dd232SDouglas Gilbert 	int n;
6509cbf67842SDouglas Gilbert 
6510cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6511185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6512185dd232SDouglas Gilbert 		return count;
6513cbf67842SDouglas Gilbert 	}
6514cbf67842SDouglas Gilbert 	return -EINVAL;
6515cbf67842SDouglas Gilbert }
6516cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6517cbf67842SDouglas Gilbert 
6518c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6519c2248fc9SDouglas Gilbert {
6520773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6521c2248fc9SDouglas Gilbert }
6522c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6523c2248fc9SDouglas Gilbert 			    size_t count)
6524c2248fc9SDouglas Gilbert {
6525c2248fc9SDouglas Gilbert 	int n;
6526c2248fc9SDouglas Gilbert 
6527c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6528773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6529c2248fc9SDouglas Gilbert 		return count;
6530c2248fc9SDouglas Gilbert 	}
6531c2248fc9SDouglas Gilbert 	return -EINVAL;
6532c2248fc9SDouglas Gilbert }
6533c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6534c2248fc9SDouglas Gilbert 
653509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
653609ba24c1SDouglas Gilbert {
653709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
653809ba24c1SDouglas Gilbert }
653909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
654009ba24c1SDouglas Gilbert 
65419b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
65429b760fd8SDouglas Gilbert {
65439b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
65449b760fd8SDouglas Gilbert }
65459b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
65469b760fd8SDouglas Gilbert 			     size_t count)
65479b760fd8SDouglas Gilbert {
65489b760fd8SDouglas Gilbert 	int ret, n;
65499b760fd8SDouglas Gilbert 
65509b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
65519b760fd8SDouglas Gilbert 	if (ret)
65529b760fd8SDouglas Gilbert 		return ret;
65539b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
65549b760fd8SDouglas Gilbert 	all_config_cdb_len();
65559b760fd8SDouglas Gilbert 	return count;
65569b760fd8SDouglas Gilbert }
65579b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
65589b760fd8SDouglas Gilbert 
65599267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
65609267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
65619267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
65629267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
65639267e0ebSDouglas Gilbert };
65649267e0ebSDouglas Gilbert 
65659267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
65669267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
65679267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
65689267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
65699267e0ebSDouglas Gilbert };
65709267e0ebSDouglas Gilbert 
65719267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
65729267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
65739267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
65749267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
65759267e0ebSDouglas Gilbert };
65769267e0ebSDouglas Gilbert 
65779267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
65789267e0ebSDouglas Gilbert {
65799267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
65809267e0ebSDouglas Gilbert 
65819267e0ebSDouglas Gilbert 	if (res < 0) {
65829267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
65839267e0ebSDouglas Gilbert 		if (res < 0) {
65849267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
658547742bdeSDan Carpenter 			if (res < 0)
65869267e0ebSDouglas Gilbert 				return -EINVAL;
65879267e0ebSDouglas Gilbert 		}
65889267e0ebSDouglas Gilbert 	}
65899267e0ebSDouglas Gilbert 	return res;
65909267e0ebSDouglas Gilbert }
65919267e0ebSDouglas Gilbert 
65929267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
65939267e0ebSDouglas Gilbert {
65949267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
65959267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
65969267e0ebSDouglas Gilbert }
65979267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6598cbf67842SDouglas Gilbert 
6599fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6600fc13638aSDouglas Gilbert {
6601fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6602fc13638aSDouglas Gilbert }
6603fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6604fc13638aSDouglas Gilbert 
660582069379SAkinobu Mita /* Note: The following array creates attribute files in the
660623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
660723183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
660823183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
660987c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
661023183910SDouglas Gilbert  */
66116ecaff7fSRandy Dunlap 
661282069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
661382069379SAkinobu Mita 	&driver_attr_delay.attr,
661482069379SAkinobu Mita 	&driver_attr_opts.attr,
661582069379SAkinobu Mita 	&driver_attr_ptype.attr,
661682069379SAkinobu Mita 	&driver_attr_dsense.attr,
661782069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6618c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
661982069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
662082069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
662182069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
662282069379SAkinobu Mita 	&driver_attr_num_parts.attr,
662382069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6624ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
662582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
662682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
662782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
662882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
662982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
663082069379SAkinobu Mita 	&driver_attr_add_host.attr,
663187c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
663282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
663382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6634c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6635c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
663682069379SAkinobu Mita 	&driver_attr_dix.attr,
663782069379SAkinobu Mita 	&driver_attr_dif.attr,
663882069379SAkinobu Mita 	&driver_attr_guard.attr,
663982069379SAkinobu Mita 	&driver_attr_ato.attr,
664082069379SAkinobu Mita 	&driver_attr_map.attr,
66410c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
664282069379SAkinobu Mita 	&driver_attr_removable.attr,
6643cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6644cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6645c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
664609ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
66479b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6648fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
66499267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
665082069379SAkinobu Mita 	NULL,
665182069379SAkinobu Mita };
665282069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
66531da177e4SLinus Torvalds 
665411ddcecaSAkinobu Mita static struct device *pseudo_primary;
66558dea0d02SFUJITA Tomonori 
66561da177e4SLinus Torvalds static int __init scsi_debug_init(void)
66571da177e4SLinus Torvalds {
665887c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
66595f2578e5SFUJITA Tomonori 	unsigned long sz;
666087c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
666187c715dcSDouglas Gilbert 	int idx = -1;
66621da177e4SLinus Torvalds 
666387c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
666487c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6665cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6666cbf67842SDouglas Gilbert 
6667773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6668c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6669773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6670773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6671c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6672cbf67842SDouglas Gilbert 
6673773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6674597136abSMartin K. Petersen 	case  512:
6675597136abSMartin K. Petersen 	case 1024:
6676597136abSMartin K. Petersen 	case 2048:
6677597136abSMartin K. Petersen 	case 4096:
6678597136abSMartin K. Petersen 		break;
6679597136abSMartin K. Petersen 	default:
6680773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6681597136abSMartin K. Petersen 		return -EINVAL;
6682597136abSMartin K. Petersen 	}
6683597136abSMartin K. Petersen 
6684773642d9SDouglas Gilbert 	switch (sdebug_dif) {
66858475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6686f46eb0e9SDouglas Gilbert 		break;
66878475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
66888475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
66898475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6690f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6691c6a44287SMartin K. Petersen 		break;
6692c6a44287SMartin K. Petersen 
6693c6a44287SMartin K. Petersen 	default:
6694c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6695c6a44287SMartin K. Petersen 		return -EINVAL;
6696c6a44287SMartin K. Petersen 	}
6697c6a44287SMartin K. Petersen 
6698aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6699aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6700aa5334c4SMaurizio Lombardi 		return -EINVAL;
6701aa5334c4SMaurizio Lombardi 	}
6702aa5334c4SMaurizio Lombardi 
6703773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6704c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6705c6a44287SMartin K. Petersen 		return -EINVAL;
6706c6a44287SMartin K. Petersen 	}
6707c6a44287SMartin K. Petersen 
6708773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6709c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6710c6a44287SMartin K. Petersen 		return -EINVAL;
6711c6a44287SMartin K. Petersen 	}
6712c6a44287SMartin K. Petersen 
6713773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6714773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6715ea61fca5SMartin K. Petersen 		return -EINVAL;
6716ea61fca5SMartin K. Petersen 	}
6717ad0c7775SDouglas Gilbert 
6718ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6719ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6720ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6721ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6722ad0c7775SDouglas Gilbert 	}
6723ad0c7775SDouglas Gilbert 
67248d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6725ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6726ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
67278d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
67288d039e22SDouglas Gilbert 		}
6729ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6730ad0c7775SDouglas Gilbert 	}
6731ea61fca5SMartin K. Petersen 
6732773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6733773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6734ea61fca5SMartin K. Petersen 		return -EINVAL;
6735ea61fca5SMartin K. Petersen 	}
6736ea61fca5SMartin K. Petersen 
6737c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6738c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6739c4837394SDouglas Gilbert 		return -EINVAL;
6740c4837394SDouglas Gilbert 	}
6741c87bf24cSJohn Garry 
6742c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6743c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6744c87bf24cSJohn Garry 		return -EINVAL;
6745c87bf24cSJohn Garry 	}
6746c87bf24cSJohn Garry 
6747c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6748c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6749c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6750c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6751c10fa55fSJohn Garry 		return -EINVAL;
6752c10fa55fSJohn Garry 	}
6753c10fa55fSJohn Garry 
6754c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6755c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6756c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6757c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6758c10fa55fSJohn Garry 			sdebug_max_queue);
6759c10fa55fSJohn Garry 	}
6760c10fa55fSJohn Garry 
6761c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6762c4837394SDouglas Gilbert 			       GFP_KERNEL);
6763c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6764c4837394SDouglas Gilbert 		return -ENOMEM;
6765c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6766c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6767c4837394SDouglas Gilbert 
6768f0d1cf93SDouglas Gilbert 	/*
67699267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
67709267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6771f0d1cf93SDouglas Gilbert 	 */
67729267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
67739267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
67749267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
67759267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
67769267e0ebSDouglas Gilbert 		if (k < 0) {
67779267e0ebSDouglas Gilbert 			ret = k;
67783b01d7eaSDinghao Liu 			goto free_q_arr;
67799267e0ebSDouglas Gilbert 		}
67809267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
67819267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
67829267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
678364e14eceSDamien Le Moal 		case BLK_ZONED_HA:
67849267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
67859267e0ebSDouglas Gilbert 			break;
67869267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
67879267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
67889267e0ebSDouglas Gilbert 			break;
67899267e0ebSDouglas Gilbert 		default:
67909267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
67913b01d7eaSDinghao Liu 			ret = -EINVAL;
67923b01d7eaSDinghao Liu 			goto free_q_arr;
67939267e0ebSDouglas Gilbert 		}
67949267e0ebSDouglas Gilbert 	}
67959267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6796f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
67979267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
67989267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
67999267e0ebSDouglas Gilbert 	}
6800f0d1cf93SDouglas Gilbert 
68019267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
68029267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6803773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6804773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6805773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6806773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
680728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
68081da177e4SLinus Torvalds 
68091da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
68101da177e4SLinus Torvalds 	sdebug_heads = 8;
68111da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6812773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
68131da177e4SLinus Torvalds 		sdebug_heads = 64;
6814773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6815fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
68161da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
68171da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
68181da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
68191da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
68201da177e4SLinus Torvalds 		sdebug_heads = 255;
68211da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
68221da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
68231da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
68241da177e4SLinus Torvalds 	}
68255b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6826773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6827773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
68286014759cSMartin K. Petersen 
6829773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6830773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
68316014759cSMartin K. Petersen 
6832773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6833773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
68346014759cSMartin K. Petersen 
6835773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6836773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6837773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6838c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6839c4837394SDouglas Gilbert 			ret = -EINVAL;
684087c715dcSDouglas Gilbert 			goto free_q_arr;
684144d92694SMartin K. Petersen 		}
684244d92694SMartin K. Petersen 	}
684387c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
684487c715dcSDouglas Gilbert 	if (want_store) {
684587c715dcSDouglas Gilbert 		idx = sdebug_add_store();
684687c715dcSDouglas Gilbert 		if (idx < 0) {
684787c715dcSDouglas Gilbert 			ret = idx;
684887c715dcSDouglas Gilbert 			goto free_q_arr;
684987c715dcSDouglas Gilbert 		}
685044d92694SMartin K. Petersen 	}
685144d92694SMartin K. Petersen 
68529b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
68539b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6854c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
68559b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
68566ecaff7fSRandy Dunlap 		goto free_vm;
68576ecaff7fSRandy Dunlap 	}
68586ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
68596ecaff7fSRandy Dunlap 	if (ret < 0) {
6860c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
68616ecaff7fSRandy Dunlap 		goto dev_unreg;
68626ecaff7fSRandy Dunlap 	}
68636ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
68646ecaff7fSRandy Dunlap 	if (ret < 0) {
6865c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
68666ecaff7fSRandy Dunlap 		goto bus_unreg;
68676ecaff7fSRandy Dunlap 	}
68681da177e4SLinus Torvalds 
686987c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6870773642d9SDouglas Gilbert 	sdebug_add_host = 0;
68711da177e4SLinus Torvalds 
687287c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
687387c715dcSDouglas Gilbert 		if (want_store && k == 0) {
687487c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
687587c715dcSDouglas Gilbert 			if (ret < 0) {
687687c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
687787c715dcSDouglas Gilbert 				       k, -ret);
687887c715dcSDouglas Gilbert 				break;
687987c715dcSDouglas Gilbert 			}
688087c715dcSDouglas Gilbert 		} else {
688187c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
688287c715dcSDouglas Gilbert 						 sdebug_per_host_store);
688387c715dcSDouglas Gilbert 			if (ret < 0) {
688487c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
68851da177e4SLinus Torvalds 				break;
68861da177e4SLinus Torvalds 			}
68871da177e4SLinus Torvalds 		}
688887c715dcSDouglas Gilbert 	}
6889773642d9SDouglas Gilbert 	if (sdebug_verbose)
689087c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6891c1287970STomas Winkler 
68921da177e4SLinus Torvalds 	return 0;
68936ecaff7fSRandy Dunlap 
68946ecaff7fSRandy Dunlap bus_unreg:
68956ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
68966ecaff7fSRandy Dunlap dev_unreg:
68979b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
68986ecaff7fSRandy Dunlap free_vm:
689987c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6900c4837394SDouglas Gilbert free_q_arr:
6901c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
69026ecaff7fSRandy Dunlap 	return ret;
69031da177e4SLinus Torvalds }
69041da177e4SLinus Torvalds 
69051da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
69061da177e4SLinus Torvalds {
690787c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
69081da177e4SLinus Torvalds 
69091da177e4SLinus Torvalds 	stop_all_queued();
69101da177e4SLinus Torvalds 	for (; k; k--)
691187c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
691252ab9768SLuis Henriques 	free_all_queued();
69131da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
69141da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
69159b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
69161da177e4SLinus Torvalds 
691787c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
691887c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
6919f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
69201da177e4SLinus Torvalds }
69211da177e4SLinus Torvalds 
69221da177e4SLinus Torvalds device_initcall(scsi_debug_init);
69231da177e4SLinus Torvalds module_exit(scsi_debug_exit);
69241da177e4SLinus Torvalds 
69251da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
69261da177e4SLinus Torvalds {
69271da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
69281da177e4SLinus Torvalds 
69291da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
69301da177e4SLinus Torvalds 	kfree(sdbg_host);
69311da177e4SLinus Torvalds }
69321da177e4SLinus Torvalds 
693387c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
693487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
69351da177e4SLinus Torvalds {
693687c715dcSDouglas Gilbert 	if (idx < 0)
693787c715dcSDouglas Gilbert 		return;
693887c715dcSDouglas Gilbert 	if (!sip) {
693987c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
694087c715dcSDouglas Gilbert 			return;
694187c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
694287c715dcSDouglas Gilbert 		if (!sip)
694387c715dcSDouglas Gilbert 			return;
694487c715dcSDouglas Gilbert 	}
694587c715dcSDouglas Gilbert 	vfree(sip->map_storep);
694687c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
694787c715dcSDouglas Gilbert 	vfree(sip->storep);
694887c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
694987c715dcSDouglas Gilbert 	kfree(sip);
695087c715dcSDouglas Gilbert }
695187c715dcSDouglas Gilbert 
695287c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
695387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
695487c715dcSDouglas Gilbert {
695587c715dcSDouglas Gilbert 	unsigned long idx;
695687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
695787c715dcSDouglas Gilbert 
695887c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
695987c715dcSDouglas Gilbert 		if (apart_from_first)
696087c715dcSDouglas Gilbert 			apart_from_first = false;
696187c715dcSDouglas Gilbert 		else
696287c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
696387c715dcSDouglas Gilbert 	}
696487c715dcSDouglas Gilbert 	if (apart_from_first)
696587c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
696687c715dcSDouglas Gilbert }
696787c715dcSDouglas Gilbert 
696887c715dcSDouglas Gilbert /*
696987c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
697087c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
697187c715dcSDouglas Gilbert  */
697287c715dcSDouglas Gilbert static int sdebug_add_store(void)
697387c715dcSDouglas Gilbert {
697487c715dcSDouglas Gilbert 	int res;
697587c715dcSDouglas Gilbert 	u32 n_idx;
697687c715dcSDouglas Gilbert 	unsigned long iflags;
697787c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
697887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
697987c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
698087c715dcSDouglas Gilbert 
698187c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
698287c715dcSDouglas Gilbert 	if (!sip)
698387c715dcSDouglas Gilbert 		return -ENOMEM;
698487c715dcSDouglas Gilbert 
698587c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
698687c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
698787c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
698887c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
698987c715dcSDouglas Gilbert 		kfree(sip);
699087c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
699187c715dcSDouglas Gilbert 		return res;
699287c715dcSDouglas Gilbert 	}
699387c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
699487c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
699587c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
699687c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
699787c715dcSDouglas Gilbert 
699887c715dcSDouglas Gilbert 	res = -ENOMEM;
699987c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
700087c715dcSDouglas Gilbert 	if (!sip->storep) {
700187c715dcSDouglas Gilbert 		pr_err("user data oom\n");
700287c715dcSDouglas Gilbert 		goto err;
700387c715dcSDouglas Gilbert 	}
700487c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
700587c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
700687c715dcSDouglas Gilbert 
700787c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
700887c715dcSDouglas Gilbert 	if (sdebug_dix) {
700987c715dcSDouglas Gilbert 		int dif_size;
701087c715dcSDouglas Gilbert 
701187c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
701287c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
701387c715dcSDouglas Gilbert 
701487c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
701587c715dcSDouglas Gilbert 			sip->dif_storep);
701687c715dcSDouglas Gilbert 
701787c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
701887c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
701987c715dcSDouglas Gilbert 			goto err;
702087c715dcSDouglas Gilbert 		}
702187c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
702287c715dcSDouglas Gilbert 	}
702387c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
702487c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
702587c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
702687c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
702787c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
702887c715dcSDouglas Gilbert 
702987c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
703087c715dcSDouglas Gilbert 
703187c715dcSDouglas Gilbert 		if (!sip->map_storep) {
703287c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
703387c715dcSDouglas Gilbert 			goto err;
703487c715dcSDouglas Gilbert 		}
703587c715dcSDouglas Gilbert 
703687c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
703787c715dcSDouglas Gilbert 
703887c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
703987c715dcSDouglas Gilbert 		if (sdebug_num_parts)
704087c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
704187c715dcSDouglas Gilbert 	}
704287c715dcSDouglas Gilbert 
704387c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
704487c715dcSDouglas Gilbert 	return (int)n_idx;
704587c715dcSDouglas Gilbert err:
704687c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
704787c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
704887c715dcSDouglas Gilbert 	return res;
704987c715dcSDouglas Gilbert }
705087c715dcSDouglas Gilbert 
705187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
705287c715dcSDouglas Gilbert {
705387c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
705487c715dcSDouglas Gilbert 	int error = -ENOMEM;
70551da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
70568b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
70571da177e4SLinus Torvalds 
705824669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
705987c715dcSDouglas Gilbert 	if (!sdbg_host)
70601da177e4SLinus Torvalds 		return -ENOMEM;
706187c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
706287c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
706387c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
706487c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
70651da177e4SLinus Torvalds 
70661da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
70671da177e4SLinus Torvalds 
7068773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
70691da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
70705cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
707187c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
70721da177e4SLinus Torvalds 			goto clean;
70731da177e4SLinus Torvalds 	}
70741da177e4SLinus Torvalds 
70751da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
70761da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
70771da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
70781da177e4SLinus Torvalds 
70791da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
70809b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
70811da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
708287c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
70831da177e4SLinus Torvalds 
70841da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
70851da177e4SLinus Torvalds 	if (error)
70861da177e4SLinus Torvalds 		goto clean;
70871da177e4SLinus Torvalds 
708887c715dcSDouglas Gilbert 	++sdebug_num_hosts;
708987c715dcSDouglas Gilbert 	return 0;
70901da177e4SLinus Torvalds 
70911da177e4SLinus Torvalds clean:
70928b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
70938b40228fSFUJITA Tomonori 				 dev_list) {
70941da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7095f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
70961da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
70971da177e4SLinus Torvalds 	}
70981da177e4SLinus Torvalds 	kfree(sdbg_host);
709987c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
71001da177e4SLinus Torvalds 	return error;
71011da177e4SLinus Torvalds }
71021da177e4SLinus Torvalds 
710387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
71041da177e4SLinus Torvalds {
710587c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
710687c715dcSDouglas Gilbert 
710787c715dcSDouglas Gilbert 	if (mk_new_store) {
710887c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
710987c715dcSDouglas Gilbert 		if (ph_idx < 0)
711087c715dcSDouglas Gilbert 			return ph_idx;
711187c715dcSDouglas Gilbert 	}
711287c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
711387c715dcSDouglas Gilbert }
711487c715dcSDouglas Gilbert 
711587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
711687c715dcSDouglas Gilbert {
711787c715dcSDouglas Gilbert 	int idx = -1;
71181da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
711987c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
71201da177e4SLinus Torvalds 
71211da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
71221da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
71231da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
71241da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
712587c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
71261da177e4SLinus Torvalds 	}
712787c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
712887c715dcSDouglas Gilbert 		bool unique = true;
712987c715dcSDouglas Gilbert 
713087c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
713187c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
713287c715dcSDouglas Gilbert 				continue;
713387c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
713487c715dcSDouglas Gilbert 				unique = false;
713587c715dcSDouglas Gilbert 				break;
713687c715dcSDouglas Gilbert 			}
713787c715dcSDouglas Gilbert 		}
713887c715dcSDouglas Gilbert 		if (unique) {
713987c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
714087c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
714187c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
714287c715dcSDouglas Gilbert 		}
714387c715dcSDouglas Gilbert 	}
714487c715dcSDouglas Gilbert 	if (sdbg_host)
714587c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
71461da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
71471da177e4SLinus Torvalds 
71481da177e4SLinus Torvalds 	if (!sdbg_host)
71491da177e4SLinus Torvalds 		return;
71501da177e4SLinus Torvalds 
71511da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
715287c715dcSDouglas Gilbert 	--sdebug_num_hosts;
71531da177e4SLinus Torvalds }
71541da177e4SLinus Torvalds 
7155fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7156cbf67842SDouglas Gilbert {
7157cbf67842SDouglas Gilbert 	int num_in_q = 0;
7158cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7159cbf67842SDouglas Gilbert 
7160c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
7161cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7162cbf67842SDouglas Gilbert 	if (NULL == devip) {
7163c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
7164cbf67842SDouglas Gilbert 		return	-ENODEV;
7165cbf67842SDouglas Gilbert 	}
7166cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7167c40ecc12SChristoph Hellwig 
7168cbf67842SDouglas Gilbert 	if (qdepth < 1)
7169cbf67842SDouglas Gilbert 		qdepth = 1;
7170c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
7171c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
7172c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
7173db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
7174cbf67842SDouglas Gilbert 
7175773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7176c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7177c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7178cbf67842SDouglas Gilbert 	}
7179c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
7180cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7181cbf67842SDouglas Gilbert }
7182cbf67842SDouglas Gilbert 
7183c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7184817fd66bSDouglas Gilbert {
7185c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7186773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7187773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7188773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7189c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7190773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7191817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7192c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7193817fd66bSDouglas Gilbert 	}
7194c4837394SDouglas Gilbert 	return false;
7195817fd66bSDouglas Gilbert }
7196817fd66bSDouglas Gilbert 
7197fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7198fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7199fc13638aSDouglas Gilbert {
7200fc13638aSDouglas Gilbert 	int stopped_state;
7201fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7202fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7203fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7204fc13638aSDouglas Gilbert 
7205fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7206fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7207fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7208fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7209fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7210fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7211fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7212fc13638aSDouglas Gilbert 				return 0;
7213fc13638aSDouglas Gilbert 			}
7214fc13638aSDouglas Gilbert 		}
7215fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7216fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7217fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7218fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7219fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7220fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7221fc13638aSDouglas Gilbert 
7222fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7223fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7224fc13638aSDouglas Gilbert 			else
7225fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7226fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7227fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7228fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7229fc13638aSDouglas Gilbert 						   diff_ns);
7230fc13638aSDouglas Gilbert 			return check_condition_result;
7231fc13638aSDouglas Gilbert 		}
7232fc13638aSDouglas Gilbert 	}
7233fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7234fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7235fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7236fc13638aSDouglas Gilbert 			    my_name);
7237fc13638aSDouglas Gilbert 	return check_condition_result;
7238fc13638aSDouglas Gilbert }
7239fc13638aSDouglas Gilbert 
7240c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost)
7241c4b57d89SKashyap Desai {
7242c4b57d89SKashyap Desai 	int i, qoff;
7243c4b57d89SKashyap Desai 
7244c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7245c4b57d89SKashyap Desai 		return 0;
7246c4b57d89SKashyap Desai 
7247c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7248c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7249c4b57d89SKashyap Desai 
7250c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7251c4b57d89SKashyap Desai 
7252c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7253c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7254c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7255c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7256c4b57d89SKashyap Desai 
7257c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7258c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7259c4b57d89SKashyap Desai 			continue;
7260c4b57d89SKashyap Desai 		}
7261c4b57d89SKashyap Desai 
7262c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7263c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7264c4b57d89SKashyap Desai 
7265c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7266c4b57d89SKashyap Desai 	}
7267c4b57d89SKashyap Desai 
7268c4b57d89SKashyap Desai 	return 0;
7269c4b57d89SKashyap Desai 
7270c4b57d89SKashyap Desai }
7271c4b57d89SKashyap Desai 
7272c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7273c4b57d89SKashyap Desai {
72744a0c6f43SDouglas Gilbert 	bool first;
72754a0c6f43SDouglas Gilbert 	bool retiring = false;
72764a0c6f43SDouglas Gilbert 	int num_entries = 0;
72774a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7278c4b57d89SKashyap Desai 	unsigned long iflags;
72794a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7280c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7281c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7282c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7283c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
72844a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7285c4b57d89SKashyap Desai 
7286c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
7287c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
72884a0c6f43SDouglas Gilbert 
72894a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
72904a0c6f43SDouglas Gilbert 		if (first) {
7291c4b57d89SKashyap Desai 			qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
72924a0c6f43SDouglas Gilbert 			first = false;
72934a0c6f43SDouglas Gilbert 		} else {
72944a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
72954a0c6f43SDouglas Gilbert 		}
72964a0c6f43SDouglas Gilbert 		if (unlikely(qc_idx >= sdebug_max_queue))
72974a0c6f43SDouglas Gilbert 			break;
7298c4b57d89SKashyap Desai 
7299c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
73004a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
73014a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
73024a0c6f43SDouglas Gilbert 			continue;
7303c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7304c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
73054a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7306c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
73074a0c6f43SDouglas Gilbert 			break;
7308c4b57d89SKashyap Desai 		}
73094a0c6f43SDouglas Gilbert 		if (sd_dp->defer_t == SDEB_DEFER_POLL) {
73104a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
73114a0c6f43SDouglas Gilbert 				continue;
73124a0c6f43SDouglas Gilbert 
73134a0c6f43SDouglas Gilbert 		} else		/* ignoring non REQ_HIPRI requests */
73144a0c6f43SDouglas Gilbert 			continue;
7315c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7316c4b57d89SKashyap Desai 		if (likely(devip))
7317c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7318c4b57d89SKashyap Desai 		else
7319c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7320c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
73214a0c6f43SDouglas Gilbert 			retiring = true;
7322c4b57d89SKashyap Desai 
7323c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7324c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
73254a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7326c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
73274a0c6f43SDouglas Gilbert 			break;
7328c4b57d89SKashyap Desai 		}
7329c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7330c4b57d89SKashyap Desai 			int k, retval;
7331c4b57d89SKashyap Desai 
7332c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7333c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7334c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
73354a0c6f43SDouglas Gilbert 				break;
7336c4b57d89SKashyap Desai 			}
7337c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7338c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7339c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7340c4b57d89SKashyap Desai 			else
7341c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7342c4b57d89SKashyap Desai 		}
73434a0c6f43SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_NONE;
7344c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
7345c4b57d89SKashyap Desai 		scp->scsi_done(scp); /* callback to mid level */
73464a0c6f43SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7347c4b57d89SKashyap Desai 		num_entries++;
73484a0c6f43SDouglas Gilbert 	}
7349c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
73504a0c6f43SDouglas Gilbert 	if (num_entries > 0)
73514a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7352c4b57d89SKashyap Desai 	return num_entries;
7353c4b57d89SKashyap Desai }
7354c4b57d89SKashyap Desai 
7355fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7356fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7357c2248fc9SDouglas Gilbert {
7358c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7359c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7360c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7361c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7362c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7363c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7364c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7365f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7366c2248fc9SDouglas Gilbert 	int k, na;
7367c2248fc9SDouglas Gilbert 	int errsts = 0;
7368ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7369c2248fc9SDouglas Gilbert 	u32 flags;
7370c2248fc9SDouglas Gilbert 	u16 sa;
7371c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7372c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
73733a90a63dSDouglas Gilbert 	bool inject_now;
7374c2248fc9SDouglas Gilbert 
7375c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
73763a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7377c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
73783a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
73793a90a63dSDouglas Gilbert 	} else {
73803a90a63dSDouglas Gilbert 		inject_now = false;
73813a90a63dSDouglas Gilbert 	}
7382f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7383f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7384c2248fc9SDouglas Gilbert 		char b[120];
7385c2248fc9SDouglas Gilbert 		int n, len, sb;
7386c2248fc9SDouglas Gilbert 
7387c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7388c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7389c2248fc9SDouglas Gilbert 		if (len > 32)
7390c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7391c2248fc9SDouglas Gilbert 		else {
7392c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7393c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7394c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7395c2248fc9SDouglas Gilbert 		}
7396458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7397458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
7398c2248fc9SDouglas Gilbert 	}
73993a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
74007ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
740134d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7402ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7403f46eb0e9SDouglas Gilbert 		goto err_out;
7404c2248fc9SDouglas Gilbert 
7405c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7406c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7407c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7408f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7409f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7410c2248fc9SDouglas Gilbert 		if (NULL == devip)
7411f46eb0e9SDouglas Gilbert 			goto err_out;
7412c2248fc9SDouglas Gilbert 	}
74133a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
74143a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
74153a90a63dSDouglas Gilbert 
7416c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7417c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7418c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7419c2248fc9SDouglas Gilbert 		r_oip = oip;
7420c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7421c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7422c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7423c2248fc9SDouglas Gilbert 			else
7424c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7425c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7426c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7427c2248fc9SDouglas Gilbert 					break;
7428c2248fc9SDouglas Gilbert 			}
7429c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7430c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7431c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7432c2248fc9SDouglas Gilbert 					break;
7433c2248fc9SDouglas Gilbert 			}
7434c2248fc9SDouglas Gilbert 		}
7435c2248fc9SDouglas Gilbert 		if (k > na) {
7436c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7437c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7438c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7439c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7440c2248fc9SDouglas Gilbert 			else
7441c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7442c2248fc9SDouglas Gilbert 			goto check_cond;
7443c2248fc9SDouglas Gilbert 		}
7444c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7445c2248fc9SDouglas Gilbert 	flags = oip->flags;
7446f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7447c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7448c2248fc9SDouglas Gilbert 		goto check_cond;
7449c2248fc9SDouglas Gilbert 	}
7450f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7451773642d9SDouglas Gilbert 		if (sdebug_verbose)
7452773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7453773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7454c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7455c2248fc9SDouglas Gilbert 		goto check_cond;
7456c2248fc9SDouglas Gilbert 	}
7457f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7458c2248fc9SDouglas Gilbert 		u8 rem;
7459c2248fc9SDouglas Gilbert 		int j;
7460c2248fc9SDouglas Gilbert 
7461c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7462c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7463c2248fc9SDouglas Gilbert 			if (rem) {
7464c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7465c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7466c2248fc9SDouglas Gilbert 						break;
7467c2248fc9SDouglas Gilbert 				}
7468c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7469c2248fc9SDouglas Gilbert 				goto check_cond;
7470c2248fc9SDouglas Gilbert 			}
7471c2248fc9SDouglas Gilbert 		}
7472c2248fc9SDouglas Gilbert 	}
7473f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7474b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7475b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7476f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7477c2248fc9SDouglas Gilbert 		if (errsts)
7478c2248fc9SDouglas Gilbert 			goto check_cond;
7479c2248fc9SDouglas Gilbert 	}
7480fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7481fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7482fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7483fc13638aSDouglas Gilbert 		if (errsts)
7484c2248fc9SDouglas Gilbert 			goto fini;
7485c2248fc9SDouglas Gilbert 	}
7486773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7487c2248fc9SDouglas Gilbert 		goto fini;
7488f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7489c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7490c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7491c2248fc9SDouglas Gilbert 	}
7492f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7493f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7494f66b8517SMartin Wilck 	else
7495f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7496c2248fc9SDouglas Gilbert 
7497c2248fc9SDouglas Gilbert fini:
749867da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7499f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
750075aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
750175aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
750280c49563SDouglas Gilbert 		/*
750375aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
750475aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
750575aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
750675aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
750780c49563SDouglas Gilbert 		 */
750880c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
75094f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
751080c49563SDouglas Gilbert 
75114f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7512f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
751380c49563SDouglas Gilbert 	} else
7514f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
751510bde980SDouglas Gilbert 				     sdebug_ndelay);
7516c2248fc9SDouglas Gilbert check_cond:
7517f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7518f46eb0e9SDouglas Gilbert err_out:
7519f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7520c2248fc9SDouglas Gilbert }
7521c2248fc9SDouglas Gilbert 
75229e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7523c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7524c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
75259e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
75269e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
75279e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
75289e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
75299e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
75309e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
75319e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7532185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7533cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7534c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7535c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
75369e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
75379e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7538cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7539cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
75409e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7541c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
75429e603ca0SFUJITA Tomonori 	.this_id =		7,
754365e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7544cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
75456bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
754650c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
75479e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7548c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
75499e603ca0SFUJITA Tomonori };
75509e603ca0SFUJITA Tomonori 
75511da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
75521da177e4SLinus Torvalds {
75531da177e4SLinus Torvalds 	int error = 0;
75541da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
75551da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7556f46eb0e9SDouglas Gilbert 	int hprot;
75571da177e4SLinus Torvalds 
75581da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
75591da177e4SLinus Torvalds 
7560773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
75612a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
75624af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
75634af14d11SChristoph Hellwig 
75641da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
75651da177e4SLinus Torvalds 	if (NULL == hpnt) {
7566c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
75671da177e4SLinus Torvalds 		error = -ENODEV;
75681da177e4SLinus Torvalds 		return error;
75691da177e4SLinus Torvalds 	}
7570c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
75719b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7572c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7573c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7574c4837394SDouglas Gilbert 	}
7575c10fa55fSJohn Garry 	/*
7576c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7577f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7578c10fa55fSJohn Garry 	 */
7579c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7580f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7581f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
75821da177e4SLinus Torvalds 
7583c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7584c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7585c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7586c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7587c4b57d89SKashyap Desai 		poll_queues = 0;
7588c4b57d89SKashyap Desai 	}
7589c4b57d89SKashyap Desai 
7590c4b57d89SKashyap Desai 	/*
7591c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7592c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7593c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7594c4b57d89SKashyap Desai 	 */
7595c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7596c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 1\n", my_name);
7597c4b57d89SKashyap Desai 		poll_queues = 1;
7598c4b57d89SKashyap Desai 	}
7599c4b57d89SKashyap Desai 	if (poll_queues)
7600c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7601c4b57d89SKashyap Desai 
76021da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
76031da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7604773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7605773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
76061da177e4SLinus Torvalds 	else
7607773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7608773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7609f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
76101da177e4SLinus Torvalds 
7611f46eb0e9SDouglas Gilbert 	hprot = 0;
7612c6a44287SMartin K. Petersen 
7613773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7614c6a44287SMartin K. Petersen 
76158475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7616f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7617773642d9SDouglas Gilbert 		if (sdebug_dix)
7618f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7619c6a44287SMartin K. Petersen 		break;
7620c6a44287SMartin K. Petersen 
76218475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7622f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7623773642d9SDouglas Gilbert 		if (sdebug_dix)
7624f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7625c6a44287SMartin K. Petersen 		break;
7626c6a44287SMartin K. Petersen 
76278475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7628f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7629773642d9SDouglas Gilbert 		if (sdebug_dix)
7630f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7631c6a44287SMartin K. Petersen 		break;
7632c6a44287SMartin K. Petersen 
7633c6a44287SMartin K. Petersen 	default:
7634773642d9SDouglas Gilbert 		if (sdebug_dix)
7635f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7636c6a44287SMartin K. Petersen 		break;
7637c6a44287SMartin K. Petersen 	}
7638c6a44287SMartin K. Petersen 
7639f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7640c6a44287SMartin K. Petersen 
7641f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7642c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7643f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7644f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7645f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7646f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7647f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7648f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7649f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7650c6a44287SMartin K. Petersen 
7651773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7652c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7653c6a44287SMartin K. Petersen 	else
7654c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7655c6a44287SMartin K. Petersen 
7656773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7657773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7658c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7659c4837394SDouglas Gilbert 		sdebug_statistics = true;
76601da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
76611da177e4SLinus Torvalds 	if (error) {
7662c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
76631da177e4SLinus Torvalds 		error = -ENODEV;
76641da177e4SLinus Torvalds 		scsi_host_put(hpnt);
766587c715dcSDouglas Gilbert 	} else {
76661da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
766787c715dcSDouglas Gilbert 	}
76681da177e4SLinus Torvalds 
76691da177e4SLinus Torvalds 	return error;
76701da177e4SLinus Torvalds }
76711da177e4SLinus Torvalds 
76721da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
76731da177e4SLinus Torvalds {
76741da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
76758b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
76761da177e4SLinus Torvalds 
76771da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
76781da177e4SLinus Torvalds 
76791da177e4SLinus Torvalds 	if (!sdbg_host) {
7680c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
76811da177e4SLinus Torvalds 		return -ENODEV;
76821da177e4SLinus Torvalds 	}
76831da177e4SLinus Torvalds 
76841da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
76851da177e4SLinus Torvalds 
76868b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
76878b40228fSFUJITA Tomonori 				 dev_list) {
76881da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7689f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
76901da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
76911da177e4SLinus Torvalds 	}
76921da177e4SLinus Torvalds 
76931da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
76941da177e4SLinus Torvalds 	return 0;
76951da177e4SLinus Torvalds }
76961da177e4SLinus Torvalds 
76978dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
76988dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
76991da177e4SLinus Torvalds {
77008dea0d02SFUJITA Tomonori 	return 1;
77018dea0d02SFUJITA Tomonori }
77021da177e4SLinus Torvalds 
77038dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
77048dea0d02SFUJITA Tomonori 	.name = "pseudo",
77058dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
77068dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
77078dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
770882069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
77098dea0d02SFUJITA Tomonori };
7710