xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 7d5a129b)
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>
362aad3cd8SDouglas Gilbert #include <linux/mutex.h>
37cbf67842SDouglas Gilbert #include <linux/interrupt.h>
38cbf67842SDouglas Gilbert #include <linux/atomic.h>
39cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
4009ba24c1SDouglas Gilbert #include <linux/uuid.h>
416ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
421442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
430c4bc91dSDouglas Gilbert #include <linux/random.h>
4487c715dcSDouglas Gilbert #include <linux/xarray.h>
45ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
46c6a44287SMartin K. Petersen 
47c6a44287SMartin K. Petersen #include <net/checksum.h>
489ff26eefSFUJITA Tomonori 
4944d92694SMartin K. Petersen #include <asm/unaligned.h>
5044d92694SMartin K. Petersen 
519ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
539ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
541da177e4SLinus Torvalds #include <scsi/scsi_host.h>
551da177e4SLinus Torvalds #include <scsi/scsicam.h>
56a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
57cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
58395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
591da177e4SLinus Torvalds 
60c6a44287SMartin K. Petersen #include "sd.h"
611da177e4SLinus Torvalds #include "scsi_logging.h"
621da177e4SLinus Torvalds 
63773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6430f67481SDouglas Gilbert #define SDEBUG_VERSION "0190"	/* format to fit INQUIRY revision field */
6530f67481SDouglas Gilbert static const char *sdebug_version_date = "20200710";
66cbf67842SDouglas Gilbert 
67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
681da177e4SLinus Torvalds 
696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
799447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
80cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
81cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8219c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8319c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8522017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
86cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
87cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
88cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8922017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
901da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
916f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
92c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
93c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9422017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
96acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
97481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
98f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
99f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
100f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
101f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1031da177e4SLinus Torvalds 
1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1066f3cbf55SDouglas Gilbert 
1071da177e4SLinus Torvalds /* Default values for driver parameters */
1081da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1091da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1101da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1121da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1131da177e4SLinus Torvalds  */
1145b94e232SMartin K. Petersen #define DEF_ATO 1
1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
116c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1205b94e232SMartin K. Petersen #define DEF_DIF 0
1215b94e232SMartin K. Petersen #define DEF_DIX 0
12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1235b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1241da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1255b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1265b94e232SMartin K. Petersen #define DEF_GUARD 0
127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1285b94e232SMartin K. Petersen #define DEF_LBPU 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS 0
1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0
131be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
133cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1351da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1361da177e4SLinus Torvalds #define DEF_OPTS   0
13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
140b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false
142d986788bSMartin Pitt #define DEF_REMOVABLE false
143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
152c2248fc9SDouglas Gilbert #define DEF_STRICT 0
153c4837394SDouglas Gilbert #define DEF_STATISTICS false
154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1581da177e4SLinus Torvalds 
159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
163f0d1cf93SDouglas Gilbert 
164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
165b01f6f83SDouglas Gilbert 
166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
177*7d5a129bSDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400	/* ignore */
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
179773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
180773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
181773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1827ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1837382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
185773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
186773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
187773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
188773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1897ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1907382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1917382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1923a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1933a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1941da177e4SLinus Torvalds 
195cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
196cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
197cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
198cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
200cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
201cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2020d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
20319c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
204acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
205acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
206acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
207cbf67842SDouglas Gilbert 
208773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2091da177e4SLinus Torvalds  * sector on read commands: */
2101da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21132f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2121da177e4SLinus Torvalds 
213c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
214c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
215c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
216c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
217c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
218c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
219c4837394SDouglas Gilbert  */
220c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
222fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN  SDEBUG_CANQUEUE
223cbf67842SDouglas Gilbert 
224b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
225b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
226b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
227fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
228fd32119bSDouglas Gilbert #define F_D_UNKN		8
229b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
230b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
231b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
232b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
233b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
234b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
235b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
236b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
237b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
238b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
239fd32119bSDouglas Gilbert 
240b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
241fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24246f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
243fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2444f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
245fd32119bSDouglas Gilbert 
246fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
247fd32119bSDouglas Gilbert 
248b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
249fd32119bSDouglas Gilbert 
25087c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25187c715dcSDouglas Gilbert 
25264e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25364e14eceSDamien Le Moal enum sdebug_z_type {
25464e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_CNV	= 0x1,
25564e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWR	= 0x2,
25664e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWP	= 0x3,
25764e14eceSDamien Le Moal };
25864e14eceSDamien Le Moal 
259f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
260f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
261f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
262f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
263f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
264f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
265f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
266f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
267f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
268f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
269f0d1cf93SDouglas Gilbert };
270f0d1cf93SDouglas Gilbert 
271f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
27264e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
273f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
27464e14eceSDamien Le Moal 	bool z_non_seq_resource;
275f0d1cf93SDouglas Gilbert 	unsigned int z_size;
276f0d1cf93SDouglas Gilbert 	sector_t z_start;
277f0d1cf93SDouglas Gilbert 	sector_t z_wp;
278f0d1cf93SDouglas Gilbert };
279fd32119bSDouglas Gilbert 
280fd32119bSDouglas Gilbert struct sdebug_dev_info {
281fd32119bSDouglas Gilbert 	struct list_head dev_list;
282fd32119bSDouglas Gilbert 	unsigned int channel;
283fd32119bSDouglas Gilbert 	unsigned int target;
284fd32119bSDouglas Gilbert 	u64 lun;
285bf476433SChristoph Hellwig 	uuid_t lu_name;
286fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
287fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
288fd32119bSDouglas Gilbert 	atomic_t num_in_q;
289fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
290fd32119bSDouglas Gilbert 	bool used;
291f0d1cf93SDouglas Gilbert 
292f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
29364e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
294f0d1cf93SDouglas Gilbert 	unsigned int zsize;
295f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
296f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
297aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
298f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
299f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
300f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
301f0d1cf93SDouglas Gilbert 	unsigned int max_open;
302fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
303f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
304fd32119bSDouglas Gilbert };
305fd32119bSDouglas Gilbert 
306fd32119bSDouglas Gilbert struct sdebug_host_info {
307fd32119bSDouglas Gilbert 	struct list_head host_list;
30887c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
309fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
310fd32119bSDouglas Gilbert 	struct device dev;
311fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
312fd32119bSDouglas Gilbert };
313fd32119bSDouglas Gilbert 
31487c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
31587c715dcSDouglas Gilbert struct sdeb_store_info {
31687c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
31787c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
31887c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
31987c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32087c715dcSDouglas Gilbert };
32187c715dcSDouglas Gilbert 
322fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
323fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
324fd32119bSDouglas Gilbert 
32510bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3264a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
32710bde980SDouglas Gilbert 
328fd32119bSDouglas Gilbert struct sdebug_defer {
329fd32119bSDouglas Gilbert 	struct hrtimer hrt;
330fd32119bSDouglas Gilbert 	struct execute_work ew;
3314a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
332c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
333c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
334c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
335c4837394SDouglas Gilbert 	int issuing_cpu;
33610bde980SDouglas Gilbert 	bool init_hrt;
33710bde980SDouglas Gilbert 	bool init_wq;
3384a0c6f43SDouglas Gilbert 	bool init_poll;
3397382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34010bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
341fd32119bSDouglas Gilbert };
342fd32119bSDouglas Gilbert 
343fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
344c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
345c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
346c4837394SDouglas Gilbert 	 */
347fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
348fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
349fd32119bSDouglas Gilbert };
350fd32119bSDouglas Gilbert 
351c4837394SDouglas Gilbert struct sdebug_queue {
352c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
353c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
354c4837394SDouglas Gilbert 	spinlock_t qc_lock;
355c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
356fd32119bSDouglas Gilbert };
357fd32119bSDouglas Gilbert 
358c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
359c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
360c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
361c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3623a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3634a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
364c4837394SDouglas Gilbert 
365fd32119bSDouglas Gilbert struct opcode_info_t {
366b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
367b01f6f83SDouglas Gilbert 				/* for terminating element */
368fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
369fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
370fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
371fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
372fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3739a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3749a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
375fd32119bSDouglas Gilbert };
376fd32119bSDouglas Gilbert 
377fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
378c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
379c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
380c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
381c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
382c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
383c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
384c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
385c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
386c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
387c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
388c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
389c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
390c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39146f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39246f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
393c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
394c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
395c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
396481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
397c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
398c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
399c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
400c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
401c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
402c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
403c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
404c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
405c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
406c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
407c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
408ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
409f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
410f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
411f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
412c2248fc9SDouglas Gilbert };
413c2248fc9SDouglas Gilbert 
414c4837394SDouglas Gilbert 
415c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
416c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
417c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
418c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
419c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
420c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
421c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
422c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
423c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
424c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
425c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
426c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
427ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
428c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
429c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
430c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
431c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
432c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
433c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
434c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
435fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
436c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
437c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
438c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
439c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
440c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
441c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
442c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
443f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
444f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44546f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
446c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
447c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
448c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
44946f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
45046f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
451c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
452c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
453c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
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 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
458c2248fc9SDouglas Gilbert };
459c2248fc9SDouglas Gilbert 
46080c49563SDouglas Gilbert /*
46180c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46280c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46380c49563SDouglas Gilbert  * command completion, they can mask their return value with
46480c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46580c49563SDouglas Gilbert  */
46680c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46780c49563SDouglas Gilbert 
468c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
469c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
470c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
477481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
485c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
48838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
489acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
49080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
491ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
492f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
493f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
494f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
495f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
496f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
497c2248fc9SDouglas Gilbert 
49887c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
49987c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
50087c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50187c715dcSDouglas Gilbert static int sdebug_add_store(void);
50287c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50487c715dcSDouglas Gilbert 
50546f64e70SDouglas Gilbert /*
50646f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50746f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
50846f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
50946f64e70SDouglas Gilbert  */
51046f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
511c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
512c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
513c2248fc9SDouglas Gilbert };
514c2248fc9SDouglas Gilbert 
51546f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
516c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
517c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
518c2248fc9SDouglas Gilbert };
519c2248fc9SDouglas Gilbert 
52046f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52146f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
522b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
523c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52446f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
525c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52646f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
527b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
528c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
529c2248fc9SDouglas Gilbert };
530c2248fc9SDouglas Gilbert 
53146f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53246f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53346f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53446f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53546f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53646f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53746f64e70SDouglas Gilbert 		   0, 0, 0} },
53846f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
53946f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54046f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
541c2248fc9SDouglas Gilbert };
542c2248fc9SDouglas Gilbert 
543c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
544c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
545c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
546c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
547c3e2fe92SDouglas Gilbert };
548c3e2fe92SDouglas Gilbert 
54946f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
550c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
551c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55246f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
553c2248fc9SDouglas Gilbert };
554c2248fc9SDouglas Gilbert 
55546f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55646f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
557b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
558c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
559481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
560481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
561481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
562c2248fc9SDouglas Gilbert };
563c2248fc9SDouglas Gilbert 
56446f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56538d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
566c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56746f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
56838d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
569c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
57046f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
571c2248fc9SDouglas Gilbert };
572c2248fc9SDouglas Gilbert 
57346f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57446f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
575c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57646f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
577c2248fc9SDouglas Gilbert };
578c2248fc9SDouglas Gilbert 
57946f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
580c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
581c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
582c2248fc9SDouglas Gilbert };
583c2248fc9SDouglas Gilbert 
58446f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
585c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
586c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
587c2248fc9SDouglas Gilbert };
588c2248fc9SDouglas Gilbert 
58980c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5904f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59180c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59280c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59380c49563SDouglas Gilbert };
59480c49563SDouglas Gilbert 
595ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
596b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
597ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
598ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
599ed9f3e25SDouglas Gilbert };
600ed9f3e25SDouglas Gilbert 
601f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
602b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
603f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
604f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
605b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
606f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
607f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
608b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
609f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
610f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
611f0d1cf93SDouglas Gilbert };
612f0d1cf93SDouglas Gilbert 
613f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
614b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
615f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
616f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
617f0d1cf93SDouglas Gilbert };
618f0d1cf93SDouglas Gilbert 
619c2248fc9SDouglas Gilbert 
620c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
621c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
622c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
623ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
624c2248fc9SDouglas Gilbert /* 0 */
62546f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
626c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62746f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
628c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
629c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
630c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63146f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
632c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
633c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
634c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
635c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63646f64e70SDouglas Gilbert /* 5 */
63746f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
63846f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
63946f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64046f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64146f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64246f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64346f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
644c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
645c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64646f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
647c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
648c2248fc9SDouglas Gilbert 	     0, 0} },
64946f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
65046f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65146f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
652c2248fc9SDouglas Gilbert /* 10 */
65346f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65446f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65546f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65680c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6574f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
658c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65946f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
66046f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66146f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66246f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
663481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
664481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
665481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66646f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66746f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
66846f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
66946f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
67046f64e70SDouglas Gilbert /* 15 */
671c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
672c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
673c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
674c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
675c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
676c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67746f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
67846f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
67946f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
68046f64e70SDouglas Gilbert 	     0xff, 0xff} },
68146f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68246f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
683c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
684c2248fc9SDouglas Gilbert 	     0} },
68546f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68646f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
687c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
688c2248fc9SDouglas Gilbert 	     0} },
689c2248fc9SDouglas Gilbert /* 20 */
690f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
691f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
692c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
693c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
694c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
695c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
696c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
697c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
69846f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
699b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
70046f64e70SDouglas Gilbert /* 25 */
701acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
702acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
703acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70446f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70546f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70646f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70746f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7084f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
70980c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
710b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71180c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71246f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
713c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
714b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
715b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
716ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
717ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
718ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
719c2248fc9SDouglas Gilbert 
720ed9f3e25SDouglas Gilbert /* 30 */
721b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
722f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
723f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
724f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
725b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
726f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
727f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
728f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
729f0d1cf93SDouglas Gilbert /* sentinel */
730c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
731c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
732c2248fc9SDouglas Gilbert };
733c2248fc9SDouglas Gilbert 
7342aad3cd8SDouglas Gilbert static atomic_t sdebug_num_hosts;
7352aad3cd8SDouglas Gilbert static DEFINE_MUTEX(add_host_mutex);
7362aad3cd8SDouglas Gilbert 
73787c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
738773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7399b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
740c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7419267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
742773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
743773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
744773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
745773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
746773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
747773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
748c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
749773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
750773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
751c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
752d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
753d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
754cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
755c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
756773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
757773642d9SDouglas Gilbert static int sdebug_no_uld;
758773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
759773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
760773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
761773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
762773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76386e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
764b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
765773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
766773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
767fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
768773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
769773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
770773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
771773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
772773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
773773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
775773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
776773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
778773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
77909ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7800c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
78187c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
782773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
7832aad3cd8SDouglas Gilbert static bool sdebug_deflect_incoming;
784773642d9SDouglas Gilbert static bool sdebug_clustering;
785773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
786773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
787817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
788773642d9SDouglas Gilbert static bool sdebug_verbose;
789f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7904f2c8bf6SDouglas Gilbert static bool write_since_sync;
791c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7929447b6ceSMartin K. Petersen static bool sdebug_wp;
7939267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7949267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7959267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7961da177e4SLinus Torvalds 
797ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
798ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
799ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
800ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
801ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
802ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
803ad0c7775SDouglas Gilbert 
804c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8051da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8081da177e4SLinus Torvalds    may still need them */
8091da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8101da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8111da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8141da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8151da177e4SLinus Torvalds 
81687c715dcSDouglas Gilbert static struct xarray per_store_arr;
81787c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
81887c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
81987c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
82087c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8211da177e4SLinus Torvalds 
82244d92694SMartin K. Petersen static unsigned long map_size;
823cbf67842SDouglas Gilbert static int num_aborts;
824cbf67842SDouglas Gilbert static int num_dev_resets;
825cbf67842SDouglas Gilbert static int num_target_resets;
826cbf67842SDouglas Gilbert static int num_bus_resets;
827cbf67842SDouglas Gilbert static int num_host_resets;
828c6a44287SMartin K. Petersen static int dix_writes;
829c6a44287SMartin K. Petersen static int dix_reads;
830c6a44287SMartin K. Petersen static int dif_errors;
8311da177e4SLinus Torvalds 
832f0d1cf93SDouglas Gilbert /* ZBC global data */
83364e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
83498e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
835380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
836aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
837f0d1cf93SDouglas Gilbert 
838c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
839c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
840c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
841fd32119bSDouglas Gilbert 
8421da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
84387c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84487c715dcSDouglas Gilbert 
84587c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8461da177e4SLinus Torvalds 
847cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
848cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8491da177e4SLinus Torvalds 
8501da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8531da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8541da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8551da177e4SLinus Torvalds };
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds static const int check_condition_result =
858464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8591da177e4SLinus Torvalds 
860c6a44287SMartin K. Petersen static const int illegal_condition_result =
861464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
862c6a44287SMartin K. Petersen 
863cbf67842SDouglas Gilbert static const int device_qfull_result =
864*7d5a129bSDouglas Gilbert 	(DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
865cbf67842SDouglas Gilbert 
866ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
867ed9f3e25SDouglas Gilbert 
868fd32119bSDouglas Gilbert 
869760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
870760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
871760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
872760f3b03SDouglas Gilbert  */
873760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
874fd32119bSDouglas Gilbert {
875fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
876fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
877fd32119bSDouglas Gilbert }
878c65b1445SDouglas Gilbert 
87987c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
88087c715dcSDouglas Gilbert 			    unsigned long long lba)
88114faa944SAkinobu Mita {
88287c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
88314faa944SAkinobu Mita 
88487c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88587c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88687c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
88787c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
88887c715dcSDouglas Gilbert 	}
88987c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
89014faa944SAkinobu Mita }
89114faa944SAkinobu Mita 
89287c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
89387c715dcSDouglas Gilbert 				      sector_t sector)
89414faa944SAkinobu Mita {
89549413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89614faa944SAkinobu Mita 
89787c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
89814faa944SAkinobu Mita }
89914faa944SAkinobu Mita 
9008dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9018dea0d02SFUJITA Tomonori {
9028dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9038dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9048dea0d02SFUJITA Tomonori 
9058dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9068dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9078dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9088dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
909773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
910773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9118dea0d02SFUJITA Tomonori 		else
912773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
913773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
914f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9158dea0d02SFUJITA Tomonori 	}
9168dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9178dea0d02SFUJITA Tomonori }
9188dea0d02SFUJITA Tomonori 
91922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
92022017ed2SDouglas Gilbert 
92122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
922fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
923fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92422017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92522017ed2SDouglas Gilbert {
92622017ed2SDouglas Gilbert 	unsigned char *sbuff;
92722017ed2SDouglas Gilbert 	u8 sks[4];
92822017ed2SDouglas Gilbert 	int sl, asc;
92922017ed2SDouglas Gilbert 
93022017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
93122017ed2SDouglas Gilbert 	if (!sbuff) {
93222017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
93322017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93422017ed2SDouglas Gilbert 		return;
93522017ed2SDouglas Gilbert 	}
93622017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
93722017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
938f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
93922017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
94022017ed2SDouglas Gilbert 	sks[0] = 0x80;
94122017ed2SDouglas Gilbert 	if (c_d)
94222017ed2SDouglas Gilbert 		sks[0] |= 0x40;
94322017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94422017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94522017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94622017ed2SDouglas Gilbert 	}
94722017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
948773642d9SDouglas Gilbert 	if (sdebug_dsense) {
94922017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
95022017ed2SDouglas Gilbert 		sbuff[7] = sl;
95122017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
95222017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
95322017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95422017ed2SDouglas Gilbert 	} else
95522017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
956773642d9SDouglas Gilbert 	if (sdebug_verbose)
95722017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
95822017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
95922017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
96022017ed2SDouglas Gilbert }
96122017ed2SDouglas Gilbert 
962cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9638dea0d02SFUJITA Tomonori {
964f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
965cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
966cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
967cbf67842SDouglas Gilbert 		return;
968cbf67842SDouglas Gilbert 	}
969f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9708dea0d02SFUJITA Tomonori 
971f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9728dea0d02SFUJITA Tomonori 
973773642d9SDouglas Gilbert 	if (sdebug_verbose)
974cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
975cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
976cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9778dea0d02SFUJITA Tomonori }
9781da177e4SLinus Torvalds 
979fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
98022017ed2SDouglas Gilbert {
98122017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98222017ed2SDouglas Gilbert }
98322017ed2SDouglas Gilbert 
9846f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9856f4e626fSNathan Chancellor 			    void __user *arg)
9861da177e4SLinus Torvalds {
987773642d9SDouglas Gilbert 	if (sdebug_verbose) {
988cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
989cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
990cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
991cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
992cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
993cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
994cbf67842SDouglas Gilbert 				    __func__);
995cbf67842SDouglas Gilbert 		else
996cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
997cbf67842SDouglas Gilbert 				    __func__, cmd);
9981da177e4SLinus Torvalds 	}
9991da177e4SLinus Torvalds 	return -EINVAL;
10001da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10011da177e4SLinus Torvalds }
10021da177e4SLinus Torvalds 
10039b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10049b760fd8SDouglas Gilbert {
10059b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10069b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10079b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10089b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10099b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10109b760fd8SDouglas Gilbert 		break;
10119b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10129b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10139b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10149b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10159b760fd8SDouglas Gilbert 		break;
10169b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10179b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10189b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10199b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10209b760fd8SDouglas Gilbert 		break;
10219b760fd8SDouglas Gilbert 	case 16:
10229b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10239b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10249b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10259b760fd8SDouglas Gilbert 		break;
10269b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10279b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10289b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10299b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10309b760fd8SDouglas Gilbert 		break;
10319b760fd8SDouglas Gilbert 	default:
10329b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10339b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10349b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10359b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10369b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10379b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10389b760fd8SDouglas Gilbert 		break;
10399b760fd8SDouglas Gilbert 	}
10409b760fd8SDouglas Gilbert }
10419b760fd8SDouglas Gilbert 
10429b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10439b760fd8SDouglas Gilbert {
10449b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10459b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10469b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10479b760fd8SDouglas Gilbert 
10489b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10499b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10509b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10519b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10529b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10539b760fd8SDouglas Gilbert 		}
10549b760fd8SDouglas Gilbert 	}
10559b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10569b760fd8SDouglas Gilbert }
10579b760fd8SDouglas Gilbert 
105819c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
105919c8ead7SEwan D. Milne {
106019c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106119c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106219c8ead7SEwan D. Milne 
106319c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
106419c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106519c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
106619c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
106719c8ead7SEwan D. Milne 			    (devip->target == dp->target))
106819c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
106919c8ead7SEwan D. Milne 		}
107019c8ead7SEwan D. Milne 	}
107119c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107219c8ead7SEwan D. Milne }
107319c8ead7SEwan D. Milne 
1074f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10751da177e4SLinus Torvalds {
1076cbf67842SDouglas Gilbert 	int k;
1077cbf67842SDouglas Gilbert 
1078cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1079cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1080cbf67842SDouglas Gilbert 		const char *cp = NULL;
1081cbf67842SDouglas Gilbert 
1082cbf67842SDouglas Gilbert 		switch (k) {
1083cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1084f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1085f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1086773642d9SDouglas Gilbert 			if (sdebug_verbose)
1087cbf67842SDouglas Gilbert 				cp = "power on reset";
1088cbf67842SDouglas Gilbert 			break;
1089cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1090f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1091f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1092773642d9SDouglas Gilbert 			if (sdebug_verbose)
1093cbf67842SDouglas Gilbert 				cp = "bus reset";
1094cbf67842SDouglas Gilbert 			break;
1095cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1096f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1097f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1098773642d9SDouglas Gilbert 			if (sdebug_verbose)
1099cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1100cbf67842SDouglas Gilbert 			break;
11010d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1102f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1103f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1104773642d9SDouglas Gilbert 			if (sdebug_verbose)
11050d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1106f49accf1SEwan D. Milne 			break;
1107acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1108f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1109b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1110b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1111773642d9SDouglas Gilbert 			if (sdebug_verbose)
1112acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1113acafd0b9SEwan D. Milne 			break;
1114acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1115f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1116acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1117acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1118773642d9SDouglas Gilbert 			if (sdebug_verbose)
1119acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1120acafd0b9SEwan D. Milne 			break;
112119c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
112219c8ead7SEwan D. Milne 			/*
112319c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
112419c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
112519c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
112619c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1127773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
112819c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
112919c8ead7SEwan D. Milne 			 */
1130773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
113119c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1132f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
113319c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
113419c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1135773642d9SDouglas Gilbert 			if (sdebug_verbose)
113619c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
113719c8ead7SEwan D. Milne 			break;
1138cbf67842SDouglas Gilbert 		default:
1139773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1140773642d9SDouglas Gilbert 			if (sdebug_verbose)
1141cbf67842SDouglas Gilbert 				cp = "unknown";
1142cbf67842SDouglas Gilbert 			break;
1143cbf67842SDouglas Gilbert 		}
1144cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1145773642d9SDouglas Gilbert 		if (sdebug_verbose)
1146f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1147cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1148cbf67842SDouglas Gilbert 				   my_name, cp);
11491da177e4SLinus Torvalds 		return check_condition_result;
11501da177e4SLinus Torvalds 	}
11511da177e4SLinus Torvalds 	return 0;
11521da177e4SLinus Torvalds }
11531da177e4SLinus Torvalds 
1154fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11551da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11561da177e4SLinus Torvalds 				int arr_len)
11571da177e4SLinus Torvalds {
115821a61829SFUJITA Tomonori 	int act_len;
1159ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11601da177e4SLinus Torvalds 
1161072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11621da177e4SLinus Torvalds 		return 0;
1163ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1164773642d9SDouglas Gilbert 		return DID_ERROR << 16;
116521a61829SFUJITA Tomonori 
116621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
116721a61829SFUJITA Tomonori 				      arr, arr_len);
116842d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
116921a61829SFUJITA Tomonori 
11701da177e4SLinus Torvalds 	return 0;
11711da177e4SLinus Torvalds }
11721da177e4SLinus Torvalds 
1173fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1174fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1175fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1176fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1177fb0cc8d1SDouglas Gilbert  */
1178fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1179fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1180fb0cc8d1SDouglas Gilbert {
11819237f04eSDamien Le Moal 	unsigned int act_len, n;
1182ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1183fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1184fb0cc8d1SDouglas Gilbert 
1185fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1186fb0cc8d1SDouglas Gilbert 		return 0;
1187ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1188fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1189fb0cc8d1SDouglas Gilbert 
1190fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1191fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1192fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
119342d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
119442d387beSBart Van Assche 		 scsi_get_resid(scp));
11959237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
119636e07d7eSGeorge Kennedy 	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
1197fb0cc8d1SDouglas Gilbert 	return 0;
1198fb0cc8d1SDouglas Gilbert }
1199fb0cc8d1SDouglas Gilbert 
1200fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1201fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1202fb0cc8d1SDouglas Gilbert  */
12031da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
120421a61829SFUJITA Tomonori 			       int arr_len)
12051da177e4SLinus Torvalds {
120621a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12071da177e4SLinus Torvalds 		return 0;
1208ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12091da177e4SLinus Torvalds 		return -1;
121021a61829SFUJITA Tomonori 
121121a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds 
1215e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1216e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12179b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12181b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12191b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12201b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12211b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12221da177e4SLinus Torvalds 
1223cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1224760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12255a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
122609ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1227bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12281da177e4SLinus Torvalds {
1229c65b1445SDouglas Gilbert 	int num, port_a;
1230c65b1445SDouglas Gilbert 	char b[32];
12311da177e4SLinus Torvalds 
1232c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12331da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12341da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12351da177e4SLinus Torvalds 	arr[1] = 0x1;
12361da177e4SLinus Torvalds 	arr[2] = 0x0;
1237e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1238e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12391da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12401da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12411da177e4SLinus Torvalds 	arr[3] = num;
12421da177e4SLinus Torvalds 	num += 4;
1243c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
124409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
124509ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
124609ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
124709ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
124809ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124909ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
125009ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
125109ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125209ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
125309ba24c1SDouglas Gilbert 			num += 16;
125409ba24c1SDouglas Gilbert 		} else {
12551b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1256c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1257c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1258c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1259c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12601b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1261773642d9SDouglas Gilbert 			num += 8;
126209ba24c1SDouglas Gilbert 		}
1263c65b1445SDouglas Gilbert 		/* Target relative port number */
1264c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1265c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1266c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1267c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1268c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1269c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1270c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1271c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1272c65b1445SDouglas Gilbert 	}
12731b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1274c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1275c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1276c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1277c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12781b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1279773642d9SDouglas Gilbert 	num += 8;
12801b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12815a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12825a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12835a09e398SHannes Reinecke 	arr[num++] = 0x0;
12845a09e398SHannes Reinecke 	arr[num++] = 0x4;
12855a09e398SHannes Reinecke 	arr[num++] = 0;
12865a09e398SHannes Reinecke 	arr[num++] = 0;
1287773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1288773642d9SDouglas Gilbert 	num += 2;
12891b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1290c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1291c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1292c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1293c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12941b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1295773642d9SDouglas Gilbert 	num += 8;
1296c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1297c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1298c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1299c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1300c65b1445SDouglas Gilbert 	arr[num++] = 24;
13011b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1302c65b1445SDouglas Gilbert 	num += 12;
1303c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1304c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1305c65b1445SDouglas Gilbert 	num += 8;
1306c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1307c65b1445SDouglas Gilbert 	num += 4;
1308c65b1445SDouglas Gilbert 	return num;
1309c65b1445SDouglas Gilbert }
1310c65b1445SDouglas Gilbert 
1311c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1312c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1313c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1314c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1315c65b1445SDouglas Gilbert };
1316c65b1445SDouglas Gilbert 
1317cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1318760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1319c65b1445SDouglas Gilbert {
1320c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1321c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1322c65b1445SDouglas Gilbert }
1323c65b1445SDouglas Gilbert 
1324cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1325760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1326c65b1445SDouglas Gilbert {
1327c65b1445SDouglas Gilbert 	int num = 0;
1328c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1329c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1330c65b1445SDouglas Gilbert 	int plen, olen;
1331c65b1445SDouglas Gilbert 
1332c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1333c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1334c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1335c65b1445SDouglas Gilbert 	olen = strlen(na1);
1336c65b1445SDouglas Gilbert 	plen = olen + 1;
1337c65b1445SDouglas Gilbert 	if (plen % 4)
1338c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1339c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1340c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1341c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1342c65b1445SDouglas Gilbert 	num += plen;
1343c65b1445SDouglas Gilbert 
1344c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1345c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1346c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1347c65b1445SDouglas Gilbert 	olen = strlen(na2);
1348c65b1445SDouglas Gilbert 	plen = olen + 1;
1349c65b1445SDouglas Gilbert 	if (plen % 4)
1350c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1351c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1352c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1353c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1354c65b1445SDouglas Gilbert 	num += plen;
1355c65b1445SDouglas Gilbert 
1356c65b1445SDouglas Gilbert 	return num;
1357c65b1445SDouglas Gilbert }
1358c65b1445SDouglas Gilbert 
1359c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1360760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1361c65b1445SDouglas Gilbert {
1362c65b1445SDouglas Gilbert 	int num = 0;
1363c65b1445SDouglas Gilbert 	int port_a, port_b;
1364c65b1445SDouglas Gilbert 
1365c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1366c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1367c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1368c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1369c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1370c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1371c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1372c65b1445SDouglas Gilbert 	num += 6;
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1374c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1375c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1376c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13801b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1381773642d9SDouglas Gilbert 	num += 8;
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1385c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1386c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1387c65b1445SDouglas Gilbert 	num += 6;
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1389c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1390c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1393c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1394c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13951b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1396773642d9SDouglas Gilbert 	num += 8;
1397c65b1445SDouglas Gilbert 
1398c65b1445SDouglas Gilbert 	return num;
1399c65b1445SDouglas Gilbert }
1400c65b1445SDouglas Gilbert 
1401c65b1445SDouglas Gilbert 
1402c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1403c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1404c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1405c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1406c65b1445SDouglas Gilbert '1','2','3','4',
1407c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1408c65b1445SDouglas Gilbert 0xec,0,0,0,
1409c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1410c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1411c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1412c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1413c65b1445SDouglas Gilbert 0x53,0x41,
1414c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1415c65b1445SDouglas Gilbert 0x20,0x20,
1416c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1417c65b1445SDouglas Gilbert 0x10,0x80,
1418c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1419c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1420c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1421c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1422c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1423c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1424c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1428c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1429c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1430c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1431c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1443c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1444c65b1445SDouglas Gilbert };
1445c65b1445SDouglas Gilbert 
1446cbf67842SDouglas Gilbert /* ATA Information VPD page */
1447760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1448c65b1445SDouglas Gilbert {
1449c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1450c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1451c65b1445SDouglas Gilbert }
1452c65b1445SDouglas Gilbert 
1453c65b1445SDouglas Gilbert 
1454c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14551e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
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,
14581e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1459c65b1445SDouglas Gilbert };
1460c65b1445SDouglas Gilbert 
1461cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1462760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1463c65b1445SDouglas Gilbert {
1464ea61fca5SMartin K. Petersen 	unsigned int gran;
1465ea61fca5SMartin K. Petersen 
1466c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1467e308b3d1SMartin K. Petersen 
1468e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
146986e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
147086e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
147186e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
147286e6828aSLukas Herbolt 	else
1473773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1474773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1475e308b3d1SMartin K. Petersen 
1476e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1477773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1478773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
147944d92694SMartin K. Petersen 
1480e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1481773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1482e308b3d1SMartin K. Petersen 
1483773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1484e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1485773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1486e308b3d1SMartin K. Petersen 
1487e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1488773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
148944d92694SMartin K. Petersen 	}
149044d92694SMartin K. Petersen 
1491e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1492773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1493773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
149444d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
149544d92694SMartin K. Petersen 	}
149644d92694SMartin K. Petersen 
1497e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1498773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14996014759cSMartin K. Petersen 
15005b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1501773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15025b94e232SMartin K. Petersen 
15035b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
150444d92694SMartin K. Petersen 
1505c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15061da177e4SLinus Torvalds }
15071da177e4SLinus Torvalds 
15081e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
150964e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1510eac6e8e4SMatthew Wilcox {
1511eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1512eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15131e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15141e49f785SDouglas Gilbert 	arr[2] = 0;
15151e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
151664e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
151764e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1518eac6e8e4SMatthew Wilcox 
1519eac6e8e4SMatthew Wilcox 	return 0x3c;
1520eac6e8e4SMatthew Wilcox }
15211da177e4SLinus Torvalds 
1522760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1523760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15246014759cSMartin K. Petersen {
15253f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15266014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1527773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15286014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1529773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15306014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1531773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15325b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1533760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1534760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1535760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1536760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1537760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15383f0bc3b3SMartin K. Petersen 	return 0x4;
15396014759cSMartin K. Petersen }
15406014759cSMartin K. Petersen 
1541d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1542f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1543d36da305SDouglas Gilbert {
1544d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1545d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1546d36da305SDouglas Gilbert 	/*
1547d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1548d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1549f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1550f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1551d36da305SDouglas Gilbert 	 */
1552d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1553d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
155464e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1555f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1556f0d1cf93SDouglas Gilbert 	else
1557d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1558d36da305SDouglas Gilbert 	return 0x3c;
1559d36da305SDouglas Gilbert }
1560d36da305SDouglas Gilbert 
15611da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1562c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15631da177e4SLinus Torvalds 
1564c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15651da177e4SLinus Torvalds {
15661da177e4SLinus Torvalds 	unsigned char pq_pdt;
15675a09e398SHannes Reinecke 	unsigned char *arr;
156801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
156936e07d7eSGeorge Kennedy 	u32 alloc_len, n;
157036e07d7eSGeorge Kennedy 	int ret;
1571d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15721da177e4SLinus Torvalds 
1573773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15746f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15756f3cbf55SDouglas Gilbert 	if (! arr)
15766f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1577760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
157864e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1579d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1580b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1581c2248fc9SDouglas Gilbert 	if (have_wlun)
1582b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1583b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1584b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1585c65b1445SDouglas Gilbert 	else
1586773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15871da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15881da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
158922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15905a09e398SHannes Reinecke 		kfree(arr);
15911da177e4SLinus Torvalds 		return check_condition_result;
15921da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
159336e07d7eSGeorge Kennedy 		int lu_id_num, port_group_id, target_dev_id;
159436e07d7eSGeorge Kennedy 		u32 len;
1595c65b1445SDouglas Gilbert 		char lu_id_str[6];
1596c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
15971da177e4SLinus Torvalds 
15985a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
15995a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1600b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
160123183910SDouglas Gilbert 			host_no = 0;
1602c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1603c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1604c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1605c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1606c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16071da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1608c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1609c65b1445SDouglas Gilbert 			n = 4;
1610c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1611c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1612c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1613c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1615c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1616c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1617c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1618d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1619c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1620760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1621760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1622d36da305SDouglas Gilbert 				if (is_disk)
1623d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
162464e14eceSDamien Le Moal 				if (is_zbc)
1625d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1626760f3b03SDouglas Gilbert 			}
1627c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16281da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1629c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16301da177e4SLinus Torvalds 			arr[3] = len;
1631c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16321da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1633c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1634760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16355a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
163609ba24c1SDouglas Gilbert 						lu_id_str, len,
163709ba24c1SDouglas Gilbert 						&devip->lu_name);
1638c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1639c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1640760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1641c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1642c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1643760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1644c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1645c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1646c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16478475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1648c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1649760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1650c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1651c6a44287SMartin K. Petersen 			else
1652c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1653c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1654c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1655c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1656c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1657c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1658c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1659c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1660c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1661c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1662c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1663760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1664d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1665c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1666760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1667773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1668d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1669c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1670760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1671d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1672eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
167364e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1674760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16756014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1676760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1677d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1678d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1679f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16801da177e4SLinus Torvalds 		} else {
168122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16825a09e398SHannes Reinecke 			kfree(arr);
16831da177e4SLinus Torvalds 			return check_condition_result;
16841da177e4SLinus Torvalds 		}
168536e07d7eSGeorge Kennedy 		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
16865a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
168736e07d7eSGeorge Kennedy 			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
16885a09e398SHannes Reinecke 		kfree(arr);
16895a09e398SHannes Reinecke 		return ret;
16901da177e4SLinus Torvalds 	}
16911da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1692773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1693773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16941da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16951da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1696f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1697b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
169870bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1699c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17001da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1701c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1702e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1703e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1704e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17059b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17069b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17071da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1708760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1709760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1710c65b1445SDouglas Gilbert 	n = 62;
1711760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1712760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1713760f3b03SDouglas Gilbert 		n += 2;
1714760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1715760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1716760f3b03SDouglas Gilbert 		n += 2;
1717d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1718d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1719d36da305SDouglas Gilbert 		n += 2;
17201da177e4SLinus Torvalds 	}
1721760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17225a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
172336e07d7eSGeorge Kennedy 			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17245a09e398SHannes Reinecke 	kfree(arr);
17255a09e398SHannes Reinecke 	return ret;
17261da177e4SLinus Torvalds }
17271da177e4SLinus Torvalds 
172884905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1729fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1730fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1731fd32119bSDouglas Gilbert 
17321da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17331da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17341da177e4SLinus Torvalds {
173501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
173684905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
173784905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
173836e07d7eSGeorge Kennedy 	u32 alloc_len = cmd[4];
173936e07d7eSGeorge Kennedy 	u32 len = 18;
174084905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17411da177e4SLinus Torvalds 
1742c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
174384905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
174484905d34SDouglas Gilbert 		if (dsense) {
174584905d34SDouglas Gilbert 			arr[0] = 0x72;
174684905d34SDouglas Gilbert 			arr[1] = NOT_READY;
174784905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
174884905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
174984905d34SDouglas Gilbert 			len = 8;
175084905d34SDouglas Gilbert 		} else {
175184905d34SDouglas Gilbert 			arr[0] = 0x70;
175284905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
175384905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
175484905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
175584905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
175684905d34SDouglas Gilbert 		}
175784905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
175884905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1759c2248fc9SDouglas Gilbert 		if (dsense) {
1760c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1761c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1762c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
176384905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1764c2248fc9SDouglas Gilbert 			len = 8;
1765c65b1445SDouglas Gilbert 		} else {
1766c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1767c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1768c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1769c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
177084905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1771c65b1445SDouglas Gilbert 		}
177284905d34SDouglas Gilbert 	} else {	/* nothing to report */
1773c2248fc9SDouglas Gilbert 		if (dsense) {
1774c2248fc9SDouglas Gilbert 			len = 8;
177584905d34SDouglas Gilbert 			memset(arr, 0, len);
177684905d34SDouglas Gilbert 			arr[0] = 0x72;
1777c2248fc9SDouglas Gilbert 		} else {
177884905d34SDouglas Gilbert 			memset(arr, 0, len);
1779c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1780c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1781c2248fc9SDouglas Gilbert 		}
1782c65b1445SDouglas Gilbert 	}
178336e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
17841da177e4SLinus Torvalds }
17851da177e4SLinus Torvalds 
1786fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1787c65b1445SDouglas Gilbert {
178801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1789fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
17904f2c8bf6SDouglas Gilbert 	bool changing;
1791c65b1445SDouglas Gilbert 
1792c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1793c65b1445SDouglas Gilbert 	if (power_cond) {
179422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1795c65b1445SDouglas Gilbert 		return check_condition_result;
1796c65b1445SDouglas Gilbert 	}
1797fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1798fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1799fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1800fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1801fc13638aSDouglas Gilbert 
1802fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1803fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1804fc13638aSDouglas Gilbert 
1805fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1806fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1807fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1808fc13638aSDouglas Gilbert 				stopped_state = 0;
1809fc13638aSDouglas Gilbert 			}
1810fc13638aSDouglas Gilbert 		}
1811fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1812fc13638aSDouglas Gilbert 			if (want_stop) {
1813fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1814fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1815fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1816fc13638aSDouglas Gilbert 				return check_condition_result;
1817fc13638aSDouglas Gilbert 			}
1818fc13638aSDouglas Gilbert 		}
1819fc13638aSDouglas Gilbert 	}
1820fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1821fc13638aSDouglas Gilbert 	if (changing)
1822fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1823fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18244f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18254f2c8bf6SDouglas Gilbert 	else
18264f2c8bf6SDouglas Gilbert 		return 0;
1827c65b1445SDouglas Gilbert }
1828c65b1445SDouglas Gilbert 
182928898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
183028898873SFUJITA Tomonori {
1831773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1832773642d9SDouglas Gilbert 
1833773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1834773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1835773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
183628898873SFUJITA Tomonori 	else
183728898873SFUJITA Tomonori 		return sdebug_store_sectors;
183828898873SFUJITA Tomonori }
183928898873SFUJITA Tomonori 
18401da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18411da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18421da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18431da177e4SLinus Torvalds {
18441da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1845c65b1445SDouglas Gilbert 	unsigned int capac;
18461da177e4SLinus Torvalds 
1847c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
184828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18491da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1850c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1851c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1852773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1853773642d9SDouglas Gilbert 	} else
1854773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1855773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18561da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18571da177e4SLinus Torvalds }
18581da177e4SLinus Torvalds 
1859c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1860c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1861c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1862c65b1445SDouglas Gilbert {
186301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1864c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18654e3ace00SYe Bin 	u32 alloc_len;
1866c65b1445SDouglas Gilbert 
1867773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1868c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186928898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1870c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1871773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1872773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1873773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1874773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
187544d92694SMartin K. Petersen 
1876be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18775b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1878760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1879760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1880760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1881760f3b03SDouglas Gilbert 		 */
1882760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1883760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1884be1dd78dSEric Sandeen 	}
188544d92694SMartin K. Petersen 
1886773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1887c6a44287SMartin K. Petersen 
1888760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1889773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1890c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1891c6a44287SMartin K. Petersen 	}
1892c6a44287SMartin K. Petersen 
1893c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
18944e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1895c65b1445SDouglas Gilbert }
1896c65b1445SDouglas Gilbert 
18975a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18985a09e398SHannes Reinecke 
18995a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19005a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19015a09e398SHannes Reinecke {
190201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19035a09e398SHannes Reinecke 	unsigned char *arr;
19045a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19055a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1906f347c268SYe Bin 	u32 alen, n, rlen;
1907f347c268SYe Bin 	int ret;
19085a09e398SHannes Reinecke 
1909773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19106f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19116f3cbf55SDouglas Gilbert 	if (! arr)
19126f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19135a09e398SHannes Reinecke 	/*
19145a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19155a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19165a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19175a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19185a09e398SHannes Reinecke 	 */
19195a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19205a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19215a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19225a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19235a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19245a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19255a09e398SHannes Reinecke 
19265a09e398SHannes Reinecke 	/*
19275a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19285a09e398SHannes Reinecke 	 */
19295a09e398SHannes Reinecke 	n = 4;
1930b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19315a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19325a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19335a09e398SHannes Reinecke 	} else {
19345a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1935773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19365a09e398SHannes Reinecke 	}
1937773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1938773642d9SDouglas Gilbert 	n += 2;
19395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19415a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19425a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1945773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1946773642d9SDouglas Gilbert 	n += 2;
19475a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19485a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1949773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1950773642d9SDouglas Gilbert 	n += 2;
19515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19535a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19545a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19555a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19565a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1957773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1958773642d9SDouglas Gilbert 	n += 2;
19595a09e398SHannes Reinecke 
19605a09e398SHannes Reinecke 	rlen = n - 4;
1961773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19625a09e398SHannes Reinecke 
19635a09e398SHannes Reinecke 	/*
19645a09e398SHannes Reinecke 	 * Return the smallest value of either
19655a09e398SHannes Reinecke 	 * - The allocated length
19665a09e398SHannes Reinecke 	 * - The constructed command length
19675a09e398SHannes Reinecke 	 * - The maximum array size
19685a09e398SHannes Reinecke 	 */
1969f347c268SYe Bin 	rlen = min(alen, n);
19705a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1971f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19725a09e398SHannes Reinecke 	kfree(arr);
19735a09e398SHannes Reinecke 	return ret;
19745a09e398SHannes Reinecke }
19755a09e398SHannes Reinecke 
1976fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1977fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
197838d5c833SDouglas Gilbert {
197938d5c833SDouglas Gilbert 	bool rctd;
198038d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
198138d5c833SDouglas Gilbert 	u16 req_sa, u;
198238d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
198338d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
198438d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
198538d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
198638d5c833SDouglas Gilbert 	u8 *arr;
198738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
198838d5c833SDouglas Gilbert 
198938d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
199038d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
199138d5c833SDouglas Gilbert 	req_opcode = cmd[3];
199238d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
199338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19946d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
199538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
199638d5c833SDouglas Gilbert 		return check_condition_result;
199738d5c833SDouglas Gilbert 	}
199838d5c833SDouglas Gilbert 	if (alloc_len > 8192)
199938d5c833SDouglas Gilbert 		a_len = 8192;
200038d5c833SDouglas Gilbert 	else
200138d5c833SDouglas Gilbert 		a_len = alloc_len;
200299531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
200338d5c833SDouglas Gilbert 	if (NULL == arr) {
200438d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
200538d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
200638d5c833SDouglas Gilbert 		return check_condition_result;
200738d5c833SDouglas Gilbert 	}
200838d5c833SDouglas Gilbert 	switch (reporting_opts) {
200938d5c833SDouglas Gilbert 	case 0:	/* all commands */
201038d5c833SDouglas Gilbert 		/* count number of commands */
201138d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
201238d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
201338d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
201438d5c833SDouglas Gilbert 				continue;
201538d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
201638d5c833SDouglas Gilbert 		}
201738d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
201838d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
201938d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
202038d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
202138d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
202238d5c833SDouglas Gilbert 				continue;
202338d5c833SDouglas Gilbert 			na = oip->num_attached;
202438d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
202538d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
202638d5c833SDouglas Gilbert 			if (rctd)
202738d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
202838d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
202938d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
203038d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
203138d5c833SDouglas Gilbert 			if (rctd)
203238d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
203338d5c833SDouglas Gilbert 			r_oip = oip;
203438d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
203538d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
203638d5c833SDouglas Gilbert 					continue;
203738d5c833SDouglas Gilbert 				offset += bump;
203838d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
203938d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
204038d5c833SDouglas Gilbert 				if (rctd)
204138d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
204238d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
204338d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
204438d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
204538d5c833SDouglas Gilbert 						   arr + offset + 6);
204638d5c833SDouglas Gilbert 				if (rctd)
204738d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
204838d5c833SDouglas Gilbert 							   arr + offset + 8);
204938d5c833SDouglas Gilbert 			}
205038d5c833SDouglas Gilbert 			oip = r_oip;
205138d5c833SDouglas Gilbert 			offset += bump;
205238d5c833SDouglas Gilbert 		}
205338d5c833SDouglas Gilbert 		break;
205438d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
205538d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
205638d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
205738d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
205838d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
205938d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
206038d5c833SDouglas Gilbert 			supp = 1;
206138d5c833SDouglas Gilbert 			offset = 4;
206238d5c833SDouglas Gilbert 		} else {
206338d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
206438d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
206538d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
206638d5c833SDouglas Gilbert 							     2, 2);
206738d5c833SDouglas Gilbert 					kfree(arr);
206838d5c833SDouglas Gilbert 					return check_condition_result;
206938d5c833SDouglas Gilbert 				}
207038d5c833SDouglas Gilbert 				req_sa = 0;
207138d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
207238d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
207338d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
207438d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
207538d5c833SDouglas Gilbert 				return check_condition_result;
207638d5c833SDouglas Gilbert 			}
207738d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
207838d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
207938d5c833SDouglas Gilbert 				supp = 3;
208038d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
208138d5c833SDouglas Gilbert 				na = oip->num_attached;
208238d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
208338d5c833SDouglas Gilbert 				     ++k, ++oip) {
208438d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
208538d5c833SDouglas Gilbert 						break;
208638d5c833SDouglas Gilbert 				}
208738d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208838d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
208938d5c833SDouglas Gilbert 				na = oip->num_attached;
209038d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
209138d5c833SDouglas Gilbert 				     ++k, ++oip) {
209238d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
209338d5c833SDouglas Gilbert 						break;
209438d5c833SDouglas Gilbert 				}
209538d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
209638d5c833SDouglas Gilbert 			} else
209738d5c833SDouglas Gilbert 				supp = 3;
209838d5c833SDouglas Gilbert 			if (3 == supp) {
209938d5c833SDouglas Gilbert 				u = oip->len_mask[0];
210038d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
210138d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
210238d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
210338d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
210438d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
210538d5c833SDouglas Gilbert 				offset = 4 + u;
210638d5c833SDouglas Gilbert 			} else
210738d5c833SDouglas Gilbert 				offset = 4;
210838d5c833SDouglas Gilbert 		}
210938d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
211038d5c833SDouglas Gilbert 		if (rctd) {
211138d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
211238d5c833SDouglas Gilbert 			offset += 12;
211338d5c833SDouglas Gilbert 		}
211438d5c833SDouglas Gilbert 		break;
211538d5c833SDouglas Gilbert 	default:
211638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
211738d5c833SDouglas Gilbert 		kfree(arr);
211838d5c833SDouglas Gilbert 		return check_condition_result;
211938d5c833SDouglas Gilbert 	}
212038d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
212138d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
212238d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
212338d5c833SDouglas Gilbert 	kfree(arr);
212438d5c833SDouglas Gilbert 	return errsts;
212538d5c833SDouglas Gilbert }
212638d5c833SDouglas Gilbert 
2127fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2128fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
212938d5c833SDouglas Gilbert {
213038d5c833SDouglas Gilbert 	bool repd;
213138d5c833SDouglas Gilbert 	u32 alloc_len, len;
213238d5c833SDouglas Gilbert 	u8 arr[16];
213338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
213438d5c833SDouglas Gilbert 
213538d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
213638d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
213738d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
213838d5c833SDouglas Gilbert 	if (alloc_len < 4) {
213938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
214038d5c833SDouglas Gilbert 		return check_condition_result;
214138d5c833SDouglas Gilbert 	}
214238d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
214338d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
214438d5c833SDouglas Gilbert 	if (repd) {
214538d5c833SDouglas Gilbert 		arr[3] = 0xc;
214638d5c833SDouglas Gilbert 		len = 16;
214738d5c833SDouglas Gilbert 	} else
214838d5c833SDouglas Gilbert 		len = 4;
214938d5c833SDouglas Gilbert 
215038d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
215138d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
215238d5c833SDouglas Gilbert }
215338d5c833SDouglas Gilbert 
21541da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21551da177e4SLinus Torvalds 
21561da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21571da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21581da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21591da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21621da177e4SLinus Torvalds 	if (1 == pcontrol)
21631da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21641da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21651da177e4SLinus Torvalds }
21661da177e4SLinus Torvalds 
21671da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21681da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21691da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21701da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21711da177e4SLinus Torvalds 
21721da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21731da177e4SLinus Torvalds 	if (1 == pcontrol)
21741da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21751da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21761da177e4SLinus Torvalds }
21771da177e4SLinus Torvalds 
21781da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21791da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21801da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21811da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21821da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21831da177e4SLinus Torvalds 
21841da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2185773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2186773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2187773642d9SDouglas Gilbert 	if (sdebug_removable)
21881da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21891da177e4SLinus Torvalds 	if (1 == pcontrol)
21901da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21911da177e4SLinus Torvalds 	return sizeof(format_pg);
21921da177e4SLinus Torvalds }
21931da177e4SLinus Torvalds 
2194fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2195fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2196fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2197fd32119bSDouglas Gilbert 
21981da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21991da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2200cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2201cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2202cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22031da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22041da177e4SLinus Torvalds 
2205773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2206cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22071da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22081da177e4SLinus Torvalds 	if (1 == pcontrol)
2209cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2210cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2211cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22121da177e4SLinus Torvalds 	return sizeof(caching_pg);
22131da177e4SLinus Torvalds }
22141da177e4SLinus Torvalds 
2215fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2216fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2217fd32119bSDouglas Gilbert 
22181da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22191da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2220c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2221c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2222c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22231da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22241da177e4SLinus Torvalds 
2225773642d9SDouglas Gilbert 	if (sdebug_dsense)
22261da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2227c65b1445SDouglas Gilbert 	else
2228c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2229c6a44287SMartin K. Petersen 
2230773642d9SDouglas Gilbert 	if (sdebug_ato)
2231c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2232c6a44287SMartin K. Petersen 
22331da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22341da177e4SLinus Torvalds 	if (1 == pcontrol)
2235c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2236c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2237c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22381da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22391da177e4SLinus Torvalds }
22401da177e4SLinus Torvalds 
2241c65b1445SDouglas Gilbert 
22421da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22431da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2244c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22451da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2246c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2247c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2248c65b1445SDouglas Gilbert 
22491da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22501da177e4SLinus Torvalds 	if (1 == pcontrol)
2251c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2252c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2253c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22541da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22551da177e4SLinus Torvalds }
22561da177e4SLinus Torvalds 
2257c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2258c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2259c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2260c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2261c65b1445SDouglas Gilbert 
2262c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2263c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2264c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2265c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2266c65b1445SDouglas Gilbert }
2267c65b1445SDouglas Gilbert 
2268c65b1445SDouglas Gilbert 
2269c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2270c65b1445SDouglas Gilbert 			      int target_dev_id)
2271c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2272c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2273c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2274773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2275773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2276c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2277c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2278c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2279c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2280773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2281773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2282c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2283c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2284c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2285c65b1445SDouglas Gilbert 		};
2286c65b1445SDouglas Gilbert 	int port_a, port_b;
2287c65b1445SDouglas Gilbert 
22881b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22891b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22911b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2292c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2293c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2294c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2295773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2296773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2297c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2298c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2299c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2300c65b1445SDouglas Gilbert }
2301c65b1445SDouglas Gilbert 
2302c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2303c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2304c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2305c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2306c65b1445SDouglas Gilbert 		};
2307c65b1445SDouglas Gilbert 
2308c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2309c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2310c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2311c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2312c65b1445SDouglas Gilbert }
2313c65b1445SDouglas Gilbert 
23141da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23151da177e4SLinus Torvalds 
2316fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2317fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23181da177e4SLinus Torvalds {
231923183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23201da177e4SLinus Torvalds 	unsigned char dev_spec;
232136e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
232236e07d7eSGeorge Kennedy 	int target_dev_id;
2323c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23241da177e4SLinus Torvalds 	unsigned char *ap;
23251da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
232601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2327d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23281da177e4SLinus Torvalds 
2329760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23301da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23311da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23321da177e4SLinus Torvalds 	subpcode = cmd[3];
23331da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2334760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2335760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
233664e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2337d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
233823183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
233923183910SDouglas Gilbert 	else
234023183910SDouglas Gilbert 		bd_len = 0;
2341773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23421da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23431da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2344cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23451da177e4SLinus Torvalds 		return check_condition_result;
23461da177e4SLinus Torvalds 	}
2347c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2348c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2349d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2350d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2351b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23529447b6ceSMartin K. Petersen 		if (sdebug_wp)
23539447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23549447b6ceSMartin K. Petersen 	} else
235523183910SDouglas Gilbert 		dev_spec = 0x0;
23561da177e4SLinus Torvalds 	if (msense_6) {
23571da177e4SLinus Torvalds 		arr[2] = dev_spec;
235823183910SDouglas Gilbert 		arr[3] = bd_len;
23591da177e4SLinus Torvalds 		offset = 4;
23601da177e4SLinus Torvalds 	} else {
23611da177e4SLinus Torvalds 		arr[3] = dev_spec;
236223183910SDouglas Gilbert 		if (16 == bd_len)
236323183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
236423183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23651da177e4SLinus Torvalds 		offset = 8;
23661da177e4SLinus Torvalds 	}
23671da177e4SLinus Torvalds 	ap = arr + offset;
236828898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
236928898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
237028898873SFUJITA Tomonori 
237123183910SDouglas Gilbert 	if (8 == bd_len) {
2372773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2373773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2374773642d9SDouglas Gilbert 		else
2375773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2376773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
237723183910SDouglas Gilbert 		offset += bd_len;
237823183910SDouglas Gilbert 		ap = arr + offset;
237923183910SDouglas Gilbert 	} else if (16 == bd_len) {
2380773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2381773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
238223183910SDouglas Gilbert 		offset += bd_len;
238323183910SDouglas Gilbert 		ap = arr + offset;
238423183910SDouglas Gilbert 	}
23851da177e4SLinus Torvalds 
2386c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2387c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
238822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23891da177e4SLinus Torvalds 		return check_condition_result;
23901da177e4SLinus Torvalds 	}
2391760f3b03SDouglas Gilbert 	bad_pcode = false;
2392760f3b03SDouglas Gilbert 
23931da177e4SLinus Torvalds 	switch (pcode) {
23941da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23951da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23961da177e4SLinus Torvalds 		offset += len;
23971da177e4SLinus Torvalds 		break;
23981da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23991da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24001da177e4SLinus Torvalds 		offset += len;
24011da177e4SLinus Torvalds 		break;
24021da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2403760f3b03SDouglas Gilbert 		if (is_disk) {
24041da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24051da177e4SLinus Torvalds 			offset += len;
2406760f3b03SDouglas Gilbert 		} else
2407760f3b03SDouglas Gilbert 			bad_pcode = true;
24081da177e4SLinus Torvalds 		break;
24091da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2410d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24111da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24121da177e4SLinus Torvalds 			offset += len;
2413760f3b03SDouglas Gilbert 		} else
2414760f3b03SDouglas Gilbert 			bad_pcode = true;
24151da177e4SLinus Torvalds 		break;
24161da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24171da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24181da177e4SLinus Torvalds 		offset += len;
24191da177e4SLinus Torvalds 		break;
2420c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2421c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
242222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2423c65b1445SDouglas Gilbert 			return check_condition_result;
2424c65b1445SDouglas Gilbert 		}
2425c65b1445SDouglas Gilbert 		len = 0;
2426c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2427c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2428c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2429c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2430c65b1445SDouglas Gilbert 						  target_dev_id);
2431c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2432c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2433c65b1445SDouglas Gilbert 		offset += len;
2434c65b1445SDouglas Gilbert 		break;
24351da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24361da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24371da177e4SLinus Torvalds 		offset += len;
24381da177e4SLinus Torvalds 		break;
24391da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2440c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24411da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24421da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2443760f3b03SDouglas Gilbert 			if (is_disk) {
2444760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2445760f3b03SDouglas Gilbert 						      target);
2446760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2447760f3b03SDouglas Gilbert 						       target);
2448d36da305SDouglas Gilbert 			} else if (is_zbc) {
2449d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2450d36da305SDouglas Gilbert 						       target);
2451760f3b03SDouglas Gilbert 			}
24521da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2453c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2454c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2455c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2456c65b1445SDouglas Gilbert 						  target, target_dev_id);
2457c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2458c65b1445SDouglas Gilbert 			}
24591da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2460760f3b03SDouglas Gilbert 			offset += len;
2461c65b1445SDouglas Gilbert 		} else {
246222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2463c65b1445SDouglas Gilbert 			return check_condition_result;
2464c65b1445SDouglas Gilbert 		}
24651da177e4SLinus Torvalds 		break;
24661da177e4SLinus Torvalds 	default:
2467760f3b03SDouglas Gilbert 		bad_pcode = true;
2468760f3b03SDouglas Gilbert 		break;
2469760f3b03SDouglas Gilbert 	}
2470760f3b03SDouglas Gilbert 	if (bad_pcode) {
247122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24721da177e4SLinus Torvalds 		return check_condition_result;
24731da177e4SLinus Torvalds 	}
24741da177e4SLinus Torvalds 	if (msense_6)
24751da177e4SLinus Torvalds 		arr[0] = offset - 1;
2476773642d9SDouglas Gilbert 	else
2477773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
247836e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
24791da177e4SLinus Torvalds }
24801da177e4SLinus Torvalds 
2481c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2482c65b1445SDouglas Gilbert 
2483fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2484fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2485c65b1445SDouglas Gilbert {
2486c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2487c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2488c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
248901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2490c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2491c65b1445SDouglas Gilbert 
2492c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2493c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2494c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2495773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2496c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
249722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2498c65b1445SDouglas Gilbert 		return check_condition_result;
2499c65b1445SDouglas Gilbert 	}
2500c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2501c65b1445SDouglas Gilbert 	if (-1 == res)
2502773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2503773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2504cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2505cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2506cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2507773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2508773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2509e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2510e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
251122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2512c65b1445SDouglas Gilbert 		return check_condition_result;
2513c65b1445SDouglas Gilbert 	}
2514c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2515c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2516c65b1445SDouglas Gilbert 	if (ps) {
251722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2518c65b1445SDouglas Gilbert 		return check_condition_result;
2519c65b1445SDouglas Gilbert 	}
2520c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2521773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2522c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2523c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2524cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2525c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2526c65b1445SDouglas Gilbert 		return check_condition_result;
2527c65b1445SDouglas Gilbert 	}
2528c65b1445SDouglas Gilbert 	switch (mpage) {
2529cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2530cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2531cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2532cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2533cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2534cbf67842SDouglas Gilbert 		}
2535cbf67842SDouglas Gilbert 		break;
2536c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2537c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2538c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2539c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25409447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25419447b6ceSMartin K. Petersen 				sdebug_wp = true;
25429447b6ceSMartin K. Petersen 			else
25439447b6ceSMartin K. Petersen 				sdebug_wp = false;
2544773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2545cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2546c65b1445SDouglas Gilbert 		}
2547c65b1445SDouglas Gilbert 		break;
2548c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2549c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2550c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2551c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2552cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2553c65b1445SDouglas Gilbert 		}
2554c65b1445SDouglas Gilbert 		break;
2555c65b1445SDouglas Gilbert 	default:
2556c65b1445SDouglas Gilbert 		break;
2557c65b1445SDouglas Gilbert 	}
255822017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2559c65b1445SDouglas Gilbert 	return check_condition_result;
2560cbf67842SDouglas Gilbert set_mode_changed_ua:
2561cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2562cbf67842SDouglas Gilbert 	return 0;
2563c65b1445SDouglas Gilbert }
2564c65b1445SDouglas Gilbert 
2565c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2566c65b1445SDouglas Gilbert {
2567c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2568c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2569c65b1445SDouglas Gilbert 		};
2570c65b1445SDouglas Gilbert 
2571c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2572c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2573c65b1445SDouglas Gilbert }
2574c65b1445SDouglas Gilbert 
2575c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2576c65b1445SDouglas Gilbert {
2577c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2578c65b1445SDouglas Gilbert 		};
2579c65b1445SDouglas Gilbert 
2580c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2581c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2582c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2583c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2584c65b1445SDouglas Gilbert 	}
2585c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2586c65b1445SDouglas Gilbert }
2587c65b1445SDouglas Gilbert 
2588c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2589c65b1445SDouglas Gilbert 
2590c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2591c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2592c65b1445SDouglas Gilbert {
259336e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
259436e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2595c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
259601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2597c65b1445SDouglas Gilbert 
2598c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2599c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2600c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2601c65b1445SDouglas Gilbert 	if (ppc || sp) {
260222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2603c65b1445SDouglas Gilbert 		return check_condition_result;
2604c65b1445SDouglas Gilbert 	}
2605c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
260623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2607773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2608c65b1445SDouglas Gilbert 	arr[0] = pcode;
260923183910SDouglas Gilbert 	if (0 == subpcode) {
2610c65b1445SDouglas Gilbert 		switch (pcode) {
2611c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2612c65b1445SDouglas Gilbert 			n = 4;
2613c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2614c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2615c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2616c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2617c65b1445SDouglas Gilbert 			break;
2618c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2619c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2620c65b1445SDouglas Gilbert 			break;
2621c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2622c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2623c65b1445SDouglas Gilbert 			break;
2624c65b1445SDouglas Gilbert 		default:
262522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2626c65b1445SDouglas Gilbert 			return check_condition_result;
2627c65b1445SDouglas Gilbert 		}
262823183910SDouglas Gilbert 	} else if (0xff == subpcode) {
262923183910SDouglas Gilbert 		arr[0] |= 0x40;
263023183910SDouglas Gilbert 		arr[1] = subpcode;
263123183910SDouglas Gilbert 		switch (pcode) {
263223183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
263323183910SDouglas Gilbert 			n = 4;
263423183910SDouglas Gilbert 			arr[n++] = 0x0;
263523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
263623183910SDouglas Gilbert 			arr[n++] = 0x0;
263723183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
263823183910SDouglas Gilbert 			arr[n++] = 0xd;
263923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
264023183910SDouglas Gilbert 			arr[n++] = 0x2f;
264123183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
264223183910SDouglas Gilbert 			arr[3] = n - 4;
264323183910SDouglas Gilbert 			break;
264423183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
264523183910SDouglas Gilbert 			n = 4;
264623183910SDouglas Gilbert 			arr[n++] = 0xd;
264723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
264823183910SDouglas Gilbert 			arr[3] = n - 4;
264923183910SDouglas Gilbert 			break;
265023183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
265123183910SDouglas Gilbert 			n = 4;
265223183910SDouglas Gilbert 			arr[n++] = 0x2f;
265323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
265423183910SDouglas Gilbert 			arr[3] = n - 4;
265523183910SDouglas Gilbert 			break;
265623183910SDouglas Gilbert 		default:
265722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
265823183910SDouglas Gilbert 			return check_condition_result;
265923183910SDouglas Gilbert 		}
266023183910SDouglas Gilbert 	} else {
266122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
266223183910SDouglas Gilbert 		return check_condition_result;
266323183910SDouglas Gilbert 	}
266436e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2665c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
266636e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2667c65b1445SDouglas Gilbert }
2668c65b1445SDouglas Gilbert 
2669f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2670f0d1cf93SDouglas Gilbert {
2671f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2672f0d1cf93SDouglas Gilbert }
2673f0d1cf93SDouglas Gilbert 
2674f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2675f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2676f0d1cf93SDouglas Gilbert {
2677108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2678f0d1cf93SDouglas Gilbert }
2679f0d1cf93SDouglas Gilbert 
2680f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2681f0d1cf93SDouglas Gilbert {
268264e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2683f0d1cf93SDouglas Gilbert }
2684f0d1cf93SDouglas Gilbert 
2685f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2686f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2687f0d1cf93SDouglas Gilbert {
2688f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2689f0d1cf93SDouglas Gilbert 
2690f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2691f0d1cf93SDouglas Gilbert 		return;
2692f0d1cf93SDouglas Gilbert 
2693f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2694f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2695f0d1cf93SDouglas Gilbert 		return;
2696f0d1cf93SDouglas Gilbert 
2697f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2698f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2699f0d1cf93SDouglas Gilbert 	else
2700f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2701f0d1cf93SDouglas Gilbert 
2702f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2703f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2704f0d1cf93SDouglas Gilbert 	} else {
2705f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2706f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2707f0d1cf93SDouglas Gilbert 	}
2708f0d1cf93SDouglas Gilbert }
2709f0d1cf93SDouglas Gilbert 
2710f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2711f0d1cf93SDouglas Gilbert {
2712f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2713f0d1cf93SDouglas Gilbert 	unsigned int i;
2714f0d1cf93SDouglas Gilbert 
2715f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2716f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2717f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2718f0d1cf93SDouglas Gilbert 			return;
2719f0d1cf93SDouglas Gilbert 		}
2720f0d1cf93SDouglas Gilbert 	}
2721f0d1cf93SDouglas Gilbert }
2722f0d1cf93SDouglas Gilbert 
2723f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2724f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2725f0d1cf93SDouglas Gilbert {
2726f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2727f0d1cf93SDouglas Gilbert 
2728f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2729f0d1cf93SDouglas Gilbert 		return;
2730f0d1cf93SDouglas Gilbert 
2731f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2732f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2733f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2734f0d1cf93SDouglas Gilbert 		return;
2735f0d1cf93SDouglas Gilbert 
2736f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2737f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2738f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2739f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2740f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2741f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2742f0d1cf93SDouglas Gilbert 
2743f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2744f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2745f0d1cf93SDouglas Gilbert 	if (explicit) {
2746f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2747f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2748f0d1cf93SDouglas Gilbert 	} else {
2749f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2750f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2751f0d1cf93SDouglas Gilbert 	}
2752f0d1cf93SDouglas Gilbert }
2753f0d1cf93SDouglas Gilbert 
2754f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2755f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2756f0d1cf93SDouglas Gilbert {
2757f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
275864e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2759f0d1cf93SDouglas Gilbert 
2760f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2761f0d1cf93SDouglas Gilbert 		return;
2762f0d1cf93SDouglas Gilbert 
276364e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2764f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
276564e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2766f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
276764e14eceSDamien Le Moal 		return;
276864e14eceSDamien Le Moal 	}
276964e14eceSDamien Le Moal 
277064e14eceSDamien Le Moal 	while (num) {
277164e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
277264e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
277364e14eceSDamien Le Moal 
277464e14eceSDamien Le Moal 		end = lba + num;
277564e14eceSDamien Le Moal 		if (end >= zend) {
277664e14eceSDamien Le Moal 			n = zend - lba;
277764e14eceSDamien Le Moal 			zsp->z_wp = zend;
277864e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
277964e14eceSDamien Le Moal 			n = num;
278064e14eceSDamien Le Moal 			zsp->z_wp = end;
278164e14eceSDamien Le Moal 		} else {
278264e14eceSDamien Le Moal 			n = num;
278364e14eceSDamien Le Moal 		}
278464e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
278564e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
278664e14eceSDamien Le Moal 
278764e14eceSDamien Le Moal 		num -= n;
278864e14eceSDamien Le Moal 		lba += n;
278964e14eceSDamien Le Moal 		if (num) {
279064e14eceSDamien Le Moal 			zsp++;
279164e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
279264e14eceSDamien Le Moal 		}
279364e14eceSDamien Le Moal 	}
2794f0d1cf93SDouglas Gilbert }
2795f0d1cf93SDouglas Gilbert 
2796f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27979447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27981da177e4SLinus Torvalds {
2799f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2800f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2801f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2802f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2803f0d1cf93SDouglas Gilbert 
2804f0d1cf93SDouglas Gilbert 	if (!write) {
280564e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
280664e14eceSDamien Le Moal 			return 0;
280764e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2808f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2809f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2810f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2811f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2812f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2813f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2814f0d1cf93SDouglas Gilbert 			return check_condition_result;
2815f0d1cf93SDouglas Gilbert 		}
2816f0d1cf93SDouglas Gilbert 		return 0;
2817f0d1cf93SDouglas Gilbert 	}
2818f0d1cf93SDouglas Gilbert 
2819f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2820f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2821f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2822f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2823f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2824f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2825f0d1cf93SDouglas Gilbert 			return check_condition_result;
2826f0d1cf93SDouglas Gilbert 		}
2827f0d1cf93SDouglas Gilbert 		return 0;
2828f0d1cf93SDouglas Gilbert 	}
2829f0d1cf93SDouglas Gilbert 
283064e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2831f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2832f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2833f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2834f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2835f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2836f0d1cf93SDouglas Gilbert 			return check_condition_result;
2837f0d1cf93SDouglas Gilbert 		}
2838f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2839f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2840f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2841f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2842f0d1cf93SDouglas Gilbert 			return check_condition_result;
2843f0d1cf93SDouglas Gilbert 		}
2844f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2845f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2846f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2847f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2848f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2849f0d1cf93SDouglas Gilbert 			return check_condition_result;
2850f0d1cf93SDouglas Gilbert 		}
285164e14eceSDamien Le Moal 	}
2852f0d1cf93SDouglas Gilbert 
2853f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2854f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2855f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2856f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2857f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2858f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2859f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2860f0d1cf93SDouglas Gilbert 			return check_condition_result;
2861f0d1cf93SDouglas Gilbert 		}
2862f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2863f0d1cf93SDouglas Gilbert 	}
2864f0d1cf93SDouglas Gilbert 
2865f0d1cf93SDouglas Gilbert 	return 0;
2866f0d1cf93SDouglas Gilbert }
2867f0d1cf93SDouglas Gilbert 
2868f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2869f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2870f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2871f0d1cf93SDouglas Gilbert {
2872f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2873f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2874f0d1cf93SDouglas Gilbert 
2875c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
287622017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28771da177e4SLinus Torvalds 		return check_condition_result;
28781da177e4SLinus Torvalds 	}
2879c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2880c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
288122017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2882cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2883c65b1445SDouglas Gilbert 		return check_condition_result;
2884c65b1445SDouglas Gilbert 	}
28859447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28869447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28879447b6ceSMartin K. Petersen 		return check_condition_result;
28889447b6ceSMartin K. Petersen 	}
2889f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2890f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2891f0d1cf93SDouglas Gilbert 
289219789100SFUJITA Tomonori 	return 0;
289319789100SFUJITA Tomonori }
289419789100SFUJITA Tomonori 
2895b6ff8ca7SDouglas Gilbert /*
2896b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2897b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2898b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2899b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2900b6ff8ca7SDouglas Gilbert  */
2901b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2902b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
290387c715dcSDouglas Gilbert {
2904b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2905b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2906b6ff8ca7SDouglas Gilbert 		return NULL;
2907b6ff8ca7SDouglas Gilbert 	}
2908b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
290987c715dcSDouglas Gilbert }
291087c715dcSDouglas Gilbert 
2911a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
291287c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
291387c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
291419789100SFUJITA Tomonori {
291519789100SFUJITA Tomonori 	int ret;
2916c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2917a4517511SAkinobu Mita 	enum dma_data_direction dir;
291887c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
291987c715dcSDouglas Gilbert 	u8 *fsp;
292019789100SFUJITA Tomonori 
2921c2248fc9SDouglas Gilbert 	if (do_write) {
2922a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
29234f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2924a4517511SAkinobu Mita 	} else {
2925a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2926a4517511SAkinobu Mita 	}
2927a4517511SAkinobu Mita 
292887c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2929a4517511SAkinobu Mita 		return 0;
293087c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2931a4517511SAkinobu Mita 		return -1;
293287c715dcSDouglas Gilbert 	fsp = sip->storep;
293319789100SFUJITA Tomonori 
293419789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
293519789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
293619789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
293719789100SFUJITA Tomonori 
2938386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
293987c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29400a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2941773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2942a4517511SAkinobu Mita 		return ret;
2943a4517511SAkinobu Mita 
2944a4517511SAkinobu Mita 	if (rest) {
2945386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
294687c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29470a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29480a7e69c7SDouglas Gilbert 			    do_write);
2949a4517511SAkinobu Mita 	}
295019789100SFUJITA Tomonori 
295119789100SFUJITA Tomonori 	return ret;
295219789100SFUJITA Tomonori }
295319789100SFUJITA Tomonori 
295487c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
295587c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
295687c715dcSDouglas Gilbert {
295787c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
295887c715dcSDouglas Gilbert 
295987c715dcSDouglas Gilbert 	if (!sdb->length)
296087c715dcSDouglas Gilbert 		return 0;
296187c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
296287c715dcSDouglas Gilbert 		return -1;
296387c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
296487c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
296587c715dcSDouglas Gilbert }
296687c715dcSDouglas Gilbert 
296787c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
296887c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
296938d5c833SDouglas Gilbert  * return false. */
297087c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2971c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
297238d5c833SDouglas Gilbert {
297338d5c833SDouglas Gilbert 	bool res;
297438d5c833SDouglas Gilbert 	u64 block, rest = 0;
297538d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2976773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
297787c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
297838d5c833SDouglas Gilbert 
297938d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
298038d5c833SDouglas Gilbert 	if (block + num > store_blks)
298138d5c833SDouglas Gilbert 		rest = block + num - store_blks;
298238d5c833SDouglas Gilbert 
298387c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
298438d5c833SDouglas Gilbert 	if (!res)
298538d5c833SDouglas Gilbert 		return res;
298638d5c833SDouglas Gilbert 	if (rest)
298787c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
298838d5c833SDouglas Gilbert 			     rest * lb_size);
298938d5c833SDouglas Gilbert 	if (!res)
299038d5c833SDouglas Gilbert 		return res;
2991c3e2fe92SDouglas Gilbert 	if (compare_only)
2992c3e2fe92SDouglas Gilbert 		return true;
299338d5c833SDouglas Gilbert 	arr += num * lb_size;
299487c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
299538d5c833SDouglas Gilbert 	if (rest)
299687c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
299738d5c833SDouglas Gilbert 	return res;
299838d5c833SDouglas Gilbert }
299938d5c833SDouglas Gilbert 
300051d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3001beb40ea4SAkinobu Mita {
300251d648afSAkinobu Mita 	__be16 csum;
3003beb40ea4SAkinobu Mita 
3004773642d9SDouglas Gilbert 	if (sdebug_guard)
300551d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
300651d648afSAkinobu Mita 	else
3007beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
300851d648afSAkinobu Mita 
3009beb40ea4SAkinobu Mita 	return csum;
3010beb40ea4SAkinobu Mita }
3011beb40ea4SAkinobu Mita 
30126ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3013beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3014beb40ea4SAkinobu Mita {
3015773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3016beb40ea4SAkinobu Mita 
3017beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3018c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3019beb40ea4SAkinobu Mita 			(unsigned long)sector,
3020beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3021beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3022beb40ea4SAkinobu Mita 		return 0x01;
3023beb40ea4SAkinobu Mita 	}
30248475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3025beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3026c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3027c1287970STomas Winkler 			(unsigned long)sector);
3028beb40ea4SAkinobu Mita 		return 0x03;
3029beb40ea4SAkinobu Mita 	}
30308475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3031beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3032c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3033c1287970STomas Winkler 			(unsigned long)sector);
3034beb40ea4SAkinobu Mita 		return 0x03;
3035beb40ea4SAkinobu Mita 	}
3036beb40ea4SAkinobu Mita 	return 0;
3037beb40ea4SAkinobu Mita }
3038beb40ea4SAkinobu Mita 
303987c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
304065f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3041c6a44287SMartin K. Petersen {
3042be4e11beSAkinobu Mita 	size_t resid;
3043c6a44287SMartin K. Petersen 	void *paddr;
304487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3045b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
304687c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
304714faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3048be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3049c6a44287SMartin K. Petersen 
3050e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3051e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3052c6a44287SMartin K. Petersen 
305387c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
305487c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3055be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3056be4e11beSAkinobu Mita 
3057be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
305887c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
305987c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3060be4e11beSAkinobu Mita 		size_t rest = 0;
306114faa944SAkinobu Mita 
306214faa944SAkinobu Mita 		if (dif_store_end < start + len)
306314faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3064c6a44287SMartin K. Petersen 
3065be4e11beSAkinobu Mita 		paddr = miter.addr;
306614faa944SAkinobu Mita 
306765f72f2aSAkinobu Mita 		if (read)
306865f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
306965f72f2aSAkinobu Mita 		else
307065f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
307165f72f2aSAkinobu Mita 
307265f72f2aSAkinobu Mita 		if (rest) {
307365f72f2aSAkinobu Mita 			if (read)
307414faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
307565f72f2aSAkinobu Mita 			else
307665f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
307765f72f2aSAkinobu Mita 		}
3078c6a44287SMartin K. Petersen 
3079e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3080c6a44287SMartin K. Petersen 		resid -= len;
3081c6a44287SMartin K. Petersen 	}
3082be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3083bb8c063cSAkinobu Mita }
3084c6a44287SMartin K. Petersen 
308587c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3086bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3087bb8c063cSAkinobu Mita {
3088f7be6772SMartin K. Petersen 	int ret = 0;
3089bb8c063cSAkinobu Mita 	unsigned int i;
3090bb8c063cSAkinobu Mita 	sector_t sector;
309187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3092b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
309387c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3094bb8c063cSAkinobu Mita 
3095c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3096bb8c063cSAkinobu Mita 		sector = start_sec + i;
309787c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3098bb8c063cSAkinobu Mita 
309951d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3100bb8c063cSAkinobu Mita 			continue;
3101bb8c063cSAkinobu Mita 
3102f7be6772SMartin K. Petersen 		/*
3103f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3104f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3105f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3106f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3107f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3108f7be6772SMartin K. Petersen 		 */
3109f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3110f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3111f7be6772SMartin K. Petersen 					 sector, ei_lba);
3112bb8c063cSAkinobu Mita 			if (ret) {
3113bb8c063cSAkinobu Mita 				dif_errors++;
3114f7be6772SMartin K. Petersen 				break;
3115f7be6772SMartin K. Petersen 			}
3116bb8c063cSAkinobu Mita 		}
3117bb8c063cSAkinobu Mita 	}
3118bb8c063cSAkinobu Mita 
311987c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3120c6a44287SMartin K. Petersen 	dix_reads++;
3121c6a44287SMartin K. Petersen 
3122f7be6772SMartin K. Petersen 	return ret;
3123c6a44287SMartin K. Petersen }
3124c6a44287SMartin K. Petersen 
3125fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
312619789100SFUJITA Tomonori {
312787c715dcSDouglas Gilbert 	bool check_prot;
3128c2248fc9SDouglas Gilbert 	u32 num;
3129c2248fc9SDouglas Gilbert 	u32 ei_lba;
313019789100SFUJITA Tomonori 	int ret;
313187c715dcSDouglas Gilbert 	u64 lba;
3132b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
313387c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
313487c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
313519789100SFUJITA Tomonori 
3136c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3137c2248fc9SDouglas Gilbert 	case READ_16:
3138c2248fc9SDouglas Gilbert 		ei_lba = 0;
3139c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3140c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3141c2248fc9SDouglas Gilbert 		check_prot = true;
3142c2248fc9SDouglas Gilbert 		break;
3143c2248fc9SDouglas Gilbert 	case READ_10:
3144c2248fc9SDouglas Gilbert 		ei_lba = 0;
3145c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3146c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3147c2248fc9SDouglas Gilbert 		check_prot = true;
3148c2248fc9SDouglas Gilbert 		break;
3149c2248fc9SDouglas Gilbert 	case READ_6:
3150c2248fc9SDouglas Gilbert 		ei_lba = 0;
3151c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3152c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3153c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3154c2248fc9SDouglas Gilbert 		check_prot = true;
3155c2248fc9SDouglas Gilbert 		break;
3156c2248fc9SDouglas Gilbert 	case READ_12:
3157c2248fc9SDouglas Gilbert 		ei_lba = 0;
3158c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3159c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3160c2248fc9SDouglas Gilbert 		check_prot = true;
3161c2248fc9SDouglas Gilbert 		break;
3162c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3163c2248fc9SDouglas Gilbert 		ei_lba = 0;
3164c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3165c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3166c2248fc9SDouglas Gilbert 		check_prot = false;
3167c2248fc9SDouglas Gilbert 		break;
3168c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3169c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3170c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3171c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3172c2248fc9SDouglas Gilbert 		check_prot = false;
3173c2248fc9SDouglas Gilbert 		break;
3174c2248fc9SDouglas Gilbert 	}
3175f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31768475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3177c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3178c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3179c2248fc9SDouglas Gilbert 			return check_condition_result;
3180c2248fc9SDouglas Gilbert 		}
31818475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31828475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3183c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3184c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3185c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3186c2248fc9SDouglas Gilbert 	}
31873a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
31883a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3189c2248fc9SDouglas Gilbert 		num /= 2;
31903a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3191c2248fc9SDouglas Gilbert 	}
3192c2248fc9SDouglas Gilbert 
31939447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31949447b6ceSMartin K. Petersen 	if (ret)
31959447b6ceSMartin K. Petersen 		return ret;
3196f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3197d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3198d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3199c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3200c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3201c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3202c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3203c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
320432f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
320532f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3206c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3207c65b1445SDouglas Gilbert 		}
3208c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
32091da177e4SLinus Torvalds 		return check_condition_result;
32101da177e4SLinus Torvalds 	}
3211c6a44287SMartin K. Petersen 
321267da413fSDouglas Gilbert 	read_lock(macc_lckp);
32136c78cc06SAkinobu Mita 
3214c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3215f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3216f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3217f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3218f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
321967da413fSDouglas Gilbert 				read_unlock(macc_lckp);
3220f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3221f7be6772SMartin K. Petersen 				return check_condition_result;
3222f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
3223f7be6772SMartin K. Petersen 				read_unlock(macc_lckp);
3224f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3225c6a44287SMartin K. Petersen 				return illegal_condition_result;
3226c6a44287SMartin K. Petersen 			}
3227f7be6772SMartin K. Petersen 			break;
3228f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3229f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
3230f7be6772SMartin K. Petersen 				read_unlock(macc_lckp);
3231f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3232f7be6772SMartin K. Petersen 				return check_condition_result;
3233f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
3234f7be6772SMartin K. Petersen 				read_unlock(macc_lckp);
3235f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3236f7be6772SMartin K. Petersen 				return illegal_condition_result;
3237f7be6772SMartin K. Petersen 			}
3238f7be6772SMartin K. Petersen 			break;
3239f7be6772SMartin K. Petersen 		}
3240c6a44287SMartin K. Petersen 	}
3241c6a44287SMartin K. Petersen 
324287c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
324367da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3244f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3245a4517511SAkinobu Mita 		return DID_ERROR << 16;
3246a4517511SAkinobu Mita 
324742d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3248a4517511SAkinobu Mita 
32493a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
32503a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
32513a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
32523a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
32533a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3254c2248fc9SDouglas Gilbert 			return check_condition_result;
32553a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3256c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3257c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
32583a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3259c2248fc9SDouglas Gilbert 			return illegal_condition_result;
32603a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3261c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
32623a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3263c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3264c2248fc9SDouglas Gilbert 		}
3265c2248fc9SDouglas Gilbert 	}
3266a4517511SAkinobu Mita 	return 0;
32671da177e4SLinus Torvalds }
32681da177e4SLinus Torvalds 
3269c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3270395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3271c6a44287SMartin K. Petersen {
3272be4e11beSAkinobu Mita 	int ret;
32736ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3274be4e11beSAkinobu Mita 	void *daddr;
327565f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3276c6a44287SMartin K. Petersen 	int ppage_offset;
3277be4e11beSAkinobu Mita 	int dpage_offset;
3278be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3279be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3280c6a44287SMartin K. Petersen 
3281c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3282c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3283c6a44287SMartin K. Petersen 
3284be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3285be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3286be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3287be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3288be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3289c6a44287SMartin K. Petersen 
3290be4e11beSAkinobu Mita 	/* For each protection page */
3291be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3292be4e11beSAkinobu Mita 		dpage_offset = 0;
3293be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3294be4e11beSAkinobu Mita 			ret = 0x01;
3295be4e11beSAkinobu Mita 			goto out;
3296c6a44287SMartin K. Petersen 		}
3297c6a44287SMartin K. Petersen 
3298be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32996ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3300be4e11beSAkinobu Mita 			/* If we're at the end of the current
3301be4e11beSAkinobu Mita 			 * data page advance to the next one
3302be4e11beSAkinobu Mita 			 */
3303be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3304be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3305be4e11beSAkinobu Mita 					ret = 0x01;
3306be4e11beSAkinobu Mita 					goto out;
3307be4e11beSAkinobu Mita 				}
3308be4e11beSAkinobu Mita 				dpage_offset = 0;
3309be4e11beSAkinobu Mita 			}
3310c6a44287SMartin K. Petersen 
3311be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3312be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3313be4e11beSAkinobu Mita 
3314f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3315be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3316c78be80dSMartin K. Petersen 				if (ret)
3317395cef03SMartin K. Petersen 					goto out;
3318395cef03SMartin K. Petersen 			}
3319395cef03SMartin K. Petersen 
3320c6a44287SMartin K. Petersen 			sector++;
3321395cef03SMartin K. Petersen 			ei_lba++;
3322773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3323c6a44287SMartin K. Petersen 		}
3324be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3325be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3326c6a44287SMartin K. Petersen 	}
3327be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3328c6a44287SMartin K. Petersen 
332965f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3330c6a44287SMartin K. Petersen 	dix_writes++;
3331c6a44287SMartin K. Petersen 
3332c6a44287SMartin K. Petersen 	return 0;
3333c6a44287SMartin K. Petersen 
3334c6a44287SMartin K. Petersen out:
3335c6a44287SMartin K. Petersen 	dif_errors++;
3336be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3337be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3338c6a44287SMartin K. Petersen 	return ret;
3339c6a44287SMartin K. Petersen }
3340c6a44287SMartin K. Petersen 
3341b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3342b90ebc3dSAkinobu Mita {
3343773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3344773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3345773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3346b90ebc3dSAkinobu Mita 	return lba;
3347b90ebc3dSAkinobu Mita }
3348b90ebc3dSAkinobu Mita 
3349b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3350b90ebc3dSAkinobu Mita {
3351773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3352a027b5b9SAkinobu Mita 
3353773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3354773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3355a027b5b9SAkinobu Mita 	return lba;
3356a027b5b9SAkinobu Mita }
3357a027b5b9SAkinobu Mita 
335887c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
335987c715dcSDouglas Gilbert 			      unsigned int *num)
336044d92694SMartin K. Petersen {
3361b90ebc3dSAkinobu Mita 	sector_t end;
3362b90ebc3dSAkinobu Mita 	unsigned int mapped;
3363b90ebc3dSAkinobu Mita 	unsigned long index;
3364b90ebc3dSAkinobu Mita 	unsigned long next;
336544d92694SMartin K. Petersen 
3366b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
336787c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
336844d92694SMartin K. Petersen 
336944d92694SMartin K. Petersen 	if (mapped)
337087c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
337144d92694SMartin K. Petersen 	else
337287c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
337344d92694SMartin K. Petersen 
3374b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
337544d92694SMartin K. Petersen 	*num = end - lba;
337644d92694SMartin K. Petersen 	return mapped;
337744d92694SMartin K. Petersen }
337844d92694SMartin K. Petersen 
337987c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
338087c715dcSDouglas Gilbert 		       unsigned int len)
338144d92694SMartin K. Petersen {
338244d92694SMartin K. Petersen 	sector_t end = lba + len;
338344d92694SMartin K. Petersen 
338444d92694SMartin K. Petersen 	while (lba < end) {
3385b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
338644d92694SMartin K. Petersen 
3387b90ebc3dSAkinobu Mita 		if (index < map_size)
338887c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
338944d92694SMartin K. Petersen 
3390b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
339144d92694SMartin K. Petersen 	}
339244d92694SMartin K. Petersen }
339344d92694SMartin K. Petersen 
339487c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
339587c715dcSDouglas Gilbert 			 unsigned int len)
339644d92694SMartin K. Petersen {
339744d92694SMartin K. Petersen 	sector_t end = lba + len;
339887c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
339944d92694SMartin K. Petersen 
340044d92694SMartin K. Petersen 	while (lba < end) {
3401b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
340244d92694SMartin K. Petersen 
3403b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3404773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3405b90ebc3dSAkinobu Mita 		    index < map_size) {
340687c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3407760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
340887c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3409760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3410773642d9SDouglas Gilbert 				       sdebug_sector_size *
3411773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3412be1dd78dSEric Sandeen 			}
341387c715dcSDouglas Gilbert 			if (sip->dif_storep) {
341487c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
341587c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3416773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3417e9926b43SAkinobu Mita 			}
3418b90ebc3dSAkinobu Mita 		}
3419b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
342044d92694SMartin K. Petersen 	}
342144d92694SMartin K. Petersen }
342244d92694SMartin K. Petersen 
3423fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34241da177e4SLinus Torvalds {
342587c715dcSDouglas Gilbert 	bool check_prot;
3426c2248fc9SDouglas Gilbert 	u32 num;
3427c2248fc9SDouglas Gilbert 	u32 ei_lba;
342819789100SFUJITA Tomonori 	int ret;
342987c715dcSDouglas Gilbert 	u64 lba;
3430b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3431b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
343287c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
34331da177e4SLinus Torvalds 
3434c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3435c2248fc9SDouglas Gilbert 	case WRITE_16:
3436c2248fc9SDouglas Gilbert 		ei_lba = 0;
3437c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3438c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3439c2248fc9SDouglas Gilbert 		check_prot = true;
3440c2248fc9SDouglas Gilbert 		break;
3441c2248fc9SDouglas Gilbert 	case WRITE_10:
3442c2248fc9SDouglas Gilbert 		ei_lba = 0;
3443c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3444c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3445c2248fc9SDouglas Gilbert 		check_prot = true;
3446c2248fc9SDouglas Gilbert 		break;
3447c2248fc9SDouglas Gilbert 	case WRITE_6:
3448c2248fc9SDouglas Gilbert 		ei_lba = 0;
3449c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3450c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3451c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3452c2248fc9SDouglas Gilbert 		check_prot = true;
3453c2248fc9SDouglas Gilbert 		break;
3454c2248fc9SDouglas Gilbert 	case WRITE_12:
3455c2248fc9SDouglas Gilbert 		ei_lba = 0;
3456c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3457c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3458c2248fc9SDouglas Gilbert 		check_prot = true;
3459c2248fc9SDouglas Gilbert 		break;
3460c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3461c2248fc9SDouglas Gilbert 		ei_lba = 0;
3462c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3463c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3464c2248fc9SDouglas Gilbert 		check_prot = false;
3465c2248fc9SDouglas Gilbert 		break;
3466c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3467c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3468c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3469c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3470c2248fc9SDouglas Gilbert 		check_prot = false;
3471c2248fc9SDouglas Gilbert 		break;
3472c2248fc9SDouglas Gilbert 	}
3473f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34748475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3475c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3476c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3477c2248fc9SDouglas Gilbert 			return check_condition_result;
3478c2248fc9SDouglas Gilbert 		}
34798475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34808475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3481c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3482c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3483c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3484c2248fc9SDouglas Gilbert 	}
3485f0d1cf93SDouglas Gilbert 
348667da413fSDouglas Gilbert 	write_lock(macc_lckp);
3487f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3488f0d1cf93SDouglas Gilbert 	if (ret) {
3489f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3490f0d1cf93SDouglas Gilbert 		return ret;
3491f0d1cf93SDouglas Gilbert 	}
34926c78cc06SAkinobu Mita 
3493c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3494f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3495f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3496f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3497f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
349867da413fSDouglas Gilbert 				write_unlock(macc_lckp);
3499f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3500c6a44287SMartin K. Petersen 				return illegal_condition_result;
3501f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
3502f7be6772SMartin K. Petersen 				write_unlock(macc_lckp);
3503f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3504f7be6772SMartin K. Petersen 				return check_condition_result;
3505f7be6772SMartin K. Petersen 			}
3506f7be6772SMartin K. Petersen 			break;
3507f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3508f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
3509f7be6772SMartin K. Petersen 				write_unlock(macc_lckp);
3510f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3511f7be6772SMartin K. Petersen 				return illegal_condition_result;
3512f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
3513f7be6772SMartin K. Petersen 				write_unlock(macc_lckp);
3514f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3515f7be6772SMartin K. Petersen 				return check_condition_result;
3516f7be6772SMartin K. Petersen 			}
3517f7be6772SMartin K. Petersen 			break;
3518c6a44287SMartin K. Petersen 		}
3519c6a44287SMartin K. Petersen 	}
3520c6a44287SMartin K. Petersen 
352187c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3522f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
352387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3524f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3525f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3526f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
352767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3528f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3529773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3530c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3531c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3532c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3533cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3534773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
353544d92694SMartin K. Petersen 
35363a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
35373a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
35383a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
35393a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
35403a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3541c2248fc9SDouglas Gilbert 			return check_condition_result;
35423a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3543c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3544c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
35453a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3546c2248fc9SDouglas Gilbert 			return illegal_condition_result;
35473a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3548c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
35493a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3550c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3551c2248fc9SDouglas Gilbert 		}
3552c2248fc9SDouglas Gilbert 	}
35531da177e4SLinus Torvalds 	return 0;
35541da177e4SLinus Torvalds }
35551da177e4SLinus Torvalds 
3556481b5e5cSDouglas Gilbert /*
3557481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3558481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3559481b5e5cSDouglas Gilbert  */
3560481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3561481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3562481b5e5cSDouglas Gilbert {
3563481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3564481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3565481b5e5cSDouglas Gilbert 	u8 *up;
3566b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3567b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
3568481b5e5cSDouglas Gilbert 	u8 wrprotect;
3569481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3570481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3571481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3572481b5e5cSDouglas Gilbert 	u32 ei_lba;
3573481b5e5cSDouglas Gilbert 	u64 lba;
3574481b5e5cSDouglas Gilbert 	int ret, res;
3575481b5e5cSDouglas Gilbert 	bool is_16;
3576481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3577481b5e5cSDouglas Gilbert 
3578481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3579481b5e5cSDouglas Gilbert 		is_16 = false;
3580481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3581481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3582481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3583481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3584481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3585481b5e5cSDouglas Gilbert 		is_16 = true;
3586481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3587481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3588481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3589481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3590481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3591481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3592481b5e5cSDouglas Gilbert 			    wrprotect) {
3593481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3594481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3595481b5e5cSDouglas Gilbert 			}
3596481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3597481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3598481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3599481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3600481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3601481b5e5cSDouglas Gilbert 		}
3602481b5e5cSDouglas Gilbert 	}
3603481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3604481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3605481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3606481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3607481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3608481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3609481b5e5cSDouglas Gilbert 				my_name, __func__);
3610481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3611481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3612481b5e5cSDouglas Gilbert 	}
3613481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3614481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3615481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3616481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3617481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3618481b5e5cSDouglas Gilbert 				my_name, __func__);
3619481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3620481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3621481b5e5cSDouglas Gilbert 	}
3622481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3623481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3624481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3625481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3626481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3627481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3628481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3629481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3630481b5e5cSDouglas Gilbert 	if (res == -1) {
3631481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3632481b5e5cSDouglas Gilbert 		goto err_out;
3633481b5e5cSDouglas Gilbert 	}
3634481b5e5cSDouglas Gilbert 
363567da413fSDouglas Gilbert 	write_lock(macc_lckp);
3636481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3637481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3638481b5e5cSDouglas Gilbert 	cum_lb = 0;
3639481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3640481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3641481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3642481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3643481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3644481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3645481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3646481b5e5cSDouglas Gilbert 		if (num == 0)
3647481b5e5cSDouglas Gilbert 			continue;
36489447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3649481b5e5cSDouglas Gilbert 		if (ret)
3650481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3651481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3652481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3653481b5e5cSDouglas Gilbert 
3654481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3655481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3656481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3657481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3658481b5e5cSDouglas Gilbert 				    my_name, __func__);
3659481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3660481b5e5cSDouglas Gilbert 					0);
3661481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3662481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3663481b5e5cSDouglas Gilbert 		}
3664481b5e5cSDouglas Gilbert 
3665481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3666481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3667481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3668481b5e5cSDouglas Gilbert 							 ei_lba);
3669481b5e5cSDouglas Gilbert 
3670481b5e5cSDouglas Gilbert 			if (prot_ret) {
3671481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3672481b5e5cSDouglas Gilbert 						prot_ret);
3673481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3674481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3675481b5e5cSDouglas Gilbert 			}
3676481b5e5cSDouglas Gilbert 		}
3677481b5e5cSDouglas Gilbert 
367887c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3679f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3680f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3681f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3682481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
368387c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3684481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3685481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3686481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3687481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3688481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3689481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3690481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3691481b5e5cSDouglas Gilbert 
36923a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36933a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
36943a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36953a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36963a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
36973a90a63dSDouglas Gilbert 				ret = check_condition_result;
3698481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36993a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3700481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
37013a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37023a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3703481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3704481b5e5cSDouglas Gilbert 				goto err_out_unlock;
37053a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
37063a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37073a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3708481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3709481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3710481b5e5cSDouglas Gilbert 			}
3711481b5e5cSDouglas Gilbert 		}
3712481b5e5cSDouglas Gilbert 		sg_off += num_by;
3713481b5e5cSDouglas Gilbert 		cum_lb += num;
3714481b5e5cSDouglas Gilbert 	}
3715481b5e5cSDouglas Gilbert 	ret = 0;
3716481b5e5cSDouglas Gilbert err_out_unlock:
371767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3718481b5e5cSDouglas Gilbert err_out:
3719481b5e5cSDouglas Gilbert 	kfree(lrdp);
3720481b5e5cSDouglas Gilbert 	return ret;
3721481b5e5cSDouglas Gilbert }
3722481b5e5cSDouglas Gilbert 
3723fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3724fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
372544d92694SMartin K. Petersen {
3726f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3727f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
372844d92694SMartin K. Petersen 	unsigned long long i;
372940d07b52SDouglas Gilbert 	u64 block, lbaa;
373087c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
373187c715dcSDouglas Gilbert 	int ret;
373287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3733b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
3734b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
373540d07b52SDouglas Gilbert 	u8 *fs1p;
373687c715dcSDouglas Gilbert 	u8 *fsp;
373744d92694SMartin K. Petersen 
373867da413fSDouglas Gilbert 	write_lock(macc_lckp);
373944d92694SMartin K. Petersen 
3740f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3741f0d1cf93SDouglas Gilbert 	if (ret) {
3742f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3743f0d1cf93SDouglas Gilbert 		return ret;
3744f0d1cf93SDouglas Gilbert 	}
3745f0d1cf93SDouglas Gilbert 
37469ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
374787c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
374844d92694SMartin K. Petersen 		goto out;
374944d92694SMartin K. Petersen 	}
375040d07b52SDouglas Gilbert 	lbaa = lba;
375140d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3752c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
375387c715dcSDouglas Gilbert 	fsp = sip->storep;
375487c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3755c2248fc9SDouglas Gilbert 	if (ndob) {
375640d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3757c2248fc9SDouglas Gilbert 		ret = 0;
3758c2248fc9SDouglas Gilbert 	} else
375940d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
376044d92694SMartin K. Petersen 
376144d92694SMartin K. Petersen 	if (-1 == ret) {
376267da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3763773642d9SDouglas Gilbert 		return DID_ERROR << 16;
376440d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3765c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3766e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
376740d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
376844d92694SMartin K. Petersen 
376944d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
377040d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
377140d07b52SDouglas Gilbert 		lbaa = lba + i;
377240d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
377387c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
377440d07b52SDouglas Gilbert 	}
37759ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
377687c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3777f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3778f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3779f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
378044d92694SMartin K. Petersen out:
378167da413fSDouglas Gilbert 	write_unlock(macc_lckp);
378244d92694SMartin K. Petersen 
378344d92694SMartin K. Petersen 	return 0;
378444d92694SMartin K. Petersen }
378544d92694SMartin K. Petersen 
3786fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3787fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3788c2248fc9SDouglas Gilbert {
3789c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3790c2248fc9SDouglas Gilbert 	u32 lba;
3791c2248fc9SDouglas Gilbert 	u16 num;
3792c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3793c2248fc9SDouglas Gilbert 	bool unmap = false;
3794c2248fc9SDouglas Gilbert 
3795c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3796773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 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 	lba = get_unaligned_be32(cmd + 2);
3803c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3804773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3805c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3806c2248fc9SDouglas Gilbert 		return check_condition_result;
3807c2248fc9SDouglas Gilbert 	}
3808c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3809c2248fc9SDouglas Gilbert }
3810c2248fc9SDouglas Gilbert 
3811fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3812fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3813c2248fc9SDouglas Gilbert {
3814c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3815c2248fc9SDouglas Gilbert 	u64 lba;
3816c2248fc9SDouglas Gilbert 	u32 num;
3817c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3818c2248fc9SDouglas Gilbert 	bool unmap = false;
3819c2248fc9SDouglas Gilbert 	bool ndob = false;
3820c2248fc9SDouglas Gilbert 
3821c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3822773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3823c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3824c2248fc9SDouglas Gilbert 			return check_condition_result;
3825c2248fc9SDouglas Gilbert 		} else
3826c2248fc9SDouglas Gilbert 			unmap = true;
3827c2248fc9SDouglas Gilbert 	}
3828c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3829c2248fc9SDouglas Gilbert 		ndob = true;
3830c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3831c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3832773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3833c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3834c2248fc9SDouglas Gilbert 		return check_condition_result;
3835c2248fc9SDouglas Gilbert 	}
3836c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3837c2248fc9SDouglas Gilbert }
3838c2248fc9SDouglas Gilbert 
3839acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3840acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3841acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3842fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3843fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3844acafd0b9SEwan D. Milne {
3845acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3846acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3847acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3848acafd0b9SEwan D. Milne 	u8 mode;
3849acafd0b9SEwan D. Milne 
3850acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3851acafd0b9SEwan D. Milne 	switch (mode) {
3852acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3853acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3854acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3855acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3856acafd0b9SEwan D. Milne 		break;
3857acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3858acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3859acafd0b9SEwan D. Milne 		break;
3860acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3861acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3862acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3863acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3864acafd0b9SEwan D. Milne 				    dev_list)
3865acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3866acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3867acafd0b9SEwan D. Milne 				if (devip != dp)
3868acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3869acafd0b9SEwan D. Milne 						dp->uas_bm);
3870acafd0b9SEwan D. Milne 			}
3871acafd0b9SEwan D. Milne 		break;
3872acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3873acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3874acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3875acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3876acafd0b9SEwan D. Milne 				    dev_list)
3877acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3878acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3879acafd0b9SEwan D. Milne 					dp->uas_bm);
3880acafd0b9SEwan D. Milne 		break;
3881acafd0b9SEwan D. Milne 	default:
3882acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3883acafd0b9SEwan D. Milne 		break;
3884acafd0b9SEwan D. Milne 	}
3885acafd0b9SEwan D. Milne 	return 0;
3886acafd0b9SEwan D. Milne }
3887acafd0b9SEwan D. Milne 
3888fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3889fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
389038d5c833SDouglas Gilbert {
389138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
389238d5c833SDouglas Gilbert 	u8 *arr;
3893b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3894b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
389538d5c833SDouglas Gilbert 	u64 lba;
389638d5c833SDouglas Gilbert 	u32 dnum;
3897773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
389838d5c833SDouglas Gilbert 	u8 num;
389938d5c833SDouglas Gilbert 	int ret;
3900d467d31fSDouglas Gilbert 	int retval = 0;
390138d5c833SDouglas Gilbert 
3902d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
390338d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
390438d5c833SDouglas Gilbert 	if (0 == num)
390538d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
39068475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
390738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
390838d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
390938d5c833SDouglas Gilbert 		return check_condition_result;
391038d5c833SDouglas Gilbert 	}
39118475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
39128475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
391338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
391438d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
391538d5c833SDouglas Gilbert 			    "to DIF device\n");
39169447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
39179447b6ceSMartin K. Petersen 	if (ret)
39189447b6ceSMartin K. Petersen 		return ret;
3919d467d31fSDouglas Gilbert 	dnum = 2 * num;
39206396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3921d467d31fSDouglas Gilbert 	if (NULL == arr) {
3922d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3923d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3924d467d31fSDouglas Gilbert 		return check_condition_result;
3925d467d31fSDouglas Gilbert 	}
392638d5c833SDouglas Gilbert 
392767da413fSDouglas Gilbert 	write_lock(macc_lckp);
392838d5c833SDouglas Gilbert 
392987c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
393038d5c833SDouglas Gilbert 	if (ret == -1) {
3931d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3932d467d31fSDouglas Gilbert 		goto cleanup;
3933773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
393438d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
393538d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
393638d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3937c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
393838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3939d467d31fSDouglas Gilbert 		retval = check_condition_result;
3940d467d31fSDouglas Gilbert 		goto cleanup;
394138d5c833SDouglas Gilbert 	}
394238d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
394387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3944d467d31fSDouglas Gilbert cleanup:
394567da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3946d467d31fSDouglas Gilbert 	kfree(arr);
3947d467d31fSDouglas Gilbert 	return retval;
394838d5c833SDouglas Gilbert }
394938d5c833SDouglas Gilbert 
395044d92694SMartin K. Petersen struct unmap_block_desc {
395144d92694SMartin K. Petersen 	__be64	lba;
395244d92694SMartin K. Petersen 	__be32	blocks;
395344d92694SMartin K. Petersen 	__be32	__reserved;
395444d92694SMartin K. Petersen };
395544d92694SMartin K. Petersen 
3956fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
395744d92694SMartin K. Petersen {
395844d92694SMartin K. Petersen 	unsigned char *buf;
395944d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
3960b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3961b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
396244d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
396344d92694SMartin K. Petersen 	int ret;
396444d92694SMartin K. Petersen 
3965c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3966c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3967c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3968c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
396944d92694SMartin K. Petersen 
397044d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3971773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3972c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
397344d92694SMartin K. Petersen 		return check_condition_result;
3974c2248fc9SDouglas Gilbert 	}
397544d92694SMartin K. Petersen 
3976b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3977c2248fc9SDouglas Gilbert 	if (!buf) {
3978c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3979c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3980c2248fc9SDouglas Gilbert 		return check_condition_result;
3981c2248fc9SDouglas Gilbert 	}
3982c2248fc9SDouglas Gilbert 
3983c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
398444d92694SMartin K. Petersen 
398544d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
398644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
398744d92694SMartin K. Petersen 
398844d92694SMartin K. Petersen 	desc = (void *)&buf[8];
398944d92694SMartin K. Petersen 
399067da413fSDouglas Gilbert 	write_lock(macc_lckp);
39916c78cc06SAkinobu Mita 
399244d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
399344d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
399444d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
399544d92694SMartin K. Petersen 
39969447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
399744d92694SMartin K. Petersen 		if (ret)
399844d92694SMartin K. Petersen 			goto out;
399944d92694SMartin K. Petersen 
400087c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
400144d92694SMartin K. Petersen 	}
400244d92694SMartin K. Petersen 
400344d92694SMartin K. Petersen 	ret = 0;
400444d92694SMartin K. Petersen 
400544d92694SMartin K. Petersen out:
400667da413fSDouglas Gilbert 	write_unlock(macc_lckp);
400744d92694SMartin K. Petersen 	kfree(buf);
400844d92694SMartin K. Petersen 
400944d92694SMartin K. Petersen 	return ret;
401044d92694SMartin K. Petersen }
401144d92694SMartin K. Petersen 
401244d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
401344d92694SMartin K. Petersen 
4014fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4015fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
401644d92694SMartin K. Petersen {
4017c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4018c2248fc9SDouglas Gilbert 	u64 lba;
4019c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
402044d92694SMartin K. Petersen 	int ret;
402187c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
402244d92694SMartin K. Petersen 
4023c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4024c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
402544d92694SMartin K. Petersen 
402644d92694SMartin K. Petersen 	if (alloc_len < 24)
402744d92694SMartin K. Petersen 		return 0;
402844d92694SMartin K. Petersen 
40299447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
403044d92694SMartin K. Petersen 	if (ret)
403144d92694SMartin K. Petersen 		return ret;
403244d92694SMartin K. Petersen 
4033b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4034b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4035b6ff8ca7SDouglas Gilbert 
403687c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4037b6ff8ca7SDouglas Gilbert 	} else {
4038c2248fc9SDouglas Gilbert 		mapped = 1;
4039c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4040c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4041c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4042c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4043c2248fc9SDouglas Gilbert 		else
4044c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4045c2248fc9SDouglas Gilbert 	}
404644d92694SMartin K. Petersen 
404744d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4048c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4049c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4050c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4051c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
405244d92694SMartin K. Petersen 
4053c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
405444d92694SMartin K. Petersen }
405544d92694SMartin K. Petersen 
405680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
405780c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
405880c49563SDouglas Gilbert {
40594f2c8bf6SDouglas Gilbert 	int res = 0;
406080c49563SDouglas Gilbert 	u64 lba;
406180c49563SDouglas Gilbert 	u32 num_blocks;
406280c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
406380c49563SDouglas Gilbert 
406480c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
406580c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
406680c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
406780c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
406880c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
406980c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
407080c49563SDouglas Gilbert 	}
407180c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
407280c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
407380c49563SDouglas Gilbert 		return check_condition_result;
407480c49563SDouglas Gilbert 	}
4075fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
40764f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40774f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40784f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40794f2c8bf6SDouglas Gilbert 	return res;
408080c49563SDouglas Gilbert }
408180c49563SDouglas Gilbert 
4082ed9f3e25SDouglas Gilbert /*
4083ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4084ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4085ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4086ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4087ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4088ed9f3e25SDouglas Gilbert  */
4089ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4090ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4091ed9f3e25SDouglas Gilbert {
4092ed9f3e25SDouglas Gilbert 	int res = 0;
4093ed9f3e25SDouglas Gilbert 	u64 lba;
4094ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4095ed9f3e25SDouglas Gilbert 	u32 nblks;
4096ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4097b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4098b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4099b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4100ed9f3e25SDouglas Gilbert 
4101ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4102ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4103ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4104ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4105ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4106ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4107ed9f3e25SDouglas Gilbert 	}
4108ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4109ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4110ed9f3e25SDouglas Gilbert 		return check_condition_result;
4111ed9f3e25SDouglas Gilbert 	}
4112ed9f3e25SDouglas Gilbert 	if (!fsp)
4113ed9f3e25SDouglas Gilbert 		goto fini;
4114ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4115ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4116ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4117ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4118ed9f3e25SDouglas Gilbert 
4119ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4120ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4121ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4122ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4123ed9f3e25SDouglas Gilbert 	if (rest)
4124ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4125ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4126ed9f3e25SDouglas Gilbert fini:
4127ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4128ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4129ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4130ed9f3e25SDouglas Gilbert }
4131ed9f3e25SDouglas Gilbert 
4132fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4133fb0cc8d1SDouglas Gilbert 
41348d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
41358d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
41368d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
41378d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41388d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
41398d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
41408d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
41418d039e22SDouglas Gilbert  */
41421da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
41431da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
41441da177e4SLinus Torvalds {
414501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
41468d039e22SDouglas Gilbert 	unsigned int alloc_len;
41478d039e22SDouglas Gilbert 	unsigned char select_report;
41488d039e22SDouglas Gilbert 	u64 lun;
41498d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4150fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41518d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41528d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
41538d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
41548d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4155fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4156fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4157fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41581da177e4SLinus Torvalds 
415919c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41608d039e22SDouglas Gilbert 
41618d039e22SDouglas Gilbert 	select_report = cmd[2];
41628d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41638d039e22SDouglas Gilbert 
41648d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41658d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41668d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41671da177e4SLinus Torvalds 		return check_condition_result;
41681da177e4SLinus Torvalds 	}
41698d039e22SDouglas Gilbert 
41708d039e22SDouglas Gilbert 	switch (select_report) {
41718d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4172773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41738d039e22SDouglas Gilbert 		wlun_cnt = 0;
41748d039e22SDouglas Gilbert 		break;
41758d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4176c65b1445SDouglas Gilbert 		lun_cnt = 0;
41778d039e22SDouglas Gilbert 		wlun_cnt = 1;
41788d039e22SDouglas Gilbert 		break;
41798d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41808d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41818d039e22SDouglas Gilbert 		wlun_cnt = 1;
41828d039e22SDouglas Gilbert 		break;
41838d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41848d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41858d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41868d039e22SDouglas Gilbert 	default:
41878d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41888d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41898d039e22SDouglas Gilbert 		return check_condition_result;
41908d039e22SDouglas Gilbert 	}
41918d039e22SDouglas Gilbert 
41928d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4193c65b1445SDouglas Gilbert 		--lun_cnt;
41948d039e22SDouglas Gilbert 
41958d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4196fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4197fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41988d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41998d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
42008d039e22SDouglas Gilbert 
4201fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
42028d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4203fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4204fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4205fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4206fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4207fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4208fb0cc8d1SDouglas Gilbert 			++lun_p;
4209fb0cc8d1SDouglas Gilbert 			j = 1;
4210fb0cc8d1SDouglas Gilbert 		}
4211fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4212fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4213fb0cc8d1SDouglas Gilbert 				break;
4214fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4215ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4216ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4217fb0cc8d1SDouglas Gilbert 		}
4218fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4219fb0cc8d1SDouglas Gilbert 			break;
4220fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4221fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4222fb0cc8d1SDouglas Gilbert 		if (res)
4223fb0cc8d1SDouglas Gilbert 			return res;
4224fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4225fb0cc8d1SDouglas Gilbert 	}
4226fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4227fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4228fb0cc8d1SDouglas Gilbert 		++j;
4229fb0cc8d1SDouglas Gilbert 	}
4230fb0cc8d1SDouglas Gilbert 	if (j > 0)
4231fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
42328d039e22SDouglas Gilbert 	return res;
42331da177e4SLinus Torvalds }
42341da177e4SLinus Torvalds 
4235c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4236c3e2fe92SDouglas Gilbert {
4237c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4238c3e2fe92SDouglas Gilbert 	u8 bytchk;
4239c3e2fe92SDouglas Gilbert 	int ret, j;
4240c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4241c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4242c3e2fe92SDouglas Gilbert 	u64 lba;
4243c3e2fe92SDouglas Gilbert 	u8 *arr;
4244c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4245b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4246b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4247c3e2fe92SDouglas Gilbert 
4248c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4249c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4250c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4251c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4252c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4253c3e2fe92SDouglas Gilbert 		return check_condition_result;
4254c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4255c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4256c3e2fe92SDouglas Gilbert 	}
4257c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4258c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4259c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4260c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4261c3e2fe92SDouglas Gilbert 		break;
4262c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4263c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4264c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4265c3e2fe92SDouglas Gilbert 		break;
4266c3e2fe92SDouglas Gilbert 	default:
4267c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4268c3e2fe92SDouglas Gilbert 		return check_condition_result;
4269c3e2fe92SDouglas Gilbert 	}
42703344b58bSGeorge Kennedy 	if (vnum == 0)
42713344b58bSGeorge Kennedy 		return 0;	/* not an error */
4272c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4273c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4274c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4275c3e2fe92SDouglas Gilbert 	if (ret)
4276c3e2fe92SDouglas Gilbert 		return ret;
4277c3e2fe92SDouglas Gilbert 
4278c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4279c3e2fe92SDouglas Gilbert 	if (!arr) {
4280c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4281c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4282c3e2fe92SDouglas Gilbert 		return check_condition_result;
4283c3e2fe92SDouglas Gilbert 	}
4284c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
428567da413fSDouglas Gilbert 	read_lock(macc_lckp);
4286c3e2fe92SDouglas Gilbert 
4287c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4288c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4289c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4290c3e2fe92SDouglas Gilbert 		goto cleanup;
4291c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4292c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4293c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4294c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4295c3e2fe92SDouglas Gilbert 	}
4296c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4297c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4298c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4299c3e2fe92SDouglas Gilbert 	}
4300c3e2fe92SDouglas Gilbert 	ret = 0;
4301c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4302c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4303c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4304c3e2fe92SDouglas Gilbert 		goto cleanup;
4305c3e2fe92SDouglas Gilbert 	}
4306c3e2fe92SDouglas Gilbert cleanup:
430767da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4308c3e2fe92SDouglas Gilbert 	kfree(arr);
4309c3e2fe92SDouglas Gilbert 	return ret;
4310c3e2fe92SDouglas Gilbert }
4311c3e2fe92SDouglas Gilbert 
4312f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4313f0d1cf93SDouglas Gilbert 
4314f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4315f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4316f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4317f0d1cf93SDouglas Gilbert {
4318f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4319f0d1cf93SDouglas Gilbert 	int ret = 0;
4320f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4321f0d1cf93SDouglas Gilbert 	bool partial;
4322f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4323f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4324f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4325f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4326b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4327f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4328f0d1cf93SDouglas Gilbert 
4329f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4330f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4331f0d1cf93SDouglas Gilbert 		return check_condition_result;
4332f0d1cf93SDouglas Gilbert 	}
4333f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4334f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
43353344b58bSGeorge Kennedy 	if (alloc_len == 0)
43363344b58bSGeorge Kennedy 		return 0;	/* not an error */
4337f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4338f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4339f0d1cf93SDouglas Gilbert 
4340f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4341f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4342f0d1cf93SDouglas Gilbert 		return check_condition_result;
4343f0d1cf93SDouglas Gilbert 	}
4344f0d1cf93SDouglas Gilbert 
4345108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4346f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4347f0d1cf93SDouglas Gilbert 			    max_zones);
4348f0d1cf93SDouglas Gilbert 
43497db0e0c8SShin'ichiro Kawasaki 	arr = kzalloc(alloc_len, GFP_ATOMIC);
4350f0d1cf93SDouglas Gilbert 	if (!arr) {
4351f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4352f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4353f0d1cf93SDouglas Gilbert 		return check_condition_result;
4354f0d1cf93SDouglas Gilbert 	}
4355f0d1cf93SDouglas Gilbert 
4356f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4357f0d1cf93SDouglas Gilbert 
4358f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4359f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4360f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4361f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4362f0d1cf93SDouglas Gilbert 			break;
4363f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4364f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4365f0d1cf93SDouglas Gilbert 		case 0x00:
4366f0d1cf93SDouglas Gilbert 			/* All zones */
4367f0d1cf93SDouglas Gilbert 			break;
4368f0d1cf93SDouglas Gilbert 		case 0x01:
4369f0d1cf93SDouglas Gilbert 			/* Empty zones */
4370f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4371f0d1cf93SDouglas Gilbert 				continue;
4372f0d1cf93SDouglas Gilbert 			break;
4373f0d1cf93SDouglas Gilbert 		case 0x02:
4374f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4375f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4376f0d1cf93SDouglas Gilbert 				continue;
4377f0d1cf93SDouglas Gilbert 			break;
4378f0d1cf93SDouglas Gilbert 		case 0x03:
4379f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4380f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4381f0d1cf93SDouglas Gilbert 				continue;
4382f0d1cf93SDouglas Gilbert 			break;
4383f0d1cf93SDouglas Gilbert 		case 0x04:
4384f0d1cf93SDouglas Gilbert 			/* Closed zones */
4385f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4386f0d1cf93SDouglas Gilbert 				continue;
4387f0d1cf93SDouglas Gilbert 			break;
4388f0d1cf93SDouglas Gilbert 		case 0x05:
4389f0d1cf93SDouglas Gilbert 			/* Full zones */
4390f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4391f0d1cf93SDouglas Gilbert 				continue;
4392f0d1cf93SDouglas Gilbert 			break;
4393f0d1cf93SDouglas Gilbert 		case 0x06:
4394f0d1cf93SDouglas Gilbert 		case 0x07:
4395f0d1cf93SDouglas Gilbert 		case 0x10:
4396f0d1cf93SDouglas Gilbert 			/*
439764e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
439864e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4399f0d1cf93SDouglas Gilbert 			 */
4400f0d1cf93SDouglas Gilbert 			continue;
440164e14eceSDamien Le Moal 		case 0x11:
440264e14eceSDamien Le Moal 			/* non-seq-resource set */
440364e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
440464e14eceSDamien Le Moal 				continue;
440564e14eceSDamien Le Moal 			break;
4406f0d1cf93SDouglas Gilbert 		case 0x3f:
4407f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4408f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4409f0d1cf93SDouglas Gilbert 				continue;
4410f0d1cf93SDouglas Gilbert 			break;
4411f0d1cf93SDouglas Gilbert 		default:
4412f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4413f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4414f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4415f0d1cf93SDouglas Gilbert 			goto fini;
4416f0d1cf93SDouglas Gilbert 		}
4417f0d1cf93SDouglas Gilbert 
4418f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4419f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
442064e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4421f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
442264e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
442364e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4424f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4425f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4426f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4427f0d1cf93SDouglas Gilbert 			desc += 64;
4428f0d1cf93SDouglas Gilbert 		}
4429f0d1cf93SDouglas Gilbert 
4430f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4431f0d1cf93SDouglas Gilbert 			break;
4432f0d1cf93SDouglas Gilbert 
4433f0d1cf93SDouglas Gilbert 		nrz++;
4434f0d1cf93SDouglas Gilbert 	}
4435f0d1cf93SDouglas Gilbert 
4436f0d1cf93SDouglas Gilbert 	/* Report header */
4437f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4438f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4439f0d1cf93SDouglas Gilbert 
4440f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
444136e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4442f0d1cf93SDouglas Gilbert 
4443f0d1cf93SDouglas Gilbert fini:
4444f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4445f0d1cf93SDouglas Gilbert 	kfree(arr);
4446f0d1cf93SDouglas Gilbert 	return ret;
4447f0d1cf93SDouglas Gilbert }
4448f0d1cf93SDouglas Gilbert 
4449f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4450f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4451f0d1cf93SDouglas Gilbert {
4452f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4453f0d1cf93SDouglas Gilbert 	unsigned int i;
4454f0d1cf93SDouglas Gilbert 
4455f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4456f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4457f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4458f0d1cf93SDouglas Gilbert 	}
4459f0d1cf93SDouglas Gilbert }
4460f0d1cf93SDouglas Gilbert 
4461f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4462f0d1cf93SDouglas Gilbert {
4463f0d1cf93SDouglas Gilbert 	int res = 0;
4464f0d1cf93SDouglas Gilbert 	u64 z_id;
4465f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4466f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4467f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4468f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4469b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4470f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4471f0d1cf93SDouglas Gilbert 
4472f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4473f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4474f0d1cf93SDouglas Gilbert 		return check_condition_result;
4475f0d1cf93SDouglas Gilbert 	}
4476f0d1cf93SDouglas Gilbert 
4477f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4478f0d1cf93SDouglas Gilbert 
4479f0d1cf93SDouglas Gilbert 	if (all) {
4480f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4481f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4482f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4483f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4484f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4485f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4486f0d1cf93SDouglas Gilbert 			goto fini;
4487f0d1cf93SDouglas Gilbert 		}
4488f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4489f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4490f0d1cf93SDouglas Gilbert 		goto fini;
4491f0d1cf93SDouglas Gilbert 	}
4492f0d1cf93SDouglas Gilbert 
4493f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4494f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4495f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4496f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4497f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4498f0d1cf93SDouglas Gilbert 		goto fini;
4499f0d1cf93SDouglas Gilbert 	}
4500f0d1cf93SDouglas Gilbert 
4501f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4502f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4503f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4504f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4505f0d1cf93SDouglas Gilbert 		goto fini;
4506f0d1cf93SDouglas Gilbert 	}
4507f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4508f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4509f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4510f0d1cf93SDouglas Gilbert 		goto fini;
4511f0d1cf93SDouglas Gilbert 	}
4512f0d1cf93SDouglas Gilbert 
4513f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4514f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4515f0d1cf93SDouglas Gilbert 		goto fini;
4516f0d1cf93SDouglas Gilbert 
4517f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4518f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4519f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4520f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4521f0d1cf93SDouglas Gilbert 		goto fini;
4522f0d1cf93SDouglas Gilbert 	}
4523f0d1cf93SDouglas Gilbert 
4524f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4525f0d1cf93SDouglas Gilbert fini:
4526f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4527f0d1cf93SDouglas Gilbert 	return res;
4528f0d1cf93SDouglas Gilbert }
4529f0d1cf93SDouglas Gilbert 
4530f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4531f0d1cf93SDouglas Gilbert {
4532f0d1cf93SDouglas Gilbert 	unsigned int i;
4533f0d1cf93SDouglas Gilbert 
4534f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4535f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4536f0d1cf93SDouglas Gilbert }
4537f0d1cf93SDouglas Gilbert 
4538f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4539f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4540f0d1cf93SDouglas Gilbert {
4541f0d1cf93SDouglas Gilbert 	int res = 0;
4542f0d1cf93SDouglas Gilbert 	u64 z_id;
4543f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4544f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4545f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4546b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4547f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4548f0d1cf93SDouglas Gilbert 
4549f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4550f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4551f0d1cf93SDouglas Gilbert 		return check_condition_result;
4552f0d1cf93SDouglas Gilbert 	}
4553f0d1cf93SDouglas Gilbert 
4554f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4555f0d1cf93SDouglas Gilbert 
4556f0d1cf93SDouglas Gilbert 	if (all) {
4557f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4558f0d1cf93SDouglas Gilbert 		goto fini;
4559f0d1cf93SDouglas Gilbert 	}
4560f0d1cf93SDouglas Gilbert 
4561f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4562f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4563f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4564f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4565f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4566f0d1cf93SDouglas Gilbert 		goto fini;
4567f0d1cf93SDouglas Gilbert 	}
4568f0d1cf93SDouglas Gilbert 
4569f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4570f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4571f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4572f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4573f0d1cf93SDouglas Gilbert 		goto fini;
4574f0d1cf93SDouglas Gilbert 	}
4575f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4576f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4577f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4578f0d1cf93SDouglas Gilbert 		goto fini;
4579f0d1cf93SDouglas Gilbert 	}
4580f0d1cf93SDouglas Gilbert 
4581f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4582f0d1cf93SDouglas Gilbert fini:
4583f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4584f0d1cf93SDouglas Gilbert 	return res;
4585f0d1cf93SDouglas Gilbert }
4586f0d1cf93SDouglas Gilbert 
4587f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4588f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4589f0d1cf93SDouglas Gilbert {
4590f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4591f0d1cf93SDouglas Gilbert 
4592f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4593f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4594f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4595f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4596f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4597f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4598f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4599f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4600f0d1cf93SDouglas Gilbert 	}
4601f0d1cf93SDouglas Gilbert }
4602f0d1cf93SDouglas Gilbert 
4603f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4604f0d1cf93SDouglas Gilbert {
4605f0d1cf93SDouglas Gilbert 	unsigned int i;
4606f0d1cf93SDouglas Gilbert 
4607f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4608f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4609f0d1cf93SDouglas Gilbert }
4610f0d1cf93SDouglas Gilbert 
4611f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4612f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4613f0d1cf93SDouglas Gilbert {
4614f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4615f0d1cf93SDouglas Gilbert 	int res = 0;
4616f0d1cf93SDouglas Gilbert 	u64 z_id;
4617f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4618f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4619b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4620f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4621f0d1cf93SDouglas Gilbert 
4622f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4623f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4624f0d1cf93SDouglas Gilbert 		return check_condition_result;
4625f0d1cf93SDouglas Gilbert 	}
4626f0d1cf93SDouglas Gilbert 
4627f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4628f0d1cf93SDouglas Gilbert 
4629f0d1cf93SDouglas Gilbert 	if (all) {
4630f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4631f0d1cf93SDouglas Gilbert 		goto fini;
4632f0d1cf93SDouglas Gilbert 	}
4633f0d1cf93SDouglas Gilbert 
4634f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4635f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4636f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4637f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4638f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4639f0d1cf93SDouglas Gilbert 		goto fini;
4640f0d1cf93SDouglas Gilbert 	}
4641f0d1cf93SDouglas Gilbert 
4642f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4643f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4644f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4645f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4646f0d1cf93SDouglas Gilbert 		goto fini;
4647f0d1cf93SDouglas Gilbert 	}
4648f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4649f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4650f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4651f0d1cf93SDouglas Gilbert 		goto fini;
4652f0d1cf93SDouglas Gilbert 	}
4653f0d1cf93SDouglas Gilbert 
4654f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4655f0d1cf93SDouglas Gilbert fini:
4656f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4657f0d1cf93SDouglas Gilbert 	return res;
4658f0d1cf93SDouglas Gilbert }
4659f0d1cf93SDouglas Gilbert 
4660f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4661f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4662f0d1cf93SDouglas Gilbert {
4663f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
46642d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4665f0d1cf93SDouglas Gilbert 
4666f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4667f0d1cf93SDouglas Gilbert 		return;
4668f0d1cf93SDouglas Gilbert 
4669f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4670f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4671f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4672f0d1cf93SDouglas Gilbert 
4673f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4674f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4675f0d1cf93SDouglas Gilbert 
46762d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
46772d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
46782d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
46792d62253eSShin'ichiro Kawasaki 
468064e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4681f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4682f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4683f0d1cf93SDouglas Gilbert }
4684f0d1cf93SDouglas Gilbert 
4685f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4686f0d1cf93SDouglas Gilbert {
4687f0d1cf93SDouglas Gilbert 	unsigned int i;
4688f0d1cf93SDouglas Gilbert 
4689f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4690f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4691f0d1cf93SDouglas Gilbert }
4692f0d1cf93SDouglas Gilbert 
4693f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4694f0d1cf93SDouglas Gilbert {
4695f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4696f0d1cf93SDouglas Gilbert 	int res = 0;
4697f0d1cf93SDouglas Gilbert 	u64 z_id;
4698f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4699f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4700b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4701f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4702f0d1cf93SDouglas Gilbert 
4703f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4704f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4705f0d1cf93SDouglas Gilbert 		return check_condition_result;
4706f0d1cf93SDouglas Gilbert 	}
4707f0d1cf93SDouglas Gilbert 
4708f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4709f0d1cf93SDouglas Gilbert 
4710f0d1cf93SDouglas Gilbert 	if (all) {
4711f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4712f0d1cf93SDouglas Gilbert 		goto fini;
4713f0d1cf93SDouglas Gilbert 	}
4714f0d1cf93SDouglas Gilbert 
4715f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4716f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4717f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4718f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4719f0d1cf93SDouglas Gilbert 		goto fini;
4720f0d1cf93SDouglas Gilbert 	}
4721f0d1cf93SDouglas Gilbert 
4722f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4723f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4724f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4725f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4726f0d1cf93SDouglas Gilbert 		goto fini;
4727f0d1cf93SDouglas Gilbert 	}
4728f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4729f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4730f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4731f0d1cf93SDouglas Gilbert 		goto fini;
4732f0d1cf93SDouglas Gilbert 	}
4733f0d1cf93SDouglas Gilbert 
4734f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4735f0d1cf93SDouglas Gilbert fini:
4736f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4737f0d1cf93SDouglas Gilbert 	return res;
4738f0d1cf93SDouglas Gilbert }
4739f0d1cf93SDouglas Gilbert 
4740c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4741c4837394SDouglas Gilbert {
4742c10fa55fSJohn Garry 	u16 hwq;
4743a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4744c10fa55fSJohn Garry 
4745c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4746c4837394SDouglas Gilbert 
4747458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4748458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4749458df78bSBart Van Assche 		hwq = 0;
4750f7c4cdc7SJohn Garry 
4751458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4752c4837394SDouglas Gilbert }
4753c4837394SDouglas Gilbert 
4754c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4755c10fa55fSJohn Garry {
4756a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4757c10fa55fSJohn Garry }
4758c10fa55fSJohn Garry 
4759c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4760fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47611da177e4SLinus Torvalds {
47627382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4763c4837394SDouglas Gilbert 	int qc_idx;
4764cbf67842SDouglas Gilbert 	int retiring = 0;
47651da177e4SLinus Torvalds 	unsigned long iflags;
4766c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4767cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4768cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4769cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47701da177e4SLinus Torvalds 
47717382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47727382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4773c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4774c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4775c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4776cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4777c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4778c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4779c4837394SDouglas Gilbert 	}
4780c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4781c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47821da177e4SLinus Torvalds 		return;
47831da177e4SLinus Torvalds 	}
4784c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4785d9d23a5aSDouglas Gilbert 	WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
4786c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4787cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4788b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4789c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4790c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4791c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
47921da177e4SLinus Torvalds 		return;
47931da177e4SLinus Torvalds 	}
4794cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4795f46eb0e9SDouglas Gilbert 	if (likely(devip))
4796cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4797cbf67842SDouglas Gilbert 	else
4798c1287970STomas Winkler 		pr_err("devip=NULL\n");
4799f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4800cbf67842SDouglas Gilbert 		retiring = 1;
4801cbf67842SDouglas Gilbert 
4802cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4803c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4804c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4805c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4806cbf67842SDouglas Gilbert 		return;
48071da177e4SLinus Torvalds 	}
48081da177e4SLinus Torvalds 
4809cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4810cbf67842SDouglas Gilbert 		int k, retval;
4811cbf67842SDouglas Gilbert 
4812cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4813c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4814c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4815c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4816cbf67842SDouglas Gilbert 			return;
4817cbf67842SDouglas Gilbert 		}
4818c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4819773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4820cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4821cbf67842SDouglas Gilbert 		else
4822cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4823cbf67842SDouglas Gilbert 	}
4824c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
48257382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
48267382f9d8SDouglas Gilbert 		if (sdebug_verbose)
48277382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
48287382f9d8SDouglas Gilbert 		return;
48297382f9d8SDouglas Gilbert 	}
48306c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
4831cbf67842SDouglas Gilbert }
4832cbf67842SDouglas Gilbert 
4833cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4834fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4835cbf67842SDouglas Gilbert {
4836a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4837a10bc12aSDouglas Gilbert 						  hrt);
4838a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4839cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4840cbf67842SDouglas Gilbert }
48411da177e4SLinus Torvalds 
4842a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4843fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4844a10bc12aSDouglas Gilbert {
4845a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4846a10bc12aSDouglas Gilbert 						  ew.work);
4847a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4848a10bc12aSDouglas Gilbert }
4849a10bc12aSDouglas Gilbert 
485009ba24c1SDouglas Gilbert static bool got_shared_uuid;
4851bf476433SChristoph Hellwig static uuid_t shared_uuid;
485209ba24c1SDouglas Gilbert 
4853f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4854f0d1cf93SDouglas Gilbert {
4855f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4856f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4857f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4858f0d1cf93SDouglas Gilbert 	unsigned int i;
4859f0d1cf93SDouglas Gilbert 
4860f0d1cf93SDouglas Gilbert 	/*
486198e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
486298e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4863f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4864f0d1cf93SDouglas Gilbert 	 * created for the device.
4865f0d1cf93SDouglas Gilbert 	 */
486698e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4867f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4868f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4869f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4870f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4871f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4872f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4873f0d1cf93SDouglas Gilbert 			return -EINVAL;
4874f0d1cf93SDouglas Gilbert 		}
4875f0d1cf93SDouglas Gilbert 	} else {
4876108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4877108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4878108e36f0SDamien Le Moal 			return -EINVAL;
4879108e36f0SDamien Le Moal 		}
488098e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4881f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4882f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4883f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4884f0d1cf93SDouglas Gilbert 			return -EINVAL;
4885f0d1cf93SDouglas Gilbert 		}
4886f0d1cf93SDouglas Gilbert 	}
4887f0d1cf93SDouglas Gilbert 
4888f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4889f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4890f0d1cf93SDouglas Gilbert 
4891aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4892aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4893aa8fecf9SDamien Le Moal 		return -EINVAL;
4894aa8fecf9SDamien Le Moal 	}
4895aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4896aa8fecf9SDamien Le Moal 
489764e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
489864e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4899380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4900f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4901f0d1cf93SDouglas Gilbert 		else
4902380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
490364e14eceSDamien Le Moal 	}
4904f0d1cf93SDouglas Gilbert 
4905f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4906f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4907f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4908f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4909f0d1cf93SDouglas Gilbert 
4910f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4911f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4912f0d1cf93SDouglas Gilbert 
4913f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4914f0d1cf93SDouglas Gilbert 
4915aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
491664e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4917f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4918f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4919f0d1cf93SDouglas Gilbert 		} else {
492064e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
492164e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
492264e14eceSDamien Le Moal 			else
492364e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4924f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4925f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4926f0d1cf93SDouglas Gilbert 		}
4927f0d1cf93SDouglas Gilbert 
4928f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4929f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4930f0d1cf93SDouglas Gilbert 		else
4931f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4932f0d1cf93SDouglas Gilbert 
4933f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4934f0d1cf93SDouglas Gilbert 	}
4935f0d1cf93SDouglas Gilbert 
4936f0d1cf93SDouglas Gilbert 	return 0;
4937f0d1cf93SDouglas Gilbert }
4938f0d1cf93SDouglas Gilbert 
4939fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4940fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
49415cb2fc06SFUJITA Tomonori {
49425cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
49435cb2fc06SFUJITA Tomonori 
49445cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
49455cb2fc06SFUJITA Tomonori 	if (devip) {
494609ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4947bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
494809ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
494909ba24c1SDouglas Gilbert 			if (got_shared_uuid)
495009ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
495109ba24c1SDouglas Gilbert 			else {
4952bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
495309ba24c1SDouglas Gilbert 				got_shared_uuid = true;
495409ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
495509ba24c1SDouglas Gilbert 			}
495609ba24c1SDouglas Gilbert 		}
49575cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4958f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
495964e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4960f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4961f0d1cf93SDouglas Gilbert 				kfree(devip);
4962f0d1cf93SDouglas Gilbert 				return NULL;
4963f0d1cf93SDouglas Gilbert 			}
496464e14eceSDamien Le Moal 		} else {
496564e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4966f0d1cf93SDouglas Gilbert 		}
4967f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
4968fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
4969fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
49705cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49715cb2fc06SFUJITA Tomonori 	}
49725cb2fc06SFUJITA Tomonori 	return devip;
49735cb2fc06SFUJITA Tomonori }
49745cb2fc06SFUJITA Tomonori 
4975f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49761da177e4SLinus Torvalds {
49771da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49781da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4979f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49801da177e4SLinus Torvalds 
4981d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49821da177e4SLinus Torvalds 	if (!sdbg_host) {
4983c1287970STomas Winkler 		pr_err("Host info NULL\n");
49841da177e4SLinus Torvalds 		return NULL;
49851da177e4SLinus Torvalds 	}
4986ad0c7775SDouglas Gilbert 
49871da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49881da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49891da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49901da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49911da177e4SLinus Torvalds 			return devip;
49921da177e4SLinus Torvalds 		else {
49931da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49941da177e4SLinus Torvalds 				open_devip = devip;
49951da177e4SLinus Torvalds 		}
49961da177e4SLinus Torvalds 	}
49975cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49985cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49995cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5000c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
50011da177e4SLinus Torvalds 			return NULL;
50021da177e4SLinus Torvalds 		}
50031da177e4SLinus Torvalds 	}
5004a75869d1SFUJITA Tomonori 
50051da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
50061da177e4SLinus Torvalds 	open_devip->target = sdev->id;
50071da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
50081da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5009cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
5010cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
5011c2248fc9SDouglas Gilbert 	open_devip->used = true;
50121da177e4SLinus Torvalds 	return open_devip;
50131da177e4SLinus Torvalds }
50141da177e4SLinus Torvalds 
50158dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
50161da177e4SLinus Torvalds {
5017773642d9SDouglas Gilbert 	if (sdebug_verbose)
5018c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
50198dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50208dea0d02SFUJITA Tomonori 	return 0;
50218dea0d02SFUJITA Tomonori }
50221da177e4SLinus Torvalds 
50238dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
50248dea0d02SFUJITA Tomonori {
5025f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5026f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5027a34c4e98SFUJITA Tomonori 
5028773642d9SDouglas Gilbert 	if (sdebug_verbose)
5029c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
50308dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5031b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5032b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
50332aad3cd8SDouglas Gilbert 	if (smp_load_acquire(&sdebug_deflect_incoming)) {
50342aad3cd8SDouglas Gilbert 		pr_info("Exit early due to deflect_incoming\n");
50352aad3cd8SDouglas Gilbert 		return 1;
50362aad3cd8SDouglas Gilbert 	}
5037b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5038f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5039b01f6f83SDouglas Gilbert 		if (devip == NULL)
50408dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5041f46eb0e9SDouglas Gilbert 	}
5042c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5043773642d9SDouglas Gilbert 	if (sdebug_no_uld)
504478d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
50459b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
50468dea0d02SFUJITA Tomonori 	return 0;
50478dea0d02SFUJITA Tomonori }
50488dea0d02SFUJITA Tomonori 
50498dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
50508dea0d02SFUJITA Tomonori {
50518dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
50528dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
50538dea0d02SFUJITA Tomonori 
5054773642d9SDouglas Gilbert 	if (sdebug_verbose)
5055c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
50568dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50578dea0d02SFUJITA Tomonori 	if (devip) {
505825985edcSLucas De Marchi 		/* make this slot available for re-use */
5059c2248fc9SDouglas Gilbert 		devip->used = false;
50608dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
50618dea0d02SFUJITA Tomonori 	}
50628dea0d02SFUJITA Tomonori }
50638dea0d02SFUJITA Tomonori 
506410bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
506510bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5066c4837394SDouglas Gilbert {
5067c4837394SDouglas Gilbert 	if (!sd_dp)
5068c4837394SDouglas Gilbert 		return;
506910bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5070c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
507110bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5072c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5073c4837394SDouglas Gilbert }
5074c4837394SDouglas Gilbert 
5075a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5076a10bc12aSDouglas Gilbert    returns false */
5077a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50788dea0d02SFUJITA Tomonori {
50798dea0d02SFUJITA Tomonori 	unsigned long iflags;
5080c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
508110bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5082c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50838dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5084cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5085a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50868dea0d02SFUJITA Tomonori 
5087c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5088c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5089773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5090cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5091cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5092cbf67842SDouglas Gilbert 			qmax = r_qmax;
5093cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5094c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5095c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5096a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5097a10bc12aSDouglas Gilbert 					continue;
5098c4837394SDouglas Gilbert 				/* found */
5099db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5100db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5101db525fceSDouglas Gilbert 				if (devip)
5102db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5103db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5104a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
510510bde980SDouglas Gilbert 				if (sd_dp) {
5106d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5107d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
510810bde980SDouglas Gilbert 				} else
510910bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5110c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
511110bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5112c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5113a10bc12aSDouglas Gilbert 				return true;
51148dea0d02SFUJITA Tomonori 			}
5115cbf67842SDouglas Gilbert 		}
5116c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5117c4837394SDouglas Gilbert 	}
5118a10bc12aSDouglas Gilbert 	return false;
51198dea0d02SFUJITA Tomonori }
51208dea0d02SFUJITA Tomonori 
5121a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
51222aad3cd8SDouglas Gilbert static void stop_all_queued(bool done_with_no_conn)
51238dea0d02SFUJITA Tomonori {
51248dea0d02SFUJITA Tomonori 	unsigned long iflags;
5125c4837394SDouglas Gilbert 	int j, k;
512610bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5127c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
51288dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5129cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5130a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
51312aad3cd8SDouglas Gilbert 	struct scsi_cmnd *scp;
51328dea0d02SFUJITA Tomonori 
5133c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5134c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5135c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5136c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5137c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
51382aad3cd8SDouglas Gilbert 				scp = sqcp->a_cmnd;
51392aad3cd8SDouglas Gilbert 				if (!scp)
5140a10bc12aSDouglas Gilbert 					continue;
5141db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5142db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5143db525fceSDouglas Gilbert 				if (devip)
5144db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5145db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5146a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
514710bde980SDouglas Gilbert 				if (sd_dp) {
5148d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5149d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
515010bde980SDouglas Gilbert 				} else
515110bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5152c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
515310bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
51542aad3cd8SDouglas Gilbert 				if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) {
51552aad3cd8SDouglas Gilbert 					scp->result = DID_NO_CONNECT << 16;
51562aad3cd8SDouglas Gilbert 					scsi_done(scp);
51572aad3cd8SDouglas Gilbert 				}
5158c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5159c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
51608dea0d02SFUJITA Tomonori 			}
51618dea0d02SFUJITA Tomonori 		}
5162c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5163c4837394SDouglas Gilbert 	}
5164cbf67842SDouglas Gilbert }
5165cbf67842SDouglas Gilbert 
5166cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5167cbf67842SDouglas Gilbert static void free_all_queued(void)
5168cbf67842SDouglas Gilbert {
5169c4837394SDouglas Gilbert 	int j, k;
5170c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5171cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5172cbf67842SDouglas Gilbert 
5173c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5174c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5175c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5176a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5177a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5178cbf67842SDouglas Gilbert 		}
51791da177e4SLinus Torvalds 	}
5180c4837394SDouglas Gilbert }
51811da177e4SLinus Torvalds 
51821da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51831da177e4SLinus Torvalds {
5184a10bc12aSDouglas Gilbert 	bool ok;
5185a10bc12aSDouglas Gilbert 
51861da177e4SLinus Torvalds 	++num_aborts;
5187cbf67842SDouglas Gilbert 	if (SCpnt) {
5188a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5189a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5190a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5191a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5192a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5193cbf67842SDouglas Gilbert 	}
51941da177e4SLinus Torvalds 	return SUCCESS;
51951da177e4SLinus Torvalds }
51961da177e4SLinus Torvalds 
51971da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51981da177e4SLinus Torvalds {
51991da177e4SLinus Torvalds 	++num_dev_resets;
5200cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5201cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5202f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5203f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5204cbf67842SDouglas Gilbert 
5205773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5206cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
52071da177e4SLinus Torvalds 		if (devip)
5208cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
52091da177e4SLinus Torvalds 	}
52101da177e4SLinus Torvalds 	return SUCCESS;
52111da177e4SLinus Torvalds }
52121da177e4SLinus Torvalds 
5213cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5214cbf67842SDouglas Gilbert {
5215cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5216cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5217cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5218cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5219cbf67842SDouglas Gilbert 	int k = 0;
5220cbf67842SDouglas Gilbert 
5221cbf67842SDouglas Gilbert 	++num_target_resets;
5222cbf67842SDouglas Gilbert 	if (!SCpnt)
5223cbf67842SDouglas Gilbert 		goto lie;
5224cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5225cbf67842SDouglas Gilbert 	if (!sdp)
5226cbf67842SDouglas Gilbert 		goto lie;
5227773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5228cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5229cbf67842SDouglas Gilbert 	hp = sdp->host;
5230cbf67842SDouglas Gilbert 	if (!hp)
5231cbf67842SDouglas Gilbert 		goto lie;
5232cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5233cbf67842SDouglas Gilbert 	if (sdbg_host) {
5234cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5235cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5236cbf67842SDouglas Gilbert 				    dev_list)
5237cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5238cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5239cbf67842SDouglas Gilbert 				++k;
5240cbf67842SDouglas Gilbert 			}
5241cbf67842SDouglas Gilbert 	}
5242773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5243cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5244cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5245cbf67842SDouglas Gilbert lie:
5246cbf67842SDouglas Gilbert 	return SUCCESS;
5247cbf67842SDouglas Gilbert }
5248cbf67842SDouglas Gilbert 
52491da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
52501da177e4SLinus Torvalds {
52511da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5252cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
52531da177e4SLinus Torvalds 	struct scsi_device *sdp;
52541da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5255cbf67842SDouglas Gilbert 	int k = 0;
52561da177e4SLinus Torvalds 
52571da177e4SLinus Torvalds 	++num_bus_resets;
5258cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5259cbf67842SDouglas Gilbert 		goto lie;
5260cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5261773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5262cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5263cbf67842SDouglas Gilbert 	hp = sdp->host;
5264cbf67842SDouglas Gilbert 	if (hp) {
5265d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52661da177e4SLinus Torvalds 		if (sdbg_host) {
5267cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
52681da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5269cbf67842SDouglas Gilbert 					    dev_list) {
5270cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5271cbf67842SDouglas Gilbert 				++k;
52721da177e4SLinus Torvalds 			}
52731da177e4SLinus Torvalds 		}
5274cbf67842SDouglas Gilbert 	}
5275773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5276cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5277cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5278cbf67842SDouglas Gilbert lie:
52791da177e4SLinus Torvalds 	return SUCCESS;
52801da177e4SLinus Torvalds }
52811da177e4SLinus Torvalds 
52821da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52831da177e4SLinus Torvalds {
52841da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5285cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5286cbf67842SDouglas Gilbert 	int k = 0;
52871da177e4SLinus Torvalds 
52881da177e4SLinus Torvalds 	++num_host_resets;
5289773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5290cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52911da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52921da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5293cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5294cbf67842SDouglas Gilbert 				    dev_list) {
5295cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5296cbf67842SDouglas Gilbert 			++k;
5297cbf67842SDouglas Gilbert 		}
52981da177e4SLinus Torvalds 	}
52991da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
53002aad3cd8SDouglas Gilbert 	stop_all_queued(false);
5301773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5302cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5303cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
53041da177e4SLinus Torvalds 	return SUCCESS;
53051da177e4SLinus Torvalds }
53061da177e4SLinus Torvalds 
530787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
53081da177e4SLinus Torvalds {
53091442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5310979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
53111da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
53121da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
53131da177e4SLinus Torvalds 
53141da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5315773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
53161da177e4SLinus Torvalds 		return;
5317773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5318773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5319c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
53201da177e4SLinus Torvalds 	}
53218c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
53221da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5323773642d9SDouglas Gilbert 			   / sdebug_num_parts;
53241da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
53251da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5326979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5327979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
53281da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
53291da177e4SLinus Torvalds 			    * heads_by_sects;
5330979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5331979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5332979e0dc3SJohn Pittman 	}
5333773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5334773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
53351da177e4SLinus Torvalds 
53361da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
53371da177e4SLinus Torvalds 	ramp[511] = 0xAA;
53381442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
53391da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
53401da177e4SLinus Torvalds 		start_sec = starts[k];
5341979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
53421da177e4SLinus Torvalds 		pp->boot_ind = 0;
53431da177e4SLinus Torvalds 
53441da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
53451da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
53461da177e4SLinus Torvalds 			   / sdebug_sectors_per;
53471da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
53481da177e4SLinus Torvalds 
53491da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
53501da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
53511da177e4SLinus Torvalds 			       / sdebug_sectors_per;
53521da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
53531da177e4SLinus Torvalds 
5354150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5355150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
53561da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
53571da177e4SLinus Torvalds 	}
53581da177e4SLinus Torvalds }
53591da177e4SLinus Torvalds 
53602aad3cd8SDouglas Gilbert static void sdeb_block_all_queues(void)
5361c4837394SDouglas Gilbert {
5362c4837394SDouglas Gilbert 	int j;
5363c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5364c4837394SDouglas Gilbert 
5365c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
53662aad3cd8SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)true);
53672aad3cd8SDouglas Gilbert }
53682aad3cd8SDouglas Gilbert 
53692aad3cd8SDouglas Gilbert static void sdeb_unblock_all_queues(void)
53702aad3cd8SDouglas Gilbert {
53712aad3cd8SDouglas Gilbert 	int j;
53722aad3cd8SDouglas Gilbert 	struct sdebug_queue *sqp;
53732aad3cd8SDouglas Gilbert 
53742aad3cd8SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
53752aad3cd8SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)false);
53762aad3cd8SDouglas Gilbert }
53772aad3cd8SDouglas Gilbert 
53782aad3cd8SDouglas Gilbert static void
53792aad3cd8SDouglas Gilbert sdeb_add_n_hosts(int num_hosts)
53802aad3cd8SDouglas Gilbert {
53812aad3cd8SDouglas Gilbert 	if (num_hosts < 1)
53822aad3cd8SDouglas Gilbert 		return;
53832aad3cd8SDouglas Gilbert 	do {
53842aad3cd8SDouglas Gilbert 		bool found;
53852aad3cd8SDouglas Gilbert 		unsigned long idx;
53862aad3cd8SDouglas Gilbert 		struct sdeb_store_info *sip;
53872aad3cd8SDouglas Gilbert 		bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
53882aad3cd8SDouglas Gilbert 
53892aad3cd8SDouglas Gilbert 		found = false;
53902aad3cd8SDouglas Gilbert 		if (want_phs) {
53912aad3cd8SDouglas Gilbert 			xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) {
53922aad3cd8SDouglas Gilbert 				sdeb_most_recent_idx = (int)idx;
53932aad3cd8SDouglas Gilbert 				found = true;
53942aad3cd8SDouglas Gilbert 				break;
53952aad3cd8SDouglas Gilbert 			}
53962aad3cd8SDouglas Gilbert 			if (found)	/* re-use case */
53972aad3cd8SDouglas Gilbert 				sdebug_add_host_helper((int)idx);
53982aad3cd8SDouglas Gilbert 			else
53992aad3cd8SDouglas Gilbert 				sdebug_do_add_host(true	/* make new store */);
54002aad3cd8SDouglas Gilbert 		} else {
54012aad3cd8SDouglas Gilbert 			sdebug_do_add_host(false);
54022aad3cd8SDouglas Gilbert 		}
54032aad3cd8SDouglas Gilbert 	} while (--num_hosts);
5404c4837394SDouglas Gilbert }
5405c4837394SDouglas Gilbert 
5406c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5407c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5408c4837394SDouglas Gilbert  */
5409c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5410c4837394SDouglas Gilbert {
5411c4837394SDouglas Gilbert 	int count, modulo;
5412c4837394SDouglas Gilbert 
5413c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5414c4837394SDouglas Gilbert 	if (modulo < 2)
5415c4837394SDouglas Gilbert 		return;
54162aad3cd8SDouglas Gilbert 	sdeb_block_all_queues();
5417c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5418c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
54192aad3cd8SDouglas Gilbert 	sdeb_unblock_all_queues();
5420c4837394SDouglas Gilbert }
5421c4837394SDouglas Gilbert 
5422c4837394SDouglas Gilbert static void clear_queue_stats(void)
5423c4837394SDouglas Gilbert {
5424c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5425c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5426c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5427c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5428c4837394SDouglas Gilbert }
5429c4837394SDouglas Gilbert 
54303a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5431c4837394SDouglas Gilbert {
54323a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
54333a90a63dSDouglas Gilbert 		return false;
54343a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5435c4837394SDouglas Gilbert }
5436c4837394SDouglas Gilbert 
54372aad3cd8SDouglas Gilbert static int process_deflect_incoming(struct scsi_cmnd *scp)
54382aad3cd8SDouglas Gilbert {
54392aad3cd8SDouglas Gilbert 	u8 opcode = scp->cmnd[0];
54402aad3cd8SDouglas Gilbert 
54412aad3cd8SDouglas Gilbert 	if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16)
54422aad3cd8SDouglas Gilbert 		return 0;
54432aad3cd8SDouglas Gilbert 	return DID_NO_CONNECT << 16;
54442aad3cd8SDouglas Gilbert }
54452aad3cd8SDouglas Gilbert 
5446a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5447a2aede97SDouglas Gilbert 
5448c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5449c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5450c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5451c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5452c4837394SDouglas Gilbert  */
5453fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5454f66b8517SMartin Wilck 			 int scsi_result,
54552aad3cd8SDouglas Gilbert 			 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *),
5456f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
54571da177e4SLinus Torvalds {
5458a2aede97SDouglas Gilbert 	bool new_sd_dp;
54593a90a63dSDouglas Gilbert 	bool inject = false;
54606ce913feSChristoph Hellwig 	bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED;
54613a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5462a2aede97SDouglas Gilbert 	unsigned long iflags;
5463a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5464c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5465c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5466299b6c07STomas Winkler 	struct scsi_device *sdp;
5467a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
54681da177e4SLinus Torvalds 
5469b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5470b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5471f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5472f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
54731da177e4SLinus Torvalds 	}
5474299b6c07STomas Winkler 	sdp = cmnd->device;
5475299b6c07STomas Winkler 
54762aad3cd8SDouglas Gilbert 	if (delta_jiff == 0) {
54772aad3cd8SDouglas Gilbert 		sqp = get_queue(cmnd);
54782aad3cd8SDouglas Gilbert 		if (atomic_read(&sqp->blocked)) {
54792aad3cd8SDouglas Gilbert 			if (smp_load_acquire(&sdebug_deflect_incoming))
54802aad3cd8SDouglas Gilbert 				return process_deflect_incoming(cmnd);
54812aad3cd8SDouglas Gilbert 			else
54822aad3cd8SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
54832aad3cd8SDouglas Gilbert 		}
5484cd62b7daSDouglas Gilbert 		goto respond_in_thread;
54852aad3cd8SDouglas Gilbert 	}
54861da177e4SLinus Torvalds 
5487c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5488c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5489c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5490c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
54912aad3cd8SDouglas Gilbert 		if (smp_load_acquire(&sdebug_deflect_incoming)) {
54922aad3cd8SDouglas Gilbert 			scsi_result = process_deflect_incoming(cmnd);
54932aad3cd8SDouglas Gilbert 			goto respond_in_thread;
54942aad3cd8SDouglas Gilbert 		}
54952aad3cd8SDouglas Gilbert 		if (sdebug_verbose)
54962aad3cd8SDouglas Gilbert 			pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n");
5497c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5498c4837394SDouglas Gilbert 	}
5499cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5500cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5501f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5502cd62b7daSDouglas Gilbert 		if (scsi_result) {
5503c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5504cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5505cd62b7daSDouglas Gilbert 		} else
5506cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5507c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5508773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5509f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5510cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5511cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5512773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5513cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
55143a90a63dSDouglas Gilbert 			inject = true;
5515cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
55161da177e4SLinus Torvalds 		}
5517cbf67842SDouglas Gilbert 	}
5518cbf67842SDouglas Gilbert 
5519c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5520f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5521c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5522cd62b7daSDouglas Gilbert 		if (scsi_result)
5523cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5524cd62b7daSDouglas Gilbert 		scsi_result = device_qfull_result;
5525773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5526*7d5a129bSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
5527*7d5a129bSDouglas Gilbert 				    __func__, sdebug_max_queue);
5528cd62b7daSDouglas Gilbert 		goto respond_in_thread;
55291da177e4SLinus Torvalds 	}
553074595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5531cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5532c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
55331da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5534c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5535a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5536c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5537c4b57d89SKashyap Desai 
553874595c04SDouglas Gilbert 	if (!sd_dp) {
553910bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
554074595c04SDouglas Gilbert 		if (!sd_dp) {
554174595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
554274595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
554310bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
554474595c04SDouglas Gilbert 		}
5545a2aede97SDouglas Gilbert 		new_sd_dp = true;
5546a2aede97SDouglas Gilbert 	} else {
5547a2aede97SDouglas Gilbert 		new_sd_dp = false;
554810bde980SDouglas Gilbert 	}
5549f66b8517SMartin Wilck 
5550c10fa55fSJohn Garry 	/* Set the hostwide tag */
5551c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5552c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5553c10fa55fSJohn Garry 
55546ce913feSChristoph Hellwig 	if (polled)
5555a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5556a2aede97SDouglas Gilbert 
5557a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
55583a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5559f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5560f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5561f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5562f66b8517SMartin Wilck 	}
5563f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5564f66b8517SMartin Wilck 		cmnd->result = scsi_result;
55653a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
55663a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
55673a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
55683a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
55693a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
55703a90a63dSDouglas Gilbert 		}
55713a90a63dSDouglas Gilbert 	}
5572f66b8517SMartin Wilck 
5573f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5574f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5575f66b8517SMartin Wilck 			    __func__, cmnd->result);
5576f66b8517SMartin Wilck 
557710bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5578b333a819SDouglas Gilbert 		ktime_t kt;
5579cbf67842SDouglas Gilbert 
5580b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
55810c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
55820c4bc91dSDouglas Gilbert 
55830c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
55840c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
55850c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
55860c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
55870c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
55880c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
55890c4bc91dSDouglas Gilbert 				ns <<= 12;
55900c4bc91dSDouglas Gilbert 			}
55910c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
55920c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
55930c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
55940c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5595a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5596a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5597a2aede97SDouglas Gilbert 
5598a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5599223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5600a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5601a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5602a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5603223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5604a2aede97SDouglas Gilbert 					if (new_sd_dp)
5605a2aede97SDouglas Gilbert 						kfree(sd_dp);
5606a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
56076c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5608a2aede97SDouglas Gilbert 					return 0;
5609a2aede97SDouglas Gilbert 				}
5610a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5611a2aede97SDouglas Gilbert 				kt -= d;
5612a2aede97SDouglas Gilbert 			}
56130c4bc91dSDouglas Gilbert 		}
56146ce913feSChristoph Hellwig 		if (polled) {
56154a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
56164a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
56174a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
56184a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
56194a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
56204a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
56214a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
56224a0c6f43SDouglas Gilbert 			}
5623d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
56244a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
56254a0c6f43SDouglas Gilbert 		} else {
562610bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
562710bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5628a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5629a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5630c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5631a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5632c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5633c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5634cbf67842SDouglas Gilbert 			}
5635d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
5636a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5637c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
56384a0c6f43SDouglas Gilbert 		}
56394a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
56404a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5641c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
56424a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
56434a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
56444a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
56456ce913feSChristoph Hellwig 		if (polled) {
56464a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
56474a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
56484a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
56494a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
56504a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
56514a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
56524a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
56534a0c6f43SDouglas Gilbert 			}
5654d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
56554a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
56564a0c6f43SDouglas Gilbert 		} else {
565710bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
565810bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5659a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5660c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5661c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5662a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5663cbf67842SDouglas Gilbert 			}
5664d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
56654a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
56664a0c6f43SDouglas Gilbert 		}
5667c4837394SDouglas Gilbert 		if (sdebug_statistics)
5668c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
56694a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
5670a6e76e6fSBart Van Assche 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5671a6e76e6fSBart Van Assche 				    scsi_cmd_to_rq(cmnd)->tag);
5672a6e76e6fSBart Van Assche 			blk_abort_request(scsi_cmd_to_rq(cmnd));
56733a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56744a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
56757382f9d8SDouglas Gilbert 		}
5676cbf67842SDouglas Gilbert 	}
56773a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
56783a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
56793a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
56801da177e4SLinus Torvalds 	return 0;
5681cd62b7daSDouglas Gilbert 
5682cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5683f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5684f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
56852aad3cd8SDouglas Gilbert 	if (cmnd->result == 0 && scsi_result != 0) {
5686cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
56872aad3cd8SDouglas Gilbert 		if (sdebug_verbose)
56882aad3cd8SDouglas Gilbert 			pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n",
56892aad3cd8SDouglas Gilbert 				blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result);
56902aad3cd8SDouglas Gilbert 	}
56916c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5692cd62b7daSDouglas Gilbert 	return 0;
56931da177e4SLinus Torvalds }
5694cbf67842SDouglas Gilbert 
569523183910SDouglas Gilbert /* Note: The following macros create attribute files in the
569623183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
569723183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
569823183910SDouglas Gilbert    as it can when the corresponding attribute in the
569923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
570023183910SDouglas Gilbert  */
5701773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5702773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
57039b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5704773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5705c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5706773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5707773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5708773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5709773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5710773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5711773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5712773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5713773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5714c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5715e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5716e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5717e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5718e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
57195d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
57205d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
57215d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5722773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5723773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5724773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5725773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5726ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5727773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5728773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
57295d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
57305d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
57315d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
57325d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5733773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5734773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5735773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5736773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5737773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5738773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
57395d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5740773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
574187c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
574287c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5743773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5744773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
57450c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5746773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5747773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5748773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5749c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5750773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5751c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5752c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5753fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5754773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5755773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5756773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5757773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
575809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
57595d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5760773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
576123183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
57629447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5763773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
57645b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
57659267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5766380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5767aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
576898e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
57691da177e4SLinus Torvalds 
57701da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
57711da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
57721da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5773b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
57741da177e4SLinus Torvalds 
57755d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
57765b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
57779b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
57780759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5779cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5780c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
57815b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
57825b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5783c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5784beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
578523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
57865b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5787185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5788c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5789c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5790e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
57919b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
57929b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
57935d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
57945d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
57955d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
57965b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
57975b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
57985b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
57995b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5800ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5801fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5802cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5803d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
58045d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5805cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5806c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
580778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
58081da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5809c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
581032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
581186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
58125d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
58135d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
58145d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5815fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
58161da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
58170c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5818d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5819760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5820ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5821c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5822c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5823c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5824fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
58255b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
58265b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
58276014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
58286014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
582909ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
583009ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5831c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
58325b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
58339447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
58345b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
58359267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5836380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5837aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
583898e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
58391da177e4SLinus Torvalds 
5840760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5841760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
58421da177e4SLinus Torvalds 
58431da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
58441da177e4SLinus Torvalds {
5845c4837394SDouglas Gilbert 	int k;
5846c4837394SDouglas Gilbert 
5847760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5848760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5849760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5850c4837394SDouglas Gilbert 		return sdebug_info;
5851760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5852760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5853760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5854760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
58551da177e4SLinus Torvalds 	return sdebug_info;
58561da177e4SLinus Torvalds }
58571da177e4SLinus Torvalds 
5858cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5859fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5860fd32119bSDouglas Gilbert 				 int length)
58611da177e4SLinus Torvalds {
58621da177e4SLinus Torvalds 	char arr[16];
5863c8ed555aSAl Viro 	int opts;
58641da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
58651da177e4SLinus Torvalds 
58661da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
58671da177e4SLinus Torvalds 		return -EACCES;
58681da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
58691da177e4SLinus Torvalds 	arr[minLen] = '\0';
5870c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
58711da177e4SLinus Torvalds 		return -EINVAL;
5872773642d9SDouglas Gilbert 	sdebug_opts = opts;
5873773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5874773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5875773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5876c4837394SDouglas Gilbert 		tweak_cmnd_count();
58771da177e4SLinus Torvalds 	return length;
58781da177e4SLinus Torvalds }
5879c8ed555aSAl Viro 
5880cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5881cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5882cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5883c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5884c8ed555aSAl Viro {
5885c4837394SDouglas Gilbert 	int f, j, l;
5886c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
588787c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5888cbf67842SDouglas Gilbert 
5889c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5890c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5891c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5892c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5893c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5894c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5895c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5896c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5897c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5898c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5899c4837394SDouglas Gilbert 		   num_aborts);
5900c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5901c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5902c4837394SDouglas Gilbert 		   num_host_resets);
5903c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5904c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5905458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5906458df78bSBart Van Assche 		   sdebug_statistics);
59074a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
5908c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5909c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5910c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
59114a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
59124a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
5913cbf67842SDouglas Gilbert 
5914c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5915c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5916c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5917c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5918773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5919c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5920c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5921c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5922c4837394SDouglas Gilbert 		}
5923cbf67842SDouglas Gilbert 	}
592487c715dcSDouglas Gilbert 
592587c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
592687c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
592787c715dcSDouglas Gilbert 		bool niu;
592887c715dcSDouglas Gilbert 		int idx;
592987c715dcSDouglas Gilbert 		unsigned long l_idx;
593087c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
593187c715dcSDouglas Gilbert 
593287c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
593387c715dcSDouglas Gilbert 		j = 0;
593487c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
593587c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
593687c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
593787c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
593887c715dcSDouglas Gilbert 			++j;
593987c715dcSDouglas Gilbert 		}
594087c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
594187c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
594287c715dcSDouglas Gilbert 		j = 0;
594387c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
594487c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
594587c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
594687c715dcSDouglas Gilbert 			idx = (int)l_idx;
594787c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
594887c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
594987c715dcSDouglas Gilbert 			++j;
595087c715dcSDouglas Gilbert 		}
595187c715dcSDouglas Gilbert 	}
5952c8ed555aSAl Viro 	return 0;
59531da177e4SLinus Torvalds }
59541da177e4SLinus Torvalds 
595582069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
59561da177e4SLinus Torvalds {
5957c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
59581da177e4SLinus Torvalds }
5959c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5960c4837394SDouglas Gilbert  * of delay is jiffies.
5961c4837394SDouglas Gilbert  */
596282069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
596382069379SAkinobu Mita 			   size_t count)
59641da177e4SLinus Torvalds {
5965c2206098SDouglas Gilbert 	int jdelay, res;
59661da177e4SLinus Torvalds 
5967b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5968cbf67842SDouglas Gilbert 		res = count;
5969c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5970c4837394SDouglas Gilbert 			int j, k;
5971c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5972cbf67842SDouglas Gilbert 
59732aad3cd8SDouglas Gilbert 			sdeb_block_all_queues();
5974c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5975c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5976c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5977c4837394SDouglas Gilbert 						   sdebug_max_queue);
5978c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5979c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5980c4837394SDouglas Gilbert 					break;
5981c4837394SDouglas Gilbert 				}
5982c4837394SDouglas Gilbert 			}
5983c4837394SDouglas Gilbert 			if (res > 0) {
5984c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5985773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
59861da177e4SLinus Torvalds 			}
59872aad3cd8SDouglas Gilbert 			sdeb_unblock_all_queues();
5988cbf67842SDouglas Gilbert 		}
5989cbf67842SDouglas Gilbert 		return res;
59901da177e4SLinus Torvalds 	}
59911da177e4SLinus Torvalds 	return -EINVAL;
59921da177e4SLinus Torvalds }
599382069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
59941da177e4SLinus Torvalds 
5995cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5996cbf67842SDouglas Gilbert {
5997773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5998cbf67842SDouglas Gilbert }
5999cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6000c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
6001cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6002cbf67842SDouglas Gilbert 			    size_t count)
6003cbf67842SDouglas Gilbert {
6004c4837394SDouglas Gilbert 	int ndelay, res;
6005cbf67842SDouglas Gilbert 
6006cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6007c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6008cbf67842SDouglas Gilbert 		res = count;
6009773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
6010c4837394SDouglas Gilbert 			int j, k;
6011c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6012c4837394SDouglas Gilbert 
60132aad3cd8SDouglas Gilbert 			sdeb_block_all_queues();
6014c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6015c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6016c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6017c4837394SDouglas Gilbert 						   sdebug_max_queue);
6018c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6019c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6020c4837394SDouglas Gilbert 					break;
6021c4837394SDouglas Gilbert 				}
6022c4837394SDouglas Gilbert 			}
6023c4837394SDouglas Gilbert 			if (res > 0) {
6024773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6025c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6026c2206098SDouglas Gilbert 							: DEF_JDELAY;
6027cbf67842SDouglas Gilbert 			}
60282aad3cd8SDouglas Gilbert 			sdeb_unblock_all_queues();
6029cbf67842SDouglas Gilbert 		}
6030cbf67842SDouglas Gilbert 		return res;
6031cbf67842SDouglas Gilbert 	}
6032cbf67842SDouglas Gilbert 	return -EINVAL;
6033cbf67842SDouglas Gilbert }
6034cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6035cbf67842SDouglas Gilbert 
603682069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
60371da177e4SLinus Torvalds {
6038773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
60391da177e4SLinus Torvalds }
60401da177e4SLinus Torvalds 
604182069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
604282069379SAkinobu Mita 			  size_t count)
60431da177e4SLinus Torvalds {
60441da177e4SLinus Torvalds 	int opts;
60451da177e4SLinus Torvalds 	char work[20];
60461da177e4SLinus Torvalds 
60479a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
60489a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
60499a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
60501da177e4SLinus Torvalds 				goto opts_done;
60511da177e4SLinus Torvalds 		} else {
60529a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
60531da177e4SLinus Torvalds 				goto opts_done;
60541da177e4SLinus Torvalds 		}
60551da177e4SLinus Torvalds 	}
60561da177e4SLinus Torvalds 	return -EINVAL;
60571da177e4SLinus Torvalds opts_done:
6058773642d9SDouglas Gilbert 	sdebug_opts = opts;
6059773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6060773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6061c4837394SDouglas Gilbert 	tweak_cmnd_count();
60621da177e4SLinus Torvalds 	return count;
60631da177e4SLinus Torvalds }
606482069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
60651da177e4SLinus Torvalds 
606682069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
60671da177e4SLinus Torvalds {
6068773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
60691da177e4SLinus Torvalds }
607082069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
607182069379SAkinobu Mita 			   size_t count)
60721da177e4SLinus Torvalds {
60731da177e4SLinus Torvalds 	int n;
60741da177e4SLinus Torvalds 
6075f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6076f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6077f0d1cf93SDouglas Gilbert 		return -EINVAL;
6078f0d1cf93SDouglas Gilbert 
60791da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6080f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6081f0d1cf93SDouglas Gilbert 			return -EINVAL;
6082773642d9SDouglas Gilbert 		sdebug_ptype = n;
60831da177e4SLinus Torvalds 		return count;
60841da177e4SLinus Torvalds 	}
60851da177e4SLinus Torvalds 	return -EINVAL;
60861da177e4SLinus Torvalds }
608782069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
60881da177e4SLinus Torvalds 
608982069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
60901da177e4SLinus Torvalds {
6091773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
60921da177e4SLinus Torvalds }
609382069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
609482069379SAkinobu Mita 			    size_t count)
60951da177e4SLinus Torvalds {
60961da177e4SLinus Torvalds 	int n;
60971da177e4SLinus Torvalds 
60981da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6099773642d9SDouglas Gilbert 		sdebug_dsense = n;
61001da177e4SLinus Torvalds 		return count;
61011da177e4SLinus Torvalds 	}
61021da177e4SLinus Torvalds 	return -EINVAL;
61031da177e4SLinus Torvalds }
610482069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
61051da177e4SLinus Torvalds 
610682069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
610723183910SDouglas Gilbert {
6108773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
610923183910SDouglas Gilbert }
611082069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
611182069379SAkinobu Mita 			     size_t count)
611223183910SDouglas Gilbert {
611387c715dcSDouglas Gilbert 	int n, idx;
611423183910SDouglas Gilbert 
611523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
611687c715dcSDouglas Gilbert 		bool want_store = (n == 0);
611787c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
611887c715dcSDouglas Gilbert 
6119cbf67842SDouglas Gilbert 		n = (n > 0);
6120773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
612187c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
612287c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6123cbf67842SDouglas Gilbert 
612487c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
612587c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
612687c715dcSDouglas Gilbert 				idx = sdebug_add_store();
612787c715dcSDouglas Gilbert 				if (idx < 0)
612887c715dcSDouglas Gilbert 					return idx;
612987c715dcSDouglas Gilbert 			} else {
613087c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
613187c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
613287c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6133cbf67842SDouglas Gilbert 			}
613487c715dcSDouglas Gilbert 			/* make all hosts use same store */
613587c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
613687c715dcSDouglas Gilbert 					    host_list) {
613787c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
613887c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
613987c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
614087c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
614187c715dcSDouglas Gilbert 				}
614287c715dcSDouglas Gilbert 			}
614387c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
614487c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
614587c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6146cbf67842SDouglas Gilbert 		}
6147773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
614823183910SDouglas Gilbert 		return count;
614923183910SDouglas Gilbert 	}
615023183910SDouglas Gilbert 	return -EINVAL;
615123183910SDouglas Gilbert }
615282069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
615323183910SDouglas Gilbert 
615482069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6155c65b1445SDouglas Gilbert {
6156773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6157c65b1445SDouglas Gilbert }
615882069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
615982069379SAkinobu Mita 			      size_t count)
6160c65b1445SDouglas Gilbert {
6161c65b1445SDouglas Gilbert 	int n;
6162c65b1445SDouglas Gilbert 
6163c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6164773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6165c65b1445SDouglas Gilbert 		return count;
6166c65b1445SDouglas Gilbert 	}
6167c65b1445SDouglas Gilbert 	return -EINVAL;
6168c65b1445SDouglas Gilbert }
616982069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6170c65b1445SDouglas Gilbert 
617182069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
61721da177e4SLinus Torvalds {
6173773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
61741da177e4SLinus Torvalds }
617582069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
617682069379SAkinobu Mita 			      size_t count)
61771da177e4SLinus Torvalds {
61781da177e4SLinus Torvalds 	int n;
61791da177e4SLinus Torvalds 
61801da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6181773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
61821da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
61831da177e4SLinus Torvalds 		return count;
61841da177e4SLinus Torvalds 	}
61851da177e4SLinus Torvalds 	return -EINVAL;
61861da177e4SLinus Torvalds }
618782069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
61881da177e4SLinus Torvalds 
618982069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
61901da177e4SLinus Torvalds {
6191773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
61921da177e4SLinus Torvalds }
619382069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
61941da177e4SLinus Torvalds 
619587c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
619687c715dcSDouglas Gilbert {
619787c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
619887c715dcSDouglas Gilbert }
619987c715dcSDouglas Gilbert 
620087c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
620187c715dcSDouglas Gilbert 				    size_t count)
620287c715dcSDouglas Gilbert {
620387c715dcSDouglas Gilbert 	bool v;
620487c715dcSDouglas Gilbert 
620587c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
620687c715dcSDouglas Gilbert 		return -EINVAL;
620787c715dcSDouglas Gilbert 
620887c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
620987c715dcSDouglas Gilbert 	return count;
621087c715dcSDouglas Gilbert }
621187c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
621287c715dcSDouglas Gilbert 
621382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
62141da177e4SLinus Torvalds {
6215773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
62161da177e4SLinus Torvalds }
621782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
62181da177e4SLinus Torvalds 
621982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
62201da177e4SLinus Torvalds {
6221773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
62221da177e4SLinus Torvalds }
622382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
622482069379SAkinobu Mita 			       size_t count)
62251da177e4SLinus Torvalds {
62261da177e4SLinus Torvalds 	int nth;
62273a90a63dSDouglas Gilbert 	char work[20];
62281da177e4SLinus Torvalds 
62293a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
62303a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
62313a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
62323a90a63dSDouglas Gilbert 				goto every_nth_done;
62333a90a63dSDouglas Gilbert 		} else {
62343a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
62353a90a63dSDouglas Gilbert 				goto every_nth_done;
62363a90a63dSDouglas Gilbert 		}
62373a90a63dSDouglas Gilbert 	}
62383a90a63dSDouglas Gilbert 	return -EINVAL;
62393a90a63dSDouglas Gilbert 
62403a90a63dSDouglas Gilbert every_nth_done:
6241773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6242c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6243c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6244c4837394SDouglas Gilbert 		sdebug_statistics = true;
6245c4837394SDouglas Gilbert 	}
6246c4837394SDouglas Gilbert 	tweak_cmnd_count();
62471da177e4SLinus Torvalds 	return count;
62481da177e4SLinus Torvalds }
624982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
62501da177e4SLinus Torvalds 
6251ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6252ad0c7775SDouglas Gilbert {
6253ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6254ad0c7775SDouglas Gilbert }
6255ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6256ad0c7775SDouglas Gilbert 				size_t count)
6257ad0c7775SDouglas Gilbert {
6258ad0c7775SDouglas Gilbert 	int n;
6259ad0c7775SDouglas Gilbert 	bool changed;
6260ad0c7775SDouglas Gilbert 
6261ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6262ad0c7775SDouglas Gilbert 		return -EINVAL;
6263ad0c7775SDouglas Gilbert 	if (n >= 0) {
6264ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6265ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6266ad0c7775SDouglas Gilbert 			return -EINVAL;
6267ad0c7775SDouglas Gilbert 		}
6268ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6269ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6270ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6271ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6272ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6273ad0c7775SDouglas Gilbert 
6274ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6275ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6276ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6277ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6278ad0c7775SDouglas Gilbert 				}
6279ad0c7775SDouglas Gilbert 			}
6280ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6281ad0c7775SDouglas Gilbert 		}
6282ad0c7775SDouglas Gilbert 		return count;
6283ad0c7775SDouglas Gilbert 	}
6284ad0c7775SDouglas Gilbert 	return -EINVAL;
6285ad0c7775SDouglas Gilbert }
6286ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6287ad0c7775SDouglas Gilbert 
628882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
62891da177e4SLinus Torvalds {
6290773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
62911da177e4SLinus Torvalds }
629282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
629382069379SAkinobu Mita 			      size_t count)
62941da177e4SLinus Torvalds {
62951da177e4SLinus Torvalds 	int n;
629619c8ead7SEwan D. Milne 	bool changed;
62971da177e4SLinus Torvalds 
62981da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
62998d039e22SDouglas Gilbert 		if (n > 256) {
63008d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
63018d039e22SDouglas Gilbert 			return -EINVAL;
63028d039e22SDouglas Gilbert 		}
6303773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6304773642d9SDouglas Gilbert 		sdebug_max_luns = n;
63051da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6306773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
630719c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
630819c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
630919c8ead7SEwan D. Milne 
631019c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
631119c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
631219c8ead7SEwan D. Milne 					    host_list) {
631319c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
631419c8ead7SEwan D. Milne 						    dev_list) {
631519c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
631619c8ead7SEwan D. Milne 						dp->uas_bm);
631719c8ead7SEwan D. Milne 				}
631819c8ead7SEwan D. Milne 			}
631919c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
632019c8ead7SEwan D. Milne 		}
63211da177e4SLinus Torvalds 		return count;
63221da177e4SLinus Torvalds 	}
63231da177e4SLinus Torvalds 	return -EINVAL;
63241da177e4SLinus Torvalds }
632582069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
63261da177e4SLinus Torvalds 
632782069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
632878d4e5a0SDouglas Gilbert {
6329773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
633078d4e5a0SDouglas Gilbert }
6331cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6332cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
633382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
633482069379SAkinobu Mita 			       size_t count)
633578d4e5a0SDouglas Gilbert {
6336c4837394SDouglas Gilbert 	int j, n, k, a;
6337c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
633878d4e5a0SDouglas Gilbert 
633978d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6340c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6341c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
63422aad3cd8SDouglas Gilbert 		sdeb_block_all_queues();
6343c4837394SDouglas Gilbert 		k = 0;
6344c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6345c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6346c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6347c4837394SDouglas Gilbert 			if (a > k)
6348c4837394SDouglas Gilbert 				k = a;
6349c4837394SDouglas Gilbert 		}
6350773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6351c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6352cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6353cbf67842SDouglas Gilbert 		else if (k >= n)
6354cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6355cbf67842SDouglas Gilbert 		else
6356cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
63572aad3cd8SDouglas Gilbert 		sdeb_unblock_all_queues();
635878d4e5a0SDouglas Gilbert 		return count;
635978d4e5a0SDouglas Gilbert 	}
636078d4e5a0SDouglas Gilbert 	return -EINVAL;
636178d4e5a0SDouglas Gilbert }
636282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
636378d4e5a0SDouglas Gilbert 
6364c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6365c10fa55fSJohn Garry {
6366c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6367c10fa55fSJohn Garry }
6368c10fa55fSJohn Garry 
6369c10fa55fSJohn Garry /*
6370c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6371c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6372c10fa55fSJohn Garry  */
6373c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6374c10fa55fSJohn Garry 
637582069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
637678d4e5a0SDouglas Gilbert {
6377773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
637878d4e5a0SDouglas Gilbert }
637982069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
638078d4e5a0SDouglas Gilbert 
638182069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
63821da177e4SLinus Torvalds {
6383773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
63841da177e4SLinus Torvalds }
638582069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
63861da177e4SLinus Torvalds 
638782069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6388c65b1445SDouglas Gilbert {
6389773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6390c65b1445SDouglas Gilbert }
639182069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
639282069379SAkinobu Mita 				size_t count)
6393c65b1445SDouglas Gilbert {
6394c65b1445SDouglas Gilbert 	int n;
63950d01c5dfSDouglas Gilbert 	bool changed;
6396c65b1445SDouglas Gilbert 
6397f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6398f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6399f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6400f0d1cf93SDouglas Gilbert 
6401c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6402773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6403773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
640428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
64050d01c5dfSDouglas Gilbert 		if (changed) {
64060d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
64070d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
640828898873SFUJITA Tomonori 
64094bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
64100d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
64110d01c5dfSDouglas Gilbert 					    host_list) {
64120d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
64130d01c5dfSDouglas Gilbert 						    dev_list) {
64140d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
64150d01c5dfSDouglas Gilbert 						dp->uas_bm);
64160d01c5dfSDouglas Gilbert 				}
64170d01c5dfSDouglas Gilbert 			}
64184bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
64190d01c5dfSDouglas Gilbert 		}
6420c65b1445SDouglas Gilbert 		return count;
6421c65b1445SDouglas Gilbert 	}
6422c65b1445SDouglas Gilbert 	return -EINVAL;
6423c65b1445SDouglas Gilbert }
642482069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6425c65b1445SDouglas Gilbert 
642682069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
64271da177e4SLinus Torvalds {
642887c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
64292aad3cd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts));
64301da177e4SLinus Torvalds }
64311da177e4SLinus Torvalds 
64322aad3cd8SDouglas Gilbert /*
64332aad3cd8SDouglas Gilbert  * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'.
64342aad3cd8SDouglas Gilbert  * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing.
64352aad3cd8SDouglas Gilbert  * Returns -EBUSY if another add_host sysfs invocation is active.
64362aad3cd8SDouglas Gilbert  */
643782069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
643882069379SAkinobu Mita 			      size_t count)
64391da177e4SLinus Torvalds {
64401da177e4SLinus Torvalds 	int delta_hosts;
64411da177e4SLinus Torvalds 
64422aad3cd8SDouglas Gilbert 	if (count == 0 || kstrtoint(buf, 0, &delta_hosts))
64431da177e4SLinus Torvalds 		return -EINVAL;
64442aad3cd8SDouglas Gilbert 	if (sdebug_verbose)
64452aad3cd8SDouglas Gilbert 		pr_info("prior num_hosts=%d, num_to_add=%d\n",
64462aad3cd8SDouglas Gilbert 			atomic_read(&sdebug_num_hosts), delta_hosts);
64472aad3cd8SDouglas Gilbert 	if (delta_hosts == 0)
64482aad3cd8SDouglas Gilbert 		return count;
64492aad3cd8SDouglas Gilbert 	if (mutex_trylock(&add_host_mutex) == 0)
64502aad3cd8SDouglas Gilbert 		return -EBUSY;
64511da177e4SLinus Torvalds 	if (delta_hosts > 0) {
64522aad3cd8SDouglas Gilbert 		sdeb_add_n_hosts(delta_hosts);
64532aad3cd8SDouglas Gilbert 	} else if (delta_hosts < 0) {
64542aad3cd8SDouglas Gilbert 		smp_store_release(&sdebug_deflect_incoming, true);
64552aad3cd8SDouglas Gilbert 		sdeb_block_all_queues();
64562aad3cd8SDouglas Gilbert 		if (delta_hosts >= atomic_read(&sdebug_num_hosts))
64572aad3cd8SDouglas Gilbert 			stop_all_queued(true);
64581da177e4SLinus Torvalds 		do {
64592aad3cd8SDouglas Gilbert 			if (atomic_read(&sdebug_num_hosts) < 1) {
64602aad3cd8SDouglas Gilbert 				free_all_queued();
646187c715dcSDouglas Gilbert 				break;
646287c715dcSDouglas Gilbert 			}
646387c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
64641da177e4SLinus Torvalds 		} while (++delta_hosts);
64652aad3cd8SDouglas Gilbert 		sdeb_unblock_all_queues();
64662aad3cd8SDouglas Gilbert 		smp_store_release(&sdebug_deflect_incoming, false);
64671da177e4SLinus Torvalds 	}
64682aad3cd8SDouglas Gilbert 	mutex_unlock(&add_host_mutex);
64692aad3cd8SDouglas Gilbert 	if (sdebug_verbose)
64702aad3cd8SDouglas Gilbert 		pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts));
64711da177e4SLinus Torvalds 	return count;
64721da177e4SLinus Torvalds }
647382069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
64741da177e4SLinus Torvalds 
647582069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
647623183910SDouglas Gilbert {
6477773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
647823183910SDouglas Gilbert }
647982069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
648082069379SAkinobu Mita 				    size_t count)
648123183910SDouglas Gilbert {
648223183910SDouglas Gilbert 	int n;
648323183910SDouglas Gilbert 
648423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6485773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
648623183910SDouglas Gilbert 		return count;
648723183910SDouglas Gilbert 	}
648823183910SDouglas Gilbert 	return -EINVAL;
648923183910SDouglas Gilbert }
649082069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
649123183910SDouglas Gilbert 
6492c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6493c4837394SDouglas Gilbert {
6494c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6495c4837394SDouglas Gilbert }
6496c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6497c4837394SDouglas Gilbert 				size_t count)
6498c4837394SDouglas Gilbert {
6499c4837394SDouglas Gilbert 	int n;
6500c4837394SDouglas Gilbert 
6501c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6502c4837394SDouglas Gilbert 		if (n > 0)
6503c4837394SDouglas Gilbert 			sdebug_statistics = true;
6504c4837394SDouglas Gilbert 		else {
6505c4837394SDouglas Gilbert 			clear_queue_stats();
6506c4837394SDouglas Gilbert 			sdebug_statistics = false;
6507c4837394SDouglas Gilbert 		}
6508c4837394SDouglas Gilbert 		return count;
6509c4837394SDouglas Gilbert 	}
6510c4837394SDouglas Gilbert 	return -EINVAL;
6511c4837394SDouglas Gilbert }
6512c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6513c4837394SDouglas Gilbert 
651482069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6515597136abSMartin K. Petersen {
6516773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6517597136abSMartin K. Petersen }
651882069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6519597136abSMartin K. Petersen 
6520c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6521c4837394SDouglas Gilbert {
6522c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6523c4837394SDouglas Gilbert }
6524c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6525c4837394SDouglas Gilbert 
652682069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6527c6a44287SMartin K. Petersen {
6528773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6529c6a44287SMartin K. Petersen }
653082069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6531c6a44287SMartin K. Petersen 
653282069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6533c6a44287SMartin K. Petersen {
6534773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6535c6a44287SMartin K. Petersen }
653682069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6537c6a44287SMartin K. Petersen 
653882069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6539c6a44287SMartin K. Petersen {
6540773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6541c6a44287SMartin K. Petersen }
654282069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6543c6a44287SMartin K. Petersen 
654482069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6545c6a44287SMartin K. Petersen {
6546773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6547c6a44287SMartin K. Petersen }
654882069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6549c6a44287SMartin K. Petersen 
655082069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
655144d92694SMartin K. Petersen {
655287c715dcSDouglas Gilbert 	ssize_t count = 0;
655344d92694SMartin K. Petersen 
65545b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
655544d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
655644d92694SMartin K. Petersen 				 sdebug_store_sectors);
655744d92694SMartin K. Petersen 
655887c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
655987c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
656087c715dcSDouglas Gilbert 
656187c715dcSDouglas Gilbert 		if (sip)
6562c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
656387c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
656487c715dcSDouglas Gilbert 	}
656544d92694SMartin K. Petersen 	buf[count++] = '\n';
6566c7badc90STejun Heo 	buf[count] = '\0';
656744d92694SMartin K. Petersen 
656844d92694SMartin K. Petersen 	return count;
656944d92694SMartin K. Petersen }
657082069379SAkinobu Mita static DRIVER_ATTR_RO(map);
657144d92694SMartin K. Petersen 
65720c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
65730c4bc91dSDouglas Gilbert {
65740c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
65750c4bc91dSDouglas Gilbert }
65760c4bc91dSDouglas Gilbert 
65770c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
65780c4bc91dSDouglas Gilbert 			    size_t count)
65790c4bc91dSDouglas Gilbert {
65800c4bc91dSDouglas Gilbert 	bool v;
65810c4bc91dSDouglas Gilbert 
65820c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
65830c4bc91dSDouglas Gilbert 		return -EINVAL;
65840c4bc91dSDouglas Gilbert 
65850c4bc91dSDouglas Gilbert 	sdebug_random = v;
65860c4bc91dSDouglas Gilbert 	return count;
65870c4bc91dSDouglas Gilbert }
65880c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
65890c4bc91dSDouglas Gilbert 
659082069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6591d986788bSMartin Pitt {
6592773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6593d986788bSMartin Pitt }
659482069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
659582069379SAkinobu Mita 			       size_t count)
6596d986788bSMartin Pitt {
6597d986788bSMartin Pitt 	int n;
6598d986788bSMartin Pitt 
6599d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6600773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6601d986788bSMartin Pitt 		return count;
6602d986788bSMartin Pitt 	}
6603d986788bSMartin Pitt 	return -EINVAL;
6604d986788bSMartin Pitt }
660582069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6606d986788bSMartin Pitt 
6607cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6608cbf67842SDouglas Gilbert {
6609773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6610cbf67842SDouglas Gilbert }
6611185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6612cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6613cbf67842SDouglas Gilbert 			       size_t count)
6614cbf67842SDouglas Gilbert {
6615185dd232SDouglas Gilbert 	int n;
6616cbf67842SDouglas Gilbert 
6617cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6618185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6619185dd232SDouglas Gilbert 		return count;
6620cbf67842SDouglas Gilbert 	}
6621cbf67842SDouglas Gilbert 	return -EINVAL;
6622cbf67842SDouglas Gilbert }
6623cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6624cbf67842SDouglas Gilbert 
6625c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6626c2248fc9SDouglas Gilbert {
6627773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6628c2248fc9SDouglas Gilbert }
6629c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6630c2248fc9SDouglas Gilbert 			    size_t count)
6631c2248fc9SDouglas Gilbert {
6632c2248fc9SDouglas Gilbert 	int n;
6633c2248fc9SDouglas Gilbert 
6634c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6635773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6636c2248fc9SDouglas Gilbert 		return count;
6637c2248fc9SDouglas Gilbert 	}
6638c2248fc9SDouglas Gilbert 	return -EINVAL;
6639c2248fc9SDouglas Gilbert }
6640c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6641c2248fc9SDouglas Gilbert 
664209ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
664309ba24c1SDouglas Gilbert {
664409ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
664509ba24c1SDouglas Gilbert }
664609ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
664709ba24c1SDouglas Gilbert 
66489b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
66499b760fd8SDouglas Gilbert {
66509b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
66519b760fd8SDouglas Gilbert }
66529b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
66539b760fd8SDouglas Gilbert 			     size_t count)
66549b760fd8SDouglas Gilbert {
66559b760fd8SDouglas Gilbert 	int ret, n;
66569b760fd8SDouglas Gilbert 
66579b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
66589b760fd8SDouglas Gilbert 	if (ret)
66599b760fd8SDouglas Gilbert 		return ret;
66609b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
66619b760fd8SDouglas Gilbert 	all_config_cdb_len();
66629b760fd8SDouglas Gilbert 	return count;
66639b760fd8SDouglas Gilbert }
66649b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
66659b760fd8SDouglas Gilbert 
66669267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
66679267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
66689267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
66699267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
66709267e0ebSDouglas Gilbert };
66719267e0ebSDouglas Gilbert 
66729267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
66739267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
66749267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
66759267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
66769267e0ebSDouglas Gilbert };
66779267e0ebSDouglas Gilbert 
66789267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
66799267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
66809267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
66819267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
66829267e0ebSDouglas Gilbert };
66839267e0ebSDouglas Gilbert 
66849267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
66859267e0ebSDouglas Gilbert {
66869267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
66879267e0ebSDouglas Gilbert 
66889267e0ebSDouglas Gilbert 	if (res < 0) {
66899267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
66909267e0ebSDouglas Gilbert 		if (res < 0) {
66919267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
669247742bdeSDan Carpenter 			if (res < 0)
66939267e0ebSDouglas Gilbert 				return -EINVAL;
66949267e0ebSDouglas Gilbert 		}
66959267e0ebSDouglas Gilbert 	}
66969267e0ebSDouglas Gilbert 	return res;
66979267e0ebSDouglas Gilbert }
66989267e0ebSDouglas Gilbert 
66999267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
67009267e0ebSDouglas Gilbert {
67019267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
67029267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
67039267e0ebSDouglas Gilbert }
67049267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6705cbf67842SDouglas Gilbert 
6706fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6707fc13638aSDouglas Gilbert {
6708fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6709fc13638aSDouglas Gilbert }
6710fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6711fc13638aSDouglas Gilbert 
671282069379SAkinobu Mita /* Note: The following array creates attribute files in the
671323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
671423183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
671523183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
671687c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
671723183910SDouglas Gilbert  */
67186ecaff7fSRandy Dunlap 
671982069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
672082069379SAkinobu Mita 	&driver_attr_delay.attr,
672182069379SAkinobu Mita 	&driver_attr_opts.attr,
672282069379SAkinobu Mita 	&driver_attr_ptype.attr,
672382069379SAkinobu Mita 	&driver_attr_dsense.attr,
672482069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6725c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
672682069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
672782069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
672882069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
672982069379SAkinobu Mita 	&driver_attr_num_parts.attr,
673082069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6731ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
673282069379SAkinobu Mita 	&driver_attr_max_luns.attr,
673382069379SAkinobu Mita 	&driver_attr_max_queue.attr,
673482069379SAkinobu Mita 	&driver_attr_no_uld.attr,
673582069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
673682069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
673782069379SAkinobu Mita 	&driver_attr_add_host.attr,
673887c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
673982069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
674082069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6741c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6742c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
674382069379SAkinobu Mita 	&driver_attr_dix.attr,
674482069379SAkinobu Mita 	&driver_attr_dif.attr,
674582069379SAkinobu Mita 	&driver_attr_guard.attr,
674682069379SAkinobu Mita 	&driver_attr_ato.attr,
674782069379SAkinobu Mita 	&driver_attr_map.attr,
67480c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
674982069379SAkinobu Mita 	&driver_attr_removable.attr,
6750cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6751cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6752c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
675309ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
67549b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6755fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
67569267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
675782069379SAkinobu Mita 	NULL,
675882069379SAkinobu Mita };
675982069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
67601da177e4SLinus Torvalds 
676111ddcecaSAkinobu Mita static struct device *pseudo_primary;
67628dea0d02SFUJITA Tomonori 
67631da177e4SLinus Torvalds static int __init scsi_debug_init(void)
67641da177e4SLinus Torvalds {
676587c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
67665f2578e5SFUJITA Tomonori 	unsigned long sz;
676787c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
676887c715dcSDouglas Gilbert 	int idx = -1;
67691da177e4SLinus Torvalds 
677087c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
677187c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6772cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6773cbf67842SDouglas Gilbert 
6774773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6775c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6776773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6777773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6778c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6779cbf67842SDouglas Gilbert 
6780773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6781597136abSMartin K. Petersen 	case  512:
6782597136abSMartin K. Petersen 	case 1024:
6783597136abSMartin K. Petersen 	case 2048:
6784597136abSMartin K. Petersen 	case 4096:
6785597136abSMartin K. Petersen 		break;
6786597136abSMartin K. Petersen 	default:
6787773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6788597136abSMartin K. Petersen 		return -EINVAL;
6789597136abSMartin K. Petersen 	}
6790597136abSMartin K. Petersen 
6791773642d9SDouglas Gilbert 	switch (sdebug_dif) {
67928475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6793f46eb0e9SDouglas Gilbert 		break;
67948475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
67958475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
67968475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6797f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6798c6a44287SMartin K. Petersen 		break;
6799c6a44287SMartin K. Petersen 
6800c6a44287SMartin K. Petersen 	default:
6801c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6802c6a44287SMartin K. Petersen 		return -EINVAL;
6803c6a44287SMartin K. Petersen 	}
6804c6a44287SMartin K. Petersen 
6805aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6806aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6807aa5334c4SMaurizio Lombardi 		return -EINVAL;
6808aa5334c4SMaurizio Lombardi 	}
6809aa5334c4SMaurizio Lombardi 
6810773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6811c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6812c6a44287SMartin K. Petersen 		return -EINVAL;
6813c6a44287SMartin K. Petersen 	}
6814c6a44287SMartin K. Petersen 
6815773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6816c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6817c6a44287SMartin K. Petersen 		return -EINVAL;
6818c6a44287SMartin K. Petersen 	}
6819c6a44287SMartin K. Petersen 
6820773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6821773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6822ea61fca5SMartin K. Petersen 		return -EINVAL;
6823ea61fca5SMartin K. Petersen 	}
6824ad0c7775SDouglas Gilbert 
6825ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6826ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6827ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6828ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6829ad0c7775SDouglas Gilbert 	}
6830ad0c7775SDouglas Gilbert 
68318d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6832ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6833ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
68348d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
68358d039e22SDouglas Gilbert 		}
6836ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6837ad0c7775SDouglas Gilbert 	}
6838ea61fca5SMartin K. Petersen 
6839773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6840773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6841ea61fca5SMartin K. Petersen 		return -EINVAL;
6842ea61fca5SMartin K. Petersen 	}
6843ea61fca5SMartin K. Petersen 
6844c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6845c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6846c4837394SDouglas Gilbert 		return -EINVAL;
6847c4837394SDouglas Gilbert 	}
6848c87bf24cSJohn Garry 
6849c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6850c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6851c87bf24cSJohn Garry 		return -EINVAL;
6852c87bf24cSJohn Garry 	}
6853c87bf24cSJohn Garry 
6854c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6855c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6856c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6857c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6858c10fa55fSJohn Garry 		return -EINVAL;
6859c10fa55fSJohn Garry 	}
6860c10fa55fSJohn Garry 
6861c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6862c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6863c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6864c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6865c10fa55fSJohn Garry 			sdebug_max_queue);
6866c10fa55fSJohn Garry 	}
6867c10fa55fSJohn Garry 
6868c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6869c4837394SDouglas Gilbert 			       GFP_KERNEL);
6870c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6871c4837394SDouglas Gilbert 		return -ENOMEM;
6872c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6873c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6874c4837394SDouglas Gilbert 
6875f0d1cf93SDouglas Gilbert 	/*
68769267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
68779267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6878f0d1cf93SDouglas Gilbert 	 */
68799267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
68809267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
68819267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
68829267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
68839267e0ebSDouglas Gilbert 		if (k < 0) {
68849267e0ebSDouglas Gilbert 			ret = k;
68853b01d7eaSDinghao Liu 			goto free_q_arr;
68869267e0ebSDouglas Gilbert 		}
68879267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
68889267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
68899267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
689064e14eceSDamien Le Moal 		case BLK_ZONED_HA:
68919267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
68929267e0ebSDouglas Gilbert 			break;
68939267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
68949267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
68959267e0ebSDouglas Gilbert 			break;
68969267e0ebSDouglas Gilbert 		default:
68979267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
68983b01d7eaSDinghao Liu 			ret = -EINVAL;
68993b01d7eaSDinghao Liu 			goto free_q_arr;
69009267e0ebSDouglas Gilbert 		}
69019267e0ebSDouglas Gilbert 	}
69029267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6903f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
69049267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
69059267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
69069267e0ebSDouglas Gilbert 	}
6907f0d1cf93SDouglas Gilbert 
69089267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
69099267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6910773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6911773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6912773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6913773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
691428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
69151da177e4SLinus Torvalds 
69161da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
69171da177e4SLinus Torvalds 	sdebug_heads = 8;
69181da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6919773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
69201da177e4SLinus Torvalds 		sdebug_heads = 64;
6921773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6922fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
69231da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
69241da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
69251da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
69261da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
69271da177e4SLinus Torvalds 		sdebug_heads = 255;
69281da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
69291da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
69301da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
69311da177e4SLinus Torvalds 	}
69325b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6933773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6934773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
69356014759cSMartin K. Petersen 
6936773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6937773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
69386014759cSMartin K. Petersen 
6939773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6940773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
69416014759cSMartin K. Petersen 
6942773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6943773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6944773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6945c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6946c4837394SDouglas Gilbert 			ret = -EINVAL;
694787c715dcSDouglas Gilbert 			goto free_q_arr;
694844d92694SMartin K. Petersen 		}
694944d92694SMartin K. Petersen 	}
695087c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
695187c715dcSDouglas Gilbert 	if (want_store) {
695287c715dcSDouglas Gilbert 		idx = sdebug_add_store();
695387c715dcSDouglas Gilbert 		if (idx < 0) {
695487c715dcSDouglas Gilbert 			ret = idx;
695587c715dcSDouglas Gilbert 			goto free_q_arr;
695687c715dcSDouglas Gilbert 		}
695744d92694SMartin K. Petersen 	}
695844d92694SMartin K. Petersen 
69599b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
69609b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6961c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
69629b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
69636ecaff7fSRandy Dunlap 		goto free_vm;
69646ecaff7fSRandy Dunlap 	}
69656ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
69666ecaff7fSRandy Dunlap 	if (ret < 0) {
6967c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
69686ecaff7fSRandy Dunlap 		goto dev_unreg;
69696ecaff7fSRandy Dunlap 	}
69706ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
69716ecaff7fSRandy Dunlap 	if (ret < 0) {
6972c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
69736ecaff7fSRandy Dunlap 		goto bus_unreg;
69746ecaff7fSRandy Dunlap 	}
69751da177e4SLinus Torvalds 
697687c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6977773642d9SDouglas Gilbert 	sdebug_add_host = 0;
69781da177e4SLinus Torvalds 
697987c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
69802aad3cd8SDouglas Gilbert 		if (smp_load_acquire(&sdebug_deflect_incoming)) {
69812aad3cd8SDouglas Gilbert 			pr_info("exit early as sdebug_deflect_incoming is set\n");
69822aad3cd8SDouglas Gilbert 			return 0;
69832aad3cd8SDouglas Gilbert 		}
698487c715dcSDouglas Gilbert 		if (want_store && k == 0) {
698587c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
698687c715dcSDouglas Gilbert 			if (ret < 0) {
698787c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
698887c715dcSDouglas Gilbert 				       k, -ret);
698987c715dcSDouglas Gilbert 				break;
699087c715dcSDouglas Gilbert 			}
699187c715dcSDouglas Gilbert 		} else {
699287c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
699387c715dcSDouglas Gilbert 						 sdebug_per_host_store);
699487c715dcSDouglas Gilbert 			if (ret < 0) {
699587c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
69961da177e4SLinus Torvalds 				break;
69971da177e4SLinus Torvalds 			}
69981da177e4SLinus Torvalds 		}
699987c715dcSDouglas Gilbert 	}
7000773642d9SDouglas Gilbert 	if (sdebug_verbose)
70012aad3cd8SDouglas Gilbert 		pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts));
7002c1287970STomas Winkler 
70032aad3cd8SDouglas Gilbert 	/*
70042aad3cd8SDouglas Gilbert 	 * Even though all the hosts have been established, due to async device (LU) scanning
70052aad3cd8SDouglas Gilbert 	 * by the scsi mid-level, there may still be devices (LUs) being set up.
70062aad3cd8SDouglas Gilbert 	 */
70071da177e4SLinus Torvalds 	return 0;
70086ecaff7fSRandy Dunlap 
70096ecaff7fSRandy Dunlap bus_unreg:
70106ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
70116ecaff7fSRandy Dunlap dev_unreg:
70129b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
70136ecaff7fSRandy Dunlap free_vm:
701487c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
7015c4837394SDouglas Gilbert free_q_arr:
7016c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
70176ecaff7fSRandy Dunlap 	return ret;
70181da177e4SLinus Torvalds }
70191da177e4SLinus Torvalds 
70201da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
70211da177e4SLinus Torvalds {
70222aad3cd8SDouglas Gilbert 	int k;
70231da177e4SLinus Torvalds 
70242aad3cd8SDouglas Gilbert 	/* Possible race with LUs still being set up; stop them asap */
70252aad3cd8SDouglas Gilbert 	sdeb_block_all_queues();
70262aad3cd8SDouglas Gilbert 	smp_store_release(&sdebug_deflect_incoming, true);
70272aad3cd8SDouglas Gilbert 	stop_all_queued(false);
70282aad3cd8SDouglas Gilbert 	for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++)
702987c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
703052ab9768SLuis Henriques 	free_all_queued();
70312aad3cd8SDouglas Gilbert 	if (sdebug_verbose)
70322aad3cd8SDouglas Gilbert 		pr_info("removed %d hosts\n", k);
70331da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
70341da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
70359b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
70361da177e4SLinus Torvalds 
703787c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
703887c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
7039f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
70401da177e4SLinus Torvalds }
70411da177e4SLinus Torvalds 
70421da177e4SLinus Torvalds device_initcall(scsi_debug_init);
70431da177e4SLinus Torvalds module_exit(scsi_debug_exit);
70441da177e4SLinus Torvalds 
70451da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
70461da177e4SLinus Torvalds {
70471da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
70481da177e4SLinus Torvalds 
70491da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
70501da177e4SLinus Torvalds 	kfree(sdbg_host);
70511da177e4SLinus Torvalds }
70521da177e4SLinus Torvalds 
705387c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
705487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
70551da177e4SLinus Torvalds {
705687c715dcSDouglas Gilbert 	if (idx < 0)
705787c715dcSDouglas Gilbert 		return;
705887c715dcSDouglas Gilbert 	if (!sip) {
705987c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
706087c715dcSDouglas Gilbert 			return;
706187c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
706287c715dcSDouglas Gilbert 		if (!sip)
706387c715dcSDouglas Gilbert 			return;
706487c715dcSDouglas Gilbert 	}
706587c715dcSDouglas Gilbert 	vfree(sip->map_storep);
706687c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
706787c715dcSDouglas Gilbert 	vfree(sip->storep);
706887c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
706987c715dcSDouglas Gilbert 	kfree(sip);
707087c715dcSDouglas Gilbert }
707187c715dcSDouglas Gilbert 
707287c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
707387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
707487c715dcSDouglas Gilbert {
707587c715dcSDouglas Gilbert 	unsigned long idx;
707687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
707787c715dcSDouglas Gilbert 
707887c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
707987c715dcSDouglas Gilbert 		if (apart_from_first)
708087c715dcSDouglas Gilbert 			apart_from_first = false;
708187c715dcSDouglas Gilbert 		else
708287c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
708387c715dcSDouglas Gilbert 	}
708487c715dcSDouglas Gilbert 	if (apart_from_first)
708587c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
708687c715dcSDouglas Gilbert }
708787c715dcSDouglas Gilbert 
708887c715dcSDouglas Gilbert /*
708987c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
709087c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
709187c715dcSDouglas Gilbert  */
709287c715dcSDouglas Gilbert static int sdebug_add_store(void)
709387c715dcSDouglas Gilbert {
709487c715dcSDouglas Gilbert 	int res;
709587c715dcSDouglas Gilbert 	u32 n_idx;
709687c715dcSDouglas Gilbert 	unsigned long iflags;
709787c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
709887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
709987c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
710087c715dcSDouglas Gilbert 
710187c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
710287c715dcSDouglas Gilbert 	if (!sip)
710387c715dcSDouglas Gilbert 		return -ENOMEM;
710487c715dcSDouglas Gilbert 
710587c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
710687c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
710787c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
710887c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
710987c715dcSDouglas Gilbert 		kfree(sip);
711087c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
711187c715dcSDouglas Gilbert 		return res;
711287c715dcSDouglas Gilbert 	}
711387c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
711487c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
711587c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
711687c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
711787c715dcSDouglas Gilbert 
711887c715dcSDouglas Gilbert 	res = -ENOMEM;
711987c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
712087c715dcSDouglas Gilbert 	if (!sip->storep) {
712187c715dcSDouglas Gilbert 		pr_err("user data oom\n");
712287c715dcSDouglas Gilbert 		goto err;
712387c715dcSDouglas Gilbert 	}
712487c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
712587c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
712687c715dcSDouglas Gilbert 
712787c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
712887c715dcSDouglas Gilbert 	if (sdebug_dix) {
712987c715dcSDouglas Gilbert 		int dif_size;
713087c715dcSDouglas Gilbert 
713187c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
713287c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
713387c715dcSDouglas Gilbert 
713487c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
713587c715dcSDouglas Gilbert 			sip->dif_storep);
713687c715dcSDouglas Gilbert 
713787c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
713887c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
713987c715dcSDouglas Gilbert 			goto err;
714087c715dcSDouglas Gilbert 		}
714187c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
714287c715dcSDouglas Gilbert 	}
714387c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
714487c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
714587c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
714687c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
714787c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
714887c715dcSDouglas Gilbert 
714987c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
715087c715dcSDouglas Gilbert 
715187c715dcSDouglas Gilbert 		if (!sip->map_storep) {
715287c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
715387c715dcSDouglas Gilbert 			goto err;
715487c715dcSDouglas Gilbert 		}
715587c715dcSDouglas Gilbert 
715687c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
715787c715dcSDouglas Gilbert 
715887c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
715987c715dcSDouglas Gilbert 		if (sdebug_num_parts)
716087c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
716187c715dcSDouglas Gilbert 	}
716287c715dcSDouglas Gilbert 
716387c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
716487c715dcSDouglas Gilbert 	return (int)n_idx;
716587c715dcSDouglas Gilbert err:
716687c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
716787c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
716887c715dcSDouglas Gilbert 	return res;
716987c715dcSDouglas Gilbert }
717087c715dcSDouglas Gilbert 
717187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
717287c715dcSDouglas Gilbert {
717387c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
717487c715dcSDouglas Gilbert 	int error = -ENOMEM;
71751da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71768b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
71771da177e4SLinus Torvalds 
717824669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
717987c715dcSDouglas Gilbert 	if (!sdbg_host)
71801da177e4SLinus Torvalds 		return -ENOMEM;
718187c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
718287c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
718387c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
718487c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
71851da177e4SLinus Torvalds 
71861da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
71871da177e4SLinus Torvalds 
7188773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
71891da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
71905cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
719187c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
71921da177e4SLinus Torvalds 			goto clean;
71931da177e4SLinus Torvalds 	}
71941da177e4SLinus Torvalds 
71951da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
71961da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
71971da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
71981da177e4SLinus Torvalds 
71991da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
72009b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
72011da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
72022aad3cd8SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts));
72031da177e4SLinus Torvalds 
72041da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
72051da177e4SLinus Torvalds 	if (error)
72061da177e4SLinus Torvalds 		goto clean;
72071da177e4SLinus Torvalds 
72082aad3cd8SDouglas Gilbert 	atomic_inc(&sdebug_num_hosts);
720987c715dcSDouglas Gilbert 	return 0;
72101da177e4SLinus Torvalds 
72111da177e4SLinus Torvalds clean:
72128b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
72138b40228fSFUJITA Tomonori 				 dev_list) {
72141da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7215f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
72161da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
72171da177e4SLinus Torvalds 	}
72181da177e4SLinus Torvalds 	kfree(sdbg_host);
721987c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
72201da177e4SLinus Torvalds 	return error;
72211da177e4SLinus Torvalds }
72221da177e4SLinus Torvalds 
722387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
72241da177e4SLinus Torvalds {
722587c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
722687c715dcSDouglas Gilbert 
722787c715dcSDouglas Gilbert 	if (mk_new_store) {
722887c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
722987c715dcSDouglas Gilbert 		if (ph_idx < 0)
723087c715dcSDouglas Gilbert 			return ph_idx;
723187c715dcSDouglas Gilbert 	}
723287c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
723387c715dcSDouglas Gilbert }
723487c715dcSDouglas Gilbert 
723587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
723687c715dcSDouglas Gilbert {
723787c715dcSDouglas Gilbert 	int idx = -1;
72381da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
723987c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
72401da177e4SLinus Torvalds 
72411da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
72421da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
72431da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
72441da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
724587c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
72461da177e4SLinus Torvalds 	}
724787c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
724887c715dcSDouglas Gilbert 		bool unique = true;
724987c715dcSDouglas Gilbert 
725087c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
725187c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
725287c715dcSDouglas Gilbert 				continue;
725387c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
725487c715dcSDouglas Gilbert 				unique = false;
725587c715dcSDouglas Gilbert 				break;
725687c715dcSDouglas Gilbert 			}
725787c715dcSDouglas Gilbert 		}
725887c715dcSDouglas Gilbert 		if (unique) {
725987c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
726087c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
726187c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
726287c715dcSDouglas Gilbert 		}
726387c715dcSDouglas Gilbert 	}
726487c715dcSDouglas Gilbert 	if (sdbg_host)
726587c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
72661da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
72671da177e4SLinus Torvalds 
72681da177e4SLinus Torvalds 	if (!sdbg_host)
72691da177e4SLinus Torvalds 		return;
72701da177e4SLinus Torvalds 
72711da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
72722aad3cd8SDouglas Gilbert 	atomic_dec(&sdebug_num_hosts);
72731da177e4SLinus Torvalds }
72741da177e4SLinus Torvalds 
7275fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7276cbf67842SDouglas Gilbert {
7277cbf67842SDouglas Gilbert 	int num_in_q = 0;
7278cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7279cbf67842SDouglas Gilbert 
72802aad3cd8SDouglas Gilbert 	sdeb_block_all_queues();
7281cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7282cbf67842SDouglas Gilbert 	if (NULL == devip) {
72832aad3cd8SDouglas Gilbert 		sdeb_unblock_all_queues();
7284cbf67842SDouglas Gilbert 		return	-ENODEV;
7285cbf67842SDouglas Gilbert 	}
7286cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7287c40ecc12SChristoph Hellwig 
7288fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7289fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7290fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7291fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7292fc09acb7SDouglas Gilbert 	}
7293cbf67842SDouglas Gilbert 	if (qdepth < 1)
7294cbf67842SDouglas Gilbert 		qdepth = 1;
7295fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7296db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7297cbf67842SDouglas Gilbert 
7298773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7299c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7300c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7301cbf67842SDouglas Gilbert 	}
73022aad3cd8SDouglas Gilbert 	sdeb_unblock_all_queues();
7303cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7304cbf67842SDouglas Gilbert }
7305cbf67842SDouglas Gilbert 
7306c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7307817fd66bSDouglas Gilbert {
7308c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7309773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7310773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7311773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7312c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7313773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7314817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7315c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7316817fd66bSDouglas Gilbert 	}
7317c4837394SDouglas Gilbert 	return false;
7318817fd66bSDouglas Gilbert }
7319817fd66bSDouglas Gilbert 
7320fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7321fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7322fc13638aSDouglas Gilbert {
7323fc13638aSDouglas Gilbert 	int stopped_state;
7324fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7325fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7326fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7327fc13638aSDouglas Gilbert 
7328fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7329fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7330fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7331fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7332fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7333fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7334fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7335fc13638aSDouglas Gilbert 				return 0;
7336fc13638aSDouglas Gilbert 			}
7337fc13638aSDouglas Gilbert 		}
7338fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7339fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7340fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7341fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7342fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7343fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7344fc13638aSDouglas Gilbert 
7345fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7346fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7347fc13638aSDouglas Gilbert 			else
7348fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7349fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7350fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7351fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7352fc13638aSDouglas Gilbert 						   diff_ns);
7353fc13638aSDouglas Gilbert 			return check_condition_result;
7354fc13638aSDouglas Gilbert 		}
7355fc13638aSDouglas Gilbert 	}
7356fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7357fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7358fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7359fc13638aSDouglas Gilbert 			    my_name);
7360fc13638aSDouglas Gilbert 	return check_condition_result;
7361fc13638aSDouglas Gilbert }
7362fc13638aSDouglas Gilbert 
7363c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost)
7364c4b57d89SKashyap Desai {
7365c4b57d89SKashyap Desai 	int i, qoff;
7366c4b57d89SKashyap Desai 
7367c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7368c4b57d89SKashyap Desai 		return 0;
7369c4b57d89SKashyap Desai 
7370c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7371c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7372c4b57d89SKashyap Desai 
7373c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7374c4b57d89SKashyap Desai 
7375c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7376c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7377c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7378c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7379c4b57d89SKashyap Desai 
7380c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7381c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7382c4b57d89SKashyap Desai 			continue;
7383c4b57d89SKashyap Desai 		}
7384c4b57d89SKashyap Desai 
7385c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7386c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7387c4b57d89SKashyap Desai 
7388c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7389c4b57d89SKashyap Desai 	}
7390c4b57d89SKashyap Desai 
7391c4b57d89SKashyap Desai 	return 0;
7392c4b57d89SKashyap Desai 
7393c4b57d89SKashyap Desai }
7394c4b57d89SKashyap Desai 
7395c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7396c4b57d89SKashyap Desai {
73974a0c6f43SDouglas Gilbert 	bool first;
73984a0c6f43SDouglas Gilbert 	bool retiring = false;
73994a0c6f43SDouglas Gilbert 	int num_entries = 0;
74004a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7401c4b57d89SKashyap Desai 	unsigned long iflags;
74024a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7403c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7404c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7405c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7406c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
74074a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7408c4b57d89SKashyap Desai 
7409c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
7410c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
74114a0c6f43SDouglas Gilbert 
74124a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
74134a0c6f43SDouglas Gilbert 		if (first) {
7414c4b57d89SKashyap Desai 			qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
74154a0c6f43SDouglas Gilbert 			first = false;
74164a0c6f43SDouglas Gilbert 		} else {
74174a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
74184a0c6f43SDouglas Gilbert 		}
74194a0c6f43SDouglas Gilbert 		if (unlikely(qc_idx >= sdebug_max_queue))
74204a0c6f43SDouglas Gilbert 			break;
7421c4b57d89SKashyap Desai 
7422c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
74234a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
74244a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
74254a0c6f43SDouglas Gilbert 			continue;
7426c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7427c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
74284a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7429c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
74304a0c6f43SDouglas Gilbert 			break;
7431c4b57d89SKashyap Desai 		}
7432d9d23a5aSDouglas Gilbert 		if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) {
74334a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
74344a0c6f43SDouglas Gilbert 				continue;
74354a0c6f43SDouglas Gilbert 
74366ce913feSChristoph Hellwig 		} else		/* ignoring non REQ_POLLED requests */
74374a0c6f43SDouglas Gilbert 			continue;
7438c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7439c4b57d89SKashyap Desai 		if (likely(devip))
7440c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7441c4b57d89SKashyap Desai 		else
7442c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7443c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
74444a0c6f43SDouglas Gilbert 			retiring = true;
7445c4b57d89SKashyap Desai 
7446c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7447c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
74484a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7449c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
74504a0c6f43SDouglas Gilbert 			break;
7451c4b57d89SKashyap Desai 		}
7452c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7453c4b57d89SKashyap Desai 			int k, retval;
7454c4b57d89SKashyap Desai 
7455c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7456c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7457c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
74584a0c6f43SDouglas Gilbert 				break;
7459c4b57d89SKashyap Desai 			}
7460c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7461c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7462c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7463c4b57d89SKashyap Desai 			else
7464c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7465c4b57d89SKashyap Desai 		}
7466d9d23a5aSDouglas Gilbert 		WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
7467c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
74686c2c7d6aSBart Van Assche 		scsi_done(scp); /* callback to mid level */
74694a0c6f43SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7470c4b57d89SKashyap Desai 		num_entries++;
74714a0c6f43SDouglas Gilbert 	}
7472c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
74734a0c6f43SDouglas Gilbert 	if (num_entries > 0)
74744a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7475c4b57d89SKashyap Desai 	return num_entries;
7476c4b57d89SKashyap Desai }
7477c4b57d89SKashyap Desai 
7478fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7479fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7480c2248fc9SDouglas Gilbert {
7481c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7482c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7483c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7484c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7485c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7486c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7487c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7488f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7489c2248fc9SDouglas Gilbert 	int k, na;
7490c2248fc9SDouglas Gilbert 	int errsts = 0;
7491ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7492c2248fc9SDouglas Gilbert 	u32 flags;
7493c2248fc9SDouglas Gilbert 	u16 sa;
7494c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7495c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
74963a90a63dSDouglas Gilbert 	bool inject_now;
7497c2248fc9SDouglas Gilbert 
7498c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
74993a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7500c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
75013a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
75023a90a63dSDouglas Gilbert 	} else {
75033a90a63dSDouglas Gilbert 		inject_now = false;
75043a90a63dSDouglas Gilbert 	}
7505f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7506f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7507c2248fc9SDouglas Gilbert 		char b[120];
7508c2248fc9SDouglas Gilbert 		int n, len, sb;
7509c2248fc9SDouglas Gilbert 
7510c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7511c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7512c2248fc9SDouglas Gilbert 		if (len > 32)
7513c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7514c2248fc9SDouglas Gilbert 		else {
7515c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7516c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7517c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7518c2248fc9SDouglas Gilbert 		}
7519458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7520a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7521c2248fc9SDouglas Gilbert 	}
75223a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
75237ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
752434d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7525ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7526f46eb0e9SDouglas Gilbert 		goto err_out;
7527c2248fc9SDouglas Gilbert 
7528c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7529c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7530c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7531f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7532f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7533c2248fc9SDouglas Gilbert 		if (NULL == devip)
7534f46eb0e9SDouglas Gilbert 			goto err_out;
7535c2248fc9SDouglas Gilbert 	}
75363a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
75373a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
75383a90a63dSDouglas Gilbert 
7539c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7540c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7541c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7542c2248fc9SDouglas Gilbert 		r_oip = oip;
7543c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7544c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7545c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7546c2248fc9SDouglas Gilbert 			else
7547c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7548c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7549c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7550c2248fc9SDouglas Gilbert 					break;
7551c2248fc9SDouglas Gilbert 			}
7552c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7553c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7554c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7555c2248fc9SDouglas Gilbert 					break;
7556c2248fc9SDouglas Gilbert 			}
7557c2248fc9SDouglas Gilbert 		}
7558c2248fc9SDouglas Gilbert 		if (k > na) {
7559c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7560c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7561c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7562c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7563c2248fc9SDouglas Gilbert 			else
7564c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7565c2248fc9SDouglas Gilbert 			goto check_cond;
7566c2248fc9SDouglas Gilbert 		}
7567c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7568c2248fc9SDouglas Gilbert 	flags = oip->flags;
7569f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7570c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7571c2248fc9SDouglas Gilbert 		goto check_cond;
7572c2248fc9SDouglas Gilbert 	}
7573f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7574773642d9SDouglas Gilbert 		if (sdebug_verbose)
7575773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7576773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7577c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7578c2248fc9SDouglas Gilbert 		goto check_cond;
7579c2248fc9SDouglas Gilbert 	}
7580f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7581c2248fc9SDouglas Gilbert 		u8 rem;
7582c2248fc9SDouglas Gilbert 		int j;
7583c2248fc9SDouglas Gilbert 
7584c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7585c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7586c2248fc9SDouglas Gilbert 			if (rem) {
7587c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7588c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7589c2248fc9SDouglas Gilbert 						break;
7590c2248fc9SDouglas Gilbert 				}
7591c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7592c2248fc9SDouglas Gilbert 				goto check_cond;
7593c2248fc9SDouglas Gilbert 			}
7594c2248fc9SDouglas Gilbert 		}
7595c2248fc9SDouglas Gilbert 	}
7596f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7597b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7598b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7599f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7600c2248fc9SDouglas Gilbert 		if (errsts)
7601c2248fc9SDouglas Gilbert 			goto check_cond;
7602c2248fc9SDouglas Gilbert 	}
7603fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7604fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7605fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7606fc13638aSDouglas Gilbert 		if (errsts)
7607c2248fc9SDouglas Gilbert 			goto fini;
7608c2248fc9SDouglas Gilbert 	}
7609773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7610c2248fc9SDouglas Gilbert 		goto fini;
7611f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7612c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7613c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7614c2248fc9SDouglas Gilbert 	}
7615f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7616f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7617f66b8517SMartin Wilck 	else
7618f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7619c2248fc9SDouglas Gilbert 
7620c2248fc9SDouglas Gilbert fini:
762167da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7622f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
762375aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
762475aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
762580c49563SDouglas Gilbert 		/*
762675aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
762775aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
762875aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
762975aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
763080c49563SDouglas Gilbert 		 */
763180c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
76324f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
763380c49563SDouglas Gilbert 
76344f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7635f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
763680c49563SDouglas Gilbert 	} else
7637f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
763810bde980SDouglas Gilbert 				     sdebug_ndelay);
7639c2248fc9SDouglas Gilbert check_cond:
7640f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7641f46eb0e9SDouglas Gilbert err_out:
7642f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7643c2248fc9SDouglas Gilbert }
7644c2248fc9SDouglas Gilbert 
76459e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7646c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7647c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
76489e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
76499e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
76509e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
76519e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
76529e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
76539e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
76549e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7655185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7656cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7657c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7658c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
76599e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
76609e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7661cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7662cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
76639e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7664c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
76659e603ca0SFUJITA Tomonori 	.this_id =		7,
766665e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7667cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
76686bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
766950c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
76709e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7671c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
76729e603ca0SFUJITA Tomonori };
76739e603ca0SFUJITA Tomonori 
76741da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
76751da177e4SLinus Torvalds {
76761da177e4SLinus Torvalds 	int error = 0;
76771da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
76781da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7679f46eb0e9SDouglas Gilbert 	int hprot;
76801da177e4SLinus Torvalds 
76811da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
76821da177e4SLinus Torvalds 
7683773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7684fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
76852a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
76864af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
76874af14d11SChristoph Hellwig 
76881da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
76891da177e4SLinus Torvalds 	if (NULL == hpnt) {
7690c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
76911da177e4SLinus Torvalds 		error = -ENODEV;
76921da177e4SLinus Torvalds 		return error;
76931da177e4SLinus Torvalds 	}
7694c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
76959b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7696c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7697c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7698c4837394SDouglas Gilbert 	}
7699c10fa55fSJohn Garry 	/*
7700c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7701f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7702c10fa55fSJohn Garry 	 */
7703c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7704f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7705f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
77061da177e4SLinus Torvalds 
7707c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7708c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7709c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7710c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7711c4b57d89SKashyap Desai 		poll_queues = 0;
7712c4b57d89SKashyap Desai 	}
7713c4b57d89SKashyap Desai 
7714c4b57d89SKashyap Desai 	/*
7715c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7716c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7717c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7718c4b57d89SKashyap Desai 	 */
7719c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7720fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7721c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7722fc09acb7SDouglas Gilbert 		else
7723fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7724fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7725c4b57d89SKashyap Desai 		poll_queues = 1;
7726c4b57d89SKashyap Desai 	}
7727c4b57d89SKashyap Desai 	if (poll_queues)
7728c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7729c4b57d89SKashyap Desai 
77301da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
77311da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7732773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7733773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
77341da177e4SLinus Torvalds 	else
7735773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7736773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7737f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
77381da177e4SLinus Torvalds 
7739f46eb0e9SDouglas Gilbert 	hprot = 0;
7740c6a44287SMartin K. Petersen 
7741773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7742c6a44287SMartin K. Petersen 
77438475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7744f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7745773642d9SDouglas Gilbert 		if (sdebug_dix)
7746f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7747c6a44287SMartin K. Petersen 		break;
7748c6a44287SMartin K. Petersen 
77498475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7750f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7751773642d9SDouglas Gilbert 		if (sdebug_dix)
7752f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7753c6a44287SMartin K. Petersen 		break;
7754c6a44287SMartin K. Petersen 
77558475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7756f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7757773642d9SDouglas Gilbert 		if (sdebug_dix)
7758f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7759c6a44287SMartin K. Petersen 		break;
7760c6a44287SMartin K. Petersen 
7761c6a44287SMartin K. Petersen 	default:
7762773642d9SDouglas Gilbert 		if (sdebug_dix)
7763f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7764c6a44287SMartin K. Petersen 		break;
7765c6a44287SMartin K. Petersen 	}
7766c6a44287SMartin K. Petersen 
7767f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7768c6a44287SMartin K. Petersen 
7769f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7770c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7771f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7772f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7773f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7774f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7775f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7776f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7777f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7778c6a44287SMartin K. Petersen 
7779773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7780c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7781c6a44287SMartin K. Petersen 	else
7782c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7783c6a44287SMartin K. Petersen 
7784773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7785773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7786c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7787c4837394SDouglas Gilbert 		sdebug_statistics = true;
77881da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
77891da177e4SLinus Torvalds 	if (error) {
7790c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
77911da177e4SLinus Torvalds 		error = -ENODEV;
77921da177e4SLinus Torvalds 		scsi_host_put(hpnt);
779387c715dcSDouglas Gilbert 	} else {
77941da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
779587c715dcSDouglas Gilbert 	}
77961da177e4SLinus Torvalds 
77971da177e4SLinus Torvalds 	return error;
77981da177e4SLinus Torvalds }
77991da177e4SLinus Torvalds 
7800fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
78011da177e4SLinus Torvalds {
78021da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
78038b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
78041da177e4SLinus Torvalds 
78051da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
78061da177e4SLinus Torvalds 
78071da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
78081da177e4SLinus Torvalds 
78098b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
78108b40228fSFUJITA Tomonori 				 dev_list) {
78111da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7812f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
78131da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
78141da177e4SLinus Torvalds 	}
78151da177e4SLinus Torvalds 
78161da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
78171da177e4SLinus Torvalds }
78181da177e4SLinus Torvalds 
78198dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
78208dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
78211da177e4SLinus Torvalds {
78228dea0d02SFUJITA Tomonori 	return 1;
78238dea0d02SFUJITA Tomonori }
78241da177e4SLinus Torvalds 
78258dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
78268dea0d02SFUJITA Tomonori 	.name = "pseudo",
78278dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
78288dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
78298dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
783082069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
78318dea0d02SFUJITA Tomonori };
7832