xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision c87bf24c)
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  *
1278d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/genhd.h>
271da177e4SLinus Torvalds #include <linux/fs.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/vmalloc.h>
311da177e4SLinus Torvalds #include <linux/moduleparam.h>
32852e034dSJens Axboe #include <linux/scatterlist.h>
331da177e4SLinus Torvalds #include <linux/blkdev.h>
34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
35cbf67842SDouglas Gilbert #include <linux/spinlock.h>
36cbf67842SDouglas Gilbert #include <linux/interrupt.h>
37cbf67842SDouglas Gilbert #include <linux/atomic.h>
38cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3909ba24c1SDouglas Gilbert #include <linux/uuid.h>
406ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
411442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
420c4bc91dSDouglas Gilbert #include <linux/random.h>
4387c715dcSDouglas Gilbert #include <linux/xarray.h>
44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6348e3bf16SDouglas Gilbert #define SDEBUG_VERSION "0189"	/* format to fit INQUIRY revision field */
6448e3bf16SDouglas Gilbert static const char *sdebug_version_date = "20200421";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
101f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1021da177e4SLinus Torvalds 
1036f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1046f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1056f3cbf55SDouglas Gilbert 
1061da177e4SLinus Torvalds /* Default values for driver parameters */
1071da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1081da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1091da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1111da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1121da177e4SLinus Torvalds  */
1135b94e232SMartin K. Petersen #define DEF_ATO 1
1149b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
115c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1169267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1171da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1189267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1195b94e232SMartin K. Petersen #define DEF_DIF 0
1205b94e232SMartin K. Petersen #define DEF_DIX 0
12187c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1225b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1231da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1245b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1255b94e232SMartin K. Petersen #define DEF_GUARD 0
126cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1275b94e232SMartin K. Petersen #define DEF_LBPU 0
1285b94e232SMartin K. Petersen #define DEF_LBPWS 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS10 0
130be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1315b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
132cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1335b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1341da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1351da177e4SLinus Torvalds #define DEF_OPTS   0
13632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1375b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
139b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1400c4bc91dSDouglas Gilbert #define DEF_RANDOM false
141d986788bSMartin Pitt #define DEF_REMOVABLE false
142760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1435b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1445b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1455b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1466014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1485b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1495b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1505b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
151c2248fc9SDouglas Gilbert #define DEF_STRICT 0
152c4837394SDouglas Gilbert #define DEF_STATISTICS false
153c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
15409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
155c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1561da177e4SLinus Torvalds 
157f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
158f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
159f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
160aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
161f0d1cf93SDouglas Gilbert 
162b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
163b01f6f83SDouglas Gilbert 
164773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
165773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
166773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
167773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
168773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
170773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
171773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
172773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
173773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
174773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
175773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
176773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
177773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
179773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1807ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1817382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
182773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
183773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
185773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
186773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1877ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1887382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1897382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1901da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
191fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1921da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
193773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1946f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
195773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1967382f9d8SDouglas Gilbert  *   - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
1977382f9d8SDouglas Gilbert  *     CMD_ABORT
1981da177e4SLinus Torvalds  *
1997382f9d8SDouglas Gilbert  * When "every_nth" < 0 then after "- every_nth" commands the selected
2007382f9d8SDouglas Gilbert  * error will be injected. The error will be injected on every subsequent
2017382f9d8SDouglas Gilbert  * command until some other action occurs; for example, the user writing
2027382f9d8SDouglas Gilbert  * a new value (other than -1 or 1) to every_nth:
2037382f9d8SDouglas Gilbert  *      echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
2041da177e4SLinus Torvalds  */
2051da177e4SLinus Torvalds 
206cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
207cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
208cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
209cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
210cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
211cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
212cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2130d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
21419c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
215acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
216acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
217acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
218cbf67842SDouglas Gilbert 
219773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2201da177e4SLinus Torvalds  * sector on read commands: */
2211da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
22232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2251da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2261da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2271da177e4SLinus Torvalds 
228c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
229c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
230c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
231c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
232c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
233c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
234c4837394SDouglas Gilbert  */
235c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
236c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
237cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
238cbf67842SDouglas Gilbert 
239b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
240b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
241b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
242fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
243fd32119bSDouglas Gilbert #define F_D_UNKN		8
244b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
245b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
246b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
247b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
248b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
249b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
250b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
251b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
252b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
253b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
254fd32119bSDouglas Gilbert 
255b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
256fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
25746f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
258fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2594f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
260fd32119bSDouglas Gilbert 
261fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
262fd32119bSDouglas Gilbert 
263b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
264fd32119bSDouglas Gilbert 
26587c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
26687c715dcSDouglas Gilbert 
26764e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
26864e14eceSDamien Le Moal enum sdebug_z_type {
26964e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_CNV	= 0x1,
27064e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWR	= 0x2,
27164e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWP	= 0x3,
27264e14eceSDamien Le Moal };
27364e14eceSDamien Le Moal 
274f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
275f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
276f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
277f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
278f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
279f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
280f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
281f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
282f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
283f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
284f0d1cf93SDouglas Gilbert };
285f0d1cf93SDouglas Gilbert 
286f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
28764e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
288f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
28964e14eceSDamien Le Moal 	bool z_non_seq_resource;
290f0d1cf93SDouglas Gilbert 	unsigned int z_size;
291f0d1cf93SDouglas Gilbert 	sector_t z_start;
292f0d1cf93SDouglas Gilbert 	sector_t z_wp;
293f0d1cf93SDouglas Gilbert };
294fd32119bSDouglas Gilbert 
295fd32119bSDouglas Gilbert struct sdebug_dev_info {
296fd32119bSDouglas Gilbert 	struct list_head dev_list;
297fd32119bSDouglas Gilbert 	unsigned int channel;
298fd32119bSDouglas Gilbert 	unsigned int target;
299fd32119bSDouglas Gilbert 	u64 lun;
300bf476433SChristoph Hellwig 	uuid_t lu_name;
301fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
302fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
303fd32119bSDouglas Gilbert 	atomic_t num_in_q;
304c4837394SDouglas Gilbert 	atomic_t stopped;
305fd32119bSDouglas Gilbert 	bool used;
306f0d1cf93SDouglas Gilbert 
307f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
30864e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
309f0d1cf93SDouglas Gilbert 	unsigned int zsize;
310f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
311f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
312aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
313f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
314f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
315f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
316f0d1cf93SDouglas Gilbert 	unsigned int max_open;
317f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
318fd32119bSDouglas Gilbert };
319fd32119bSDouglas Gilbert 
320fd32119bSDouglas Gilbert struct sdebug_host_info {
321fd32119bSDouglas Gilbert 	struct list_head host_list;
32287c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
323fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
324fd32119bSDouglas Gilbert 	struct device dev;
325fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
326fd32119bSDouglas Gilbert };
327fd32119bSDouglas Gilbert 
32887c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
32987c715dcSDouglas Gilbert struct sdeb_store_info {
33087c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
33187c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
33287c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
33387c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
33487c715dcSDouglas Gilbert };
33587c715dcSDouglas Gilbert 
336fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
337fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
338fd32119bSDouglas Gilbert 
33910bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
34010bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
34110bde980SDouglas Gilbert 
342fd32119bSDouglas Gilbert struct sdebug_defer {
343fd32119bSDouglas Gilbert 	struct hrtimer hrt;
344fd32119bSDouglas Gilbert 	struct execute_work ew;
345c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
346c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
347c4837394SDouglas Gilbert 	int issuing_cpu;
34810bde980SDouglas Gilbert 	bool init_hrt;
34910bde980SDouglas Gilbert 	bool init_wq;
3507382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
35110bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
352fd32119bSDouglas Gilbert };
353fd32119bSDouglas Gilbert 
354fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
355c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
356c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
357c4837394SDouglas Gilbert 	 */
358fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
359fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
360c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
361c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
362c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
363c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
364c4837394SDouglas Gilbert 	unsigned int inj_short:1;
3657ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
3667382f9d8SDouglas Gilbert 	unsigned int inj_cmd_abort:1;
367fd32119bSDouglas Gilbert };
368fd32119bSDouglas Gilbert 
369c4837394SDouglas Gilbert struct sdebug_queue {
370c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
371c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
372c4837394SDouglas Gilbert 	spinlock_t qc_lock;
373c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
374fd32119bSDouglas Gilbert };
375fd32119bSDouglas Gilbert 
376c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
377c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
378c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
379c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
380c4837394SDouglas Gilbert 
381fd32119bSDouglas Gilbert struct opcode_info_t {
382b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
383b01f6f83SDouglas Gilbert 				/* for terminating element */
384fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
385fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
386fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
387fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
388fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3899a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3909a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
391fd32119bSDouglas Gilbert };
392fd32119bSDouglas Gilbert 
393fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
394c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
395c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
396c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
397c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
398c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
399c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
400c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
401c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
402c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
403c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
404c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
405c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
406c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
40746f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
40846f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
409c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
410c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
411c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
412481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
413c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
414c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
415c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
416c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
417c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
418c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
419c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
420c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
421c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
422c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
423c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
424ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
425f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
426f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
427f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
428c2248fc9SDouglas Gilbert };
429c2248fc9SDouglas Gilbert 
430c4837394SDouglas Gilbert 
431c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
432c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
433c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
434c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
435c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
436c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
437c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
438c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
439c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
440c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
441c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
442c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
443ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
444c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
445c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
446c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
447c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
448c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
449c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
450c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
451fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
452c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
455c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
456c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
457c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
458c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
459f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
460f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
46146f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
462c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
463c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
464c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
46546f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
46646f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
467c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
468c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
469c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
470c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
471c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
472c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
473c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
474c2248fc9SDouglas Gilbert };
475c2248fc9SDouglas Gilbert 
47680c49563SDouglas Gilbert /*
47780c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
47880c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
47980c49563SDouglas Gilbert  * command completion, they can mask their return value with
48080c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
48180c49563SDouglas Gilbert  */
48280c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
48380c49563SDouglas Gilbert 
484c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
488c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
489c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
490c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
491c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
492c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
493481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
494c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
495c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
496c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
497c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
498c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
49938d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
50038d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
501c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
502c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
503c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
50438d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
505acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
50680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
507ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
508f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
509f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
510f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
511f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
512f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
513c2248fc9SDouglas Gilbert 
51487c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
51587c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
51687c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
51787c715dcSDouglas Gilbert static int sdebug_add_store(void);
51887c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
51987c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
52087c715dcSDouglas Gilbert 
52146f64e70SDouglas Gilbert /*
52246f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
52346f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
52446f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
52546f64e70SDouglas Gilbert  */
52646f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
527c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
528c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
529c2248fc9SDouglas Gilbert };
530c2248fc9SDouglas Gilbert 
53146f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
532c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
533c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
534c2248fc9SDouglas Gilbert };
535c2248fc9SDouglas Gilbert 
53646f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
53746f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
538b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
539c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
54046f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
541c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
54246f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
543b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
544c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
545c2248fc9SDouglas Gilbert };
546c2248fc9SDouglas Gilbert 
54746f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
54846f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
54946f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
55046f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
55146f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
55246f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
55346f64e70SDouglas Gilbert 		   0, 0, 0} },
55446f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
55546f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55646f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
557c2248fc9SDouglas Gilbert };
558c2248fc9SDouglas Gilbert 
559c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
560c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
561c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
562c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
563c3e2fe92SDouglas Gilbert };
564c3e2fe92SDouglas Gilbert 
56546f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
566c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
567c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56846f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
569c2248fc9SDouglas Gilbert };
570c2248fc9SDouglas Gilbert 
57146f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
57246f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
573b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
574c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
575481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
576481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
577481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
578c2248fc9SDouglas Gilbert };
579c2248fc9SDouglas Gilbert 
58046f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
58138d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
582c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
58346f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
58438d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
585c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
58646f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
587c2248fc9SDouglas Gilbert };
588c2248fc9SDouglas Gilbert 
58946f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
59046f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
591c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59246f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
593c2248fc9SDouglas Gilbert };
594c2248fc9SDouglas Gilbert 
59546f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
596c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
597c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
598c2248fc9SDouglas Gilbert };
599c2248fc9SDouglas Gilbert 
60046f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
601c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
602c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
603c2248fc9SDouglas Gilbert };
604c2248fc9SDouglas Gilbert 
60580c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
6064f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
60780c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60880c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
60980c49563SDouglas Gilbert };
61080c49563SDouglas Gilbert 
611ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
612b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
613ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
614ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
615ed9f3e25SDouglas Gilbert };
616ed9f3e25SDouglas Gilbert 
617f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
618b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
619f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
620f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
621b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
622f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
623f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
624b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
625f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
626f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
627f0d1cf93SDouglas Gilbert };
628f0d1cf93SDouglas Gilbert 
629f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
630b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
631f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
632f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
633f0d1cf93SDouglas Gilbert };
634f0d1cf93SDouglas Gilbert 
635c2248fc9SDouglas Gilbert 
636c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
637c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
638c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
639ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
640c2248fc9SDouglas Gilbert /* 0 */
64146f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
642c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64346f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
644c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
645c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
646c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
64746f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
648c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
649c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
650c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
651c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65246f64e70SDouglas Gilbert /* 5 */
65346f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
65446f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
65546f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65646f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
65746f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
65846f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65946f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
660c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
661c2248fc9SDouglas Gilbert 	     0, 0, 0} },
66246f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
663c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
664c2248fc9SDouglas Gilbert 	     0, 0} },
66546f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
66646f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
66746f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
668c2248fc9SDouglas Gilbert /* 10 */
66946f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
67046f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
67146f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67280c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6734f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
674c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
67546f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
67646f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
67746f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67846f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
679481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
680481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
681481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
68246f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
68346f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
68446f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
68546f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
68646f64e70SDouglas Gilbert /* 15 */
687c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
688c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
689c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
690c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
691c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
692c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
69346f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
69446f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
69546f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
69646f64e70SDouglas Gilbert 	     0xff, 0xff} },
69746f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
69846f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
699c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
700c2248fc9SDouglas Gilbert 	     0} },
70146f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
70246f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
703c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
704c2248fc9SDouglas Gilbert 	     0} },
705c2248fc9SDouglas Gilbert /* 20 */
706f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
707f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
708c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
709c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
710c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
711c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
712c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
713c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
71446f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
715b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
71646f64e70SDouglas Gilbert /* 25 */
717acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
718acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
719acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
72046f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
72146f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
72246f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
72346f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7244f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
72580c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
726b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
72780c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
72846f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
729c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
730b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
731b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
732ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
733ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
734ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
735c2248fc9SDouglas Gilbert 
736ed9f3e25SDouglas Gilbert /* 30 */
737b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
738f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
739f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
740f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
741b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
742f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
743f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
744f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
745f0d1cf93SDouglas Gilbert /* sentinel */
746c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
747c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
748c2248fc9SDouglas Gilbert };
749c2248fc9SDouglas Gilbert 
75087c715dcSDouglas Gilbert static int sdebug_num_hosts;
75187c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
752773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7539b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
754c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7559267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
756773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
757773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
758773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
759773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
760773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
761773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
762773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
763773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
764c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
765d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
766d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
767cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
768c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
769773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
770773642d9SDouglas Gilbert static int sdebug_no_uld;
771773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
772773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
773773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
774773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
775773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
77686e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
777b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
778773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
779773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
780773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
781773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
782773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
783773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
784773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
785773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
786773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
787773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
788773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
789773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
790773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
79109ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7920c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
79387c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
794773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
795773642d9SDouglas Gilbert static bool sdebug_clustering;
796773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
797773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
798817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
799773642d9SDouglas Gilbert static bool sdebug_verbose;
800f46eb0e9SDouglas Gilbert static bool have_dif_prot;
8014f2c8bf6SDouglas Gilbert static bool write_since_sync;
802c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
8039447b6ceSMartin K. Petersen static bool sdebug_wp;
8049267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
8059267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
8069267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
8071da177e4SLinus Torvalds 
808c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8091da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8121da177e4SLinus Torvalds    may still need them */
8131da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8141da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8151da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8181da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8191da177e4SLinus Torvalds 
82087c715dcSDouglas Gilbert static struct xarray per_store_arr;
82187c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
82287c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
82387c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
82487c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8251da177e4SLinus Torvalds 
82644d92694SMartin K. Petersen static unsigned long map_size;
827cbf67842SDouglas Gilbert static int num_aborts;
828cbf67842SDouglas Gilbert static int num_dev_resets;
829cbf67842SDouglas Gilbert static int num_target_resets;
830cbf67842SDouglas Gilbert static int num_bus_resets;
831cbf67842SDouglas Gilbert static int num_host_resets;
832c6a44287SMartin K. Petersen static int dix_writes;
833c6a44287SMartin K. Petersen static int dix_reads;
834c6a44287SMartin K. Petersen static int dif_errors;
8351da177e4SLinus Torvalds 
836f0d1cf93SDouglas Gilbert /* ZBC global data */
83764e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
83898e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
839380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
840aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
841f0d1cf93SDouglas Gilbert 
842c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
843c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
844fd32119bSDouglas Gilbert 
8451da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
84687c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84787c715dcSDouglas Gilbert 
84887c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8491da177e4SLinus Torvalds 
850cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
851cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8561da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8571da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8581da177e4SLinus Torvalds };
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds static const int check_condition_result =
8611da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8621da177e4SLinus Torvalds 
863c6a44287SMartin K. Petersen static const int illegal_condition_result =
864c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
865c6a44287SMartin K. Petersen 
866cbf67842SDouglas Gilbert static const int device_qfull_result =
867cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
868cbf67842SDouglas Gilbert 
869ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
870ed9f3e25SDouglas Gilbert 
871fd32119bSDouglas Gilbert 
872760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
873760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
874760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
875760f3b03SDouglas Gilbert  */
876760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
877fd32119bSDouglas Gilbert {
878fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
879fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
880fd32119bSDouglas Gilbert }
881c65b1445SDouglas Gilbert 
88287c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
88387c715dcSDouglas Gilbert 			    unsigned long long lba)
88414faa944SAkinobu Mita {
88587c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
88614faa944SAkinobu Mita 
88787c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88887c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88987c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
89087c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
89187c715dcSDouglas Gilbert 	}
89287c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
89314faa944SAkinobu Mita }
89414faa944SAkinobu Mita 
89587c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
89687c715dcSDouglas Gilbert 				      sector_t sector)
89714faa944SAkinobu Mita {
89849413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89914faa944SAkinobu Mita 
90087c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
90114faa944SAkinobu Mita }
90214faa944SAkinobu Mita 
9038dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9048dea0d02SFUJITA Tomonori {
9058dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9068dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9078dea0d02SFUJITA Tomonori 
9088dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9098dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9108dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9118dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
912773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
913773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9148dea0d02SFUJITA Tomonori 		else
915773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
916773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
917f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9188dea0d02SFUJITA Tomonori 	}
9198dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9208dea0d02SFUJITA Tomonori }
9218dea0d02SFUJITA Tomonori 
92222017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
92322017ed2SDouglas Gilbert 
92422017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
925fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
926fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92722017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92822017ed2SDouglas Gilbert {
92922017ed2SDouglas Gilbert 	unsigned char *sbuff;
93022017ed2SDouglas Gilbert 	u8 sks[4];
93122017ed2SDouglas Gilbert 	int sl, asc;
93222017ed2SDouglas Gilbert 
93322017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
93422017ed2SDouglas Gilbert 	if (!sbuff) {
93522017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
93622017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93722017ed2SDouglas Gilbert 		return;
93822017ed2SDouglas Gilbert 	}
93922017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
94022017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
941773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
94222017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
94322017ed2SDouglas Gilbert 	sks[0] = 0x80;
94422017ed2SDouglas Gilbert 	if (c_d)
94522017ed2SDouglas Gilbert 		sks[0] |= 0x40;
94622017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94722017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94822017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94922017ed2SDouglas Gilbert 	}
95022017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
951773642d9SDouglas Gilbert 	if (sdebug_dsense) {
95222017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
95322017ed2SDouglas Gilbert 		sbuff[7] = sl;
95422017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
95522017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
95622017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95722017ed2SDouglas Gilbert 	} else
95822017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
959773642d9SDouglas Gilbert 	if (sdebug_verbose)
96022017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
96122017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
96222017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
96322017ed2SDouglas Gilbert }
96422017ed2SDouglas Gilbert 
965cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9668dea0d02SFUJITA Tomonori {
9678dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
9688dea0d02SFUJITA Tomonori 
969cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
970cbf67842SDouglas Gilbert 	if (!sbuff) {
971cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
972cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
973cbf67842SDouglas Gilbert 		return;
974cbf67842SDouglas Gilbert 	}
975cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9768dea0d02SFUJITA Tomonori 
977773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9788dea0d02SFUJITA Tomonori 
979773642d9SDouglas Gilbert 	if (sdebug_verbose)
980cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
981cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
982cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9838dea0d02SFUJITA Tomonori }
9841da177e4SLinus Torvalds 
985fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
98622017ed2SDouglas Gilbert {
98722017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98822017ed2SDouglas Gilbert }
98922017ed2SDouglas Gilbert 
9906f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9916f4e626fSNathan Chancellor 			    void __user *arg)
9921da177e4SLinus Torvalds {
993773642d9SDouglas Gilbert 	if (sdebug_verbose) {
994cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
995cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
996cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
997cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
998cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
999cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
1000cbf67842SDouglas Gilbert 				    __func__);
1001cbf67842SDouglas Gilbert 		else
1002cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
1003cbf67842SDouglas Gilbert 				    __func__, cmd);
10041da177e4SLinus Torvalds 	}
10051da177e4SLinus Torvalds 	return -EINVAL;
10061da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10071da177e4SLinus Torvalds }
10081da177e4SLinus Torvalds 
10099b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10109b760fd8SDouglas Gilbert {
10119b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10129b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10149b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10159b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10169b760fd8SDouglas Gilbert 		break;
10179b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10199b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10209b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10219b760fd8SDouglas Gilbert 		break;
10229b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10239b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10249b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10259b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10269b760fd8SDouglas Gilbert 		break;
10279b760fd8SDouglas Gilbert 	case 16:
10289b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10299b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10309b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10319b760fd8SDouglas Gilbert 		break;
10329b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10339b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10349b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10359b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10369b760fd8SDouglas Gilbert 		break;
10379b760fd8SDouglas Gilbert 	default:
10389b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10399b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10409b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10419b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10429b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10439b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10449b760fd8SDouglas Gilbert 		break;
10459b760fd8SDouglas Gilbert 	}
10469b760fd8SDouglas Gilbert }
10479b760fd8SDouglas Gilbert 
10489b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10499b760fd8SDouglas Gilbert {
10509b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10519b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10529b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10539b760fd8SDouglas Gilbert 
10549b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10559b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10569b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10579b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10589b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10599b760fd8SDouglas Gilbert 		}
10609b760fd8SDouglas Gilbert 	}
10619b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10629b760fd8SDouglas Gilbert }
10639b760fd8SDouglas Gilbert 
106419c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
106519c8ead7SEwan D. Milne {
106619c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106719c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106819c8ead7SEwan D. Milne 
106919c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
107019c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
107119c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
107219c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
107319c8ead7SEwan D. Milne 			    (devip->target == dp->target))
107419c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
107519c8ead7SEwan D. Milne 		}
107619c8ead7SEwan D. Milne 	}
107719c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107819c8ead7SEwan D. Milne }
107919c8ead7SEwan D. Milne 
1080f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10811da177e4SLinus Torvalds {
1082cbf67842SDouglas Gilbert 	int k;
1083cbf67842SDouglas Gilbert 
1084cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1085cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1086cbf67842SDouglas Gilbert 		const char *cp = NULL;
1087cbf67842SDouglas Gilbert 
1088cbf67842SDouglas Gilbert 		switch (k) {
1089cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1090f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1091f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1092773642d9SDouglas Gilbert 			if (sdebug_verbose)
1093cbf67842SDouglas Gilbert 				cp = "power on reset";
1094cbf67842SDouglas Gilbert 			break;
1095cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1096f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1097f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1098773642d9SDouglas Gilbert 			if (sdebug_verbose)
1099cbf67842SDouglas Gilbert 				cp = "bus reset";
1100cbf67842SDouglas Gilbert 			break;
1101cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1102f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1103f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1104773642d9SDouglas Gilbert 			if (sdebug_verbose)
1105cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1106cbf67842SDouglas Gilbert 			break;
11070d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1108f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1109f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1110773642d9SDouglas Gilbert 			if (sdebug_verbose)
11110d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1112f49accf1SEwan D. Milne 			break;
1113acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1114f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1115b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1116b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1117773642d9SDouglas Gilbert 			if (sdebug_verbose)
1118acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1119acafd0b9SEwan D. Milne 			break;
1120acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1121f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1122acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1123acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1124773642d9SDouglas Gilbert 			if (sdebug_verbose)
1125acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1126acafd0b9SEwan D. Milne 			break;
112719c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
112819c8ead7SEwan D. Milne 			/*
112919c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
113019c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
113119c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
113219c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1133773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
113419c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
113519c8ead7SEwan D. Milne 			 */
1136773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
113719c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1138f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
113919c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
114019c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1141773642d9SDouglas Gilbert 			if (sdebug_verbose)
114219c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
114319c8ead7SEwan D. Milne 			break;
1144cbf67842SDouglas Gilbert 		default:
1145773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1146773642d9SDouglas Gilbert 			if (sdebug_verbose)
1147cbf67842SDouglas Gilbert 				cp = "unknown";
1148cbf67842SDouglas Gilbert 			break;
1149cbf67842SDouglas Gilbert 		}
1150cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1151773642d9SDouglas Gilbert 		if (sdebug_verbose)
1152f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1153cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1154cbf67842SDouglas Gilbert 				   my_name, cp);
11551da177e4SLinus Torvalds 		return check_condition_result;
11561da177e4SLinus Torvalds 	}
11571da177e4SLinus Torvalds 	return 0;
11581da177e4SLinus Torvalds }
11591da177e4SLinus Torvalds 
1160fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11611da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11621da177e4SLinus Torvalds 				int arr_len)
11631da177e4SLinus Torvalds {
116421a61829SFUJITA Tomonori 	int act_len;
1165ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11661da177e4SLinus Torvalds 
1167072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11681da177e4SLinus Torvalds 		return 0;
1169ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1170773642d9SDouglas Gilbert 		return DID_ERROR << 16;
117121a61829SFUJITA Tomonori 
117221a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
117321a61829SFUJITA Tomonori 				      arr, arr_len);
117442d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
117521a61829SFUJITA Tomonori 
11761da177e4SLinus Torvalds 	return 0;
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds 
1179fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1180fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1181fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1182fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1183fb0cc8d1SDouglas Gilbert  */
1184fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1185fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1186fb0cc8d1SDouglas Gilbert {
11879237f04eSDamien Le Moal 	unsigned int act_len, n;
1188ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1189fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1190fb0cc8d1SDouglas Gilbert 
1191fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1192fb0cc8d1SDouglas Gilbert 		return 0;
1193ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1194fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1195fb0cc8d1SDouglas Gilbert 
1196fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1197fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1198fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
119942d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
120042d387beSBart Van Assche 		 scsi_get_resid(scp));
12019237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
120287c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1203fb0cc8d1SDouglas Gilbert 	return 0;
1204fb0cc8d1SDouglas Gilbert }
1205fb0cc8d1SDouglas Gilbert 
1206fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1207fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1208fb0cc8d1SDouglas Gilbert  */
12091da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
121021a61829SFUJITA Tomonori 			       int arr_len)
12111da177e4SLinus Torvalds {
121221a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12131da177e4SLinus Torvalds 		return 0;
1214ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12151da177e4SLinus Torvalds 		return -1;
121621a61829SFUJITA Tomonori 
121721a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12181da177e4SLinus Torvalds }
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 
1221e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1222e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12239b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12241b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12251b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12261b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12271b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12281da177e4SLinus Torvalds 
1229cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1230760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12315a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
123209ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1233bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12341da177e4SLinus Torvalds {
1235c65b1445SDouglas Gilbert 	int num, port_a;
1236c65b1445SDouglas Gilbert 	char b[32];
12371da177e4SLinus Torvalds 
1238c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12391da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12401da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12411da177e4SLinus Torvalds 	arr[1] = 0x1;
12421da177e4SLinus Torvalds 	arr[2] = 0x0;
1243e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1244e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12451da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12461da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12471da177e4SLinus Torvalds 	arr[3] = num;
12481da177e4SLinus Torvalds 	num += 4;
1249c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
125009ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
125109ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
125209ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
125309ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
125409ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125509ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
125609ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
125709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125809ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
125909ba24c1SDouglas Gilbert 			num += 16;
126009ba24c1SDouglas Gilbert 		} else {
12611b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1262c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1263c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1264c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1265c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12661b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1267773642d9SDouglas Gilbert 			num += 8;
126809ba24c1SDouglas Gilbert 		}
1269c65b1445SDouglas Gilbert 		/* Target relative port number */
1270c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1271c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1272c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1273c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1274c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1275c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1276c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1277c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1278c65b1445SDouglas Gilbert 	}
12791b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1280c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1281c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1282c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1283c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12841b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1285773642d9SDouglas Gilbert 	num += 8;
12861b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12875a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12885a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12895a09e398SHannes Reinecke 	arr[num++] = 0x0;
12905a09e398SHannes Reinecke 	arr[num++] = 0x4;
12915a09e398SHannes Reinecke 	arr[num++] = 0;
12925a09e398SHannes Reinecke 	arr[num++] = 0;
1293773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1294773642d9SDouglas Gilbert 	num += 2;
12951b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1296c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1297c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1298c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1299c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
13001b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1301773642d9SDouglas Gilbert 	num += 8;
1302c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1303c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1304c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1305c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1306c65b1445SDouglas Gilbert 	arr[num++] = 24;
13071b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1308c65b1445SDouglas Gilbert 	num += 12;
1309c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1310c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1311c65b1445SDouglas Gilbert 	num += 8;
1312c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1313c65b1445SDouglas Gilbert 	num += 4;
1314c65b1445SDouglas Gilbert 	return num;
1315c65b1445SDouglas Gilbert }
1316c65b1445SDouglas Gilbert 
1317c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1318c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1319c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1320c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1321c65b1445SDouglas Gilbert };
1322c65b1445SDouglas Gilbert 
1323cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1324760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1325c65b1445SDouglas Gilbert {
1326c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1327c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1328c65b1445SDouglas Gilbert }
1329c65b1445SDouglas Gilbert 
1330cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1331760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1332c65b1445SDouglas Gilbert {
1333c65b1445SDouglas Gilbert 	int num = 0;
1334c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1335c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1336c65b1445SDouglas Gilbert 	int plen, olen;
1337c65b1445SDouglas Gilbert 
1338c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1339c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1340c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1341c65b1445SDouglas Gilbert 	olen = strlen(na1);
1342c65b1445SDouglas Gilbert 	plen = olen + 1;
1343c65b1445SDouglas Gilbert 	if (plen % 4)
1344c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1345c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1346c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1347c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1348c65b1445SDouglas Gilbert 	num += plen;
1349c65b1445SDouglas Gilbert 
1350c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1351c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1352c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1353c65b1445SDouglas Gilbert 	olen = strlen(na2);
1354c65b1445SDouglas Gilbert 	plen = olen + 1;
1355c65b1445SDouglas Gilbert 	if (plen % 4)
1356c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1357c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1358c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1359c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1360c65b1445SDouglas Gilbert 	num += plen;
1361c65b1445SDouglas Gilbert 
1362c65b1445SDouglas Gilbert 	return num;
1363c65b1445SDouglas Gilbert }
1364c65b1445SDouglas Gilbert 
1365c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1366760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1367c65b1445SDouglas Gilbert {
1368c65b1445SDouglas Gilbert 	int num = 0;
1369c65b1445SDouglas Gilbert 	int port_a, port_b;
1370c65b1445SDouglas Gilbert 
1371c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1372c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1374c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1375c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1376c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1377c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1378c65b1445SDouglas Gilbert 	num += 6;
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1380c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1381c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1385c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13861b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1387773642d9SDouglas Gilbert 	num += 8;
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1389c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1390c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1392c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1393c65b1445SDouglas Gilbert 	num += 6;
1394c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1395c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1396c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1397c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1398c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1399c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1400c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
14011b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1402773642d9SDouglas Gilbert 	num += 8;
1403c65b1445SDouglas Gilbert 
1404c65b1445SDouglas Gilbert 	return num;
1405c65b1445SDouglas Gilbert }
1406c65b1445SDouglas Gilbert 
1407c65b1445SDouglas Gilbert 
1408c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1409c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1410c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1411c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1412c65b1445SDouglas Gilbert '1','2','3','4',
1413c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1414c65b1445SDouglas Gilbert 0xec,0,0,0,
1415c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1416c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1417c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1418c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1419c65b1445SDouglas Gilbert 0x53,0x41,
1420c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1421c65b1445SDouglas Gilbert 0x20,0x20,
1422c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1423c65b1445SDouglas Gilbert 0x10,0x80,
1424c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1425c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1426c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1428c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1429c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1430c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1435c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1436c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1437c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1444c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1445c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1446c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1448c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1449c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1450c65b1445SDouglas Gilbert };
1451c65b1445SDouglas Gilbert 
1452cbf67842SDouglas Gilbert /* ATA Information VPD page */
1453760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1454c65b1445SDouglas Gilbert {
1455c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1456c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1457c65b1445SDouglas Gilbert }
1458c65b1445SDouglas Gilbert 
1459c65b1445SDouglas Gilbert 
1460c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14611e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14621e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14631e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14641e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1465c65b1445SDouglas Gilbert };
1466c65b1445SDouglas Gilbert 
1467cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1468760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1469c65b1445SDouglas Gilbert {
1470ea61fca5SMartin K. Petersen 	unsigned int gran;
1471ea61fca5SMartin K. Petersen 
1472c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1473e308b3d1SMartin K. Petersen 
1474e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
147586e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
147686e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
147786e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
147886e6828aSLukas Herbolt 	else
1479773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1480773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1481e308b3d1SMartin K. Petersen 
1482e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1483773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1484773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
148544d92694SMartin K. Petersen 
1486e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1487773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1488e308b3d1SMartin K. Petersen 
1489773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1490e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1491773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1492e308b3d1SMartin K. Petersen 
1493e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1494773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
149544d92694SMartin K. Petersen 	}
149644d92694SMartin K. Petersen 
1497e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1498773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1499773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
150044d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
150144d92694SMartin K. Petersen 	}
150244d92694SMartin K. Petersen 
1503e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1504773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
15056014759cSMartin K. Petersen 
15065b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1507773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15085b94e232SMartin K. Petersen 
15095b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
151044d92694SMartin K. Petersen 
1511c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15121da177e4SLinus Torvalds }
15131da177e4SLinus Torvalds 
15141e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
151564e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1516eac6e8e4SMatthew Wilcox {
1517eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1518eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15191e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15201e49f785SDouglas Gilbert 	arr[2] = 0;
15211e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
152264e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
152364e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1524eac6e8e4SMatthew Wilcox 
1525eac6e8e4SMatthew Wilcox 	return 0x3c;
1526eac6e8e4SMatthew Wilcox }
15271da177e4SLinus Torvalds 
1528760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1529760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15306014759cSMartin K. Petersen {
15313f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15326014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1533773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15346014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1535773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15366014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1537773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15385b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1539760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1540760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1541760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1542760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1543760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15443f0bc3b3SMartin K. Petersen 	return 0x4;
15456014759cSMartin K. Petersen }
15466014759cSMartin K. Petersen 
1547d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1548f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1549d36da305SDouglas Gilbert {
1550d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1551d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1552d36da305SDouglas Gilbert 	/*
1553d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1554d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1555f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1556f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1557d36da305SDouglas Gilbert 	 */
1558d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1559d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
156064e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1561f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1562f0d1cf93SDouglas Gilbert 	else
1563d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1564d36da305SDouglas Gilbert 	return 0x3c;
1565d36da305SDouglas Gilbert }
1566d36da305SDouglas Gilbert 
15671da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1568c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15691da177e4SLinus Torvalds 
1570c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15711da177e4SLinus Torvalds {
15721da177e4SLinus Torvalds 	unsigned char pq_pdt;
15735a09e398SHannes Reinecke 	unsigned char *arr;
157401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15755a09e398SHannes Reinecke 	int alloc_len, n, ret;
1576d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15771da177e4SLinus Torvalds 
1578773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15796f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15806f3cbf55SDouglas Gilbert 	if (! arr)
15816f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1582760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
158364e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1584d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1585b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1586c2248fc9SDouglas Gilbert 	if (have_wlun)
1587b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1588b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1589b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1590c65b1445SDouglas Gilbert 	else
1591773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15921da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15931da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
159422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15955a09e398SHannes Reinecke 		kfree(arr);
15961da177e4SLinus Torvalds 		return check_condition_result;
15971da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15985a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1599c65b1445SDouglas Gilbert 		char lu_id_str[6];
1600c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
16011da177e4SLinus Torvalds 
16025a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16035a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1604b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
160523183910SDouglas Gilbert 			host_no = 0;
1606c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1607c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1608c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1609c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1610c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16111da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1612c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1613c65b1445SDouglas Gilbert 			n = 4;
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1615c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1616c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1617c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1618c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1619c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1620c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1621c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1622d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1623c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1624760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1625760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1626d36da305SDouglas Gilbert 				if (is_disk)
1627d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
162864e14eceSDamien Le Moal 				if (is_zbc)
1629d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1630760f3b03SDouglas Gilbert 			}
1631c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16321da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1633c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16341da177e4SLinus Torvalds 			arr[3] = len;
1635c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16361da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1637c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1638760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16395a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
164009ba24c1SDouglas Gilbert 						lu_id_str, len,
164109ba24c1SDouglas Gilbert 						&devip->lu_name);
1642c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1643c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1644760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1645c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1646c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1647760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1648c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1649c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1650c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16518475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1652c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1653760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1654c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1655c6a44287SMartin K. Petersen 			else
1656c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1657c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1658c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1659c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1660c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1661c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1662c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1663c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1664c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1665c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1666c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1667760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1668d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1669c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1670760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1671773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1672d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1673c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1674760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1675d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1676eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
167764e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1678760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16796014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1680760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1681d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1682d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1683f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16841da177e4SLinus Torvalds 		} else {
168522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16865a09e398SHannes Reinecke 			kfree(arr);
16871da177e4SLinus Torvalds 			return check_condition_result;
16881da177e4SLinus Torvalds 		}
1689773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
16905a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1691c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
16925a09e398SHannes Reinecke 		kfree(arr);
16935a09e398SHannes Reinecke 		return ret;
16941da177e4SLinus Torvalds 	}
16951da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1696773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1697773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16981da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16991da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1700f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1701b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
170270bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1703c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17041da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1705c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1706e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1707e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1708e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17099b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17109b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17111da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1712760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1713760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1714c65b1445SDouglas Gilbert 	n = 62;
1715760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1716760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1717760f3b03SDouglas Gilbert 		n += 2;
1718760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1719760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1720760f3b03SDouglas Gilbert 		n += 2;
1721d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1722d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1723d36da305SDouglas Gilbert 		n += 2;
17241da177e4SLinus Torvalds 	}
1725760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17265a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
172787c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
17285a09e398SHannes Reinecke 	kfree(arr);
17295a09e398SHannes Reinecke 	return ret;
17301da177e4SLinus Torvalds }
17311da177e4SLinus Torvalds 
1732fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1733fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1734fd32119bSDouglas Gilbert 
17351da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17361da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17371da177e4SLinus Torvalds {
17381da177e4SLinus Torvalds 	unsigned char *sbuff;
173901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1740cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
17412492fc09STomas Winkler 	bool dsense;
17421da177e4SLinus Torvalds 	int len = 18;
17431da177e4SLinus Torvalds 
1744c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1745c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1746cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1747c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1748c2248fc9SDouglas Gilbert 		if (dsense) {
1749c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1750c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1751c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1752c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1753c2248fc9SDouglas Gilbert 			len = 8;
1754c65b1445SDouglas Gilbert 		} else {
1755c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1756c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1757c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1758c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1759c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1760c65b1445SDouglas Gilbert 		}
1761c65b1445SDouglas Gilbert 	} else {
1762cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1763773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1764c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1765c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1766c2248fc9SDouglas Gilbert 			if (dsense) {
1767c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1768c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1769c2248fc9SDouglas Gilbert 				len = 8;
1770c2248fc9SDouglas Gilbert 			} else {
1771c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1772c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1773c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1774c2248fc9SDouglas Gilbert 			}
1775c2248fc9SDouglas Gilbert 		} else if (dsense) {
1776c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
17771da177e4SLinus Torvalds 			arr[0] = 0x72;
17781da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
17791da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
17801da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
17811da177e4SLinus Torvalds 			len = 8;
1782c2248fc9SDouglas Gilbert 		} else {
1783c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1784c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1785c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1786c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1787c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1788c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1789c65b1445SDouglas Gilbert 		}
1790c2248fc9SDouglas Gilbert 
1791c65b1445SDouglas Gilbert 	}
1792cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
17931da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
17941da177e4SLinus Torvalds }
17951da177e4SLinus Torvalds 
1796c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1797c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1798c65b1445SDouglas Gilbert {
179901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1800c4837394SDouglas Gilbert 	int power_cond, stop;
18014f2c8bf6SDouglas Gilbert 	bool changing;
1802c65b1445SDouglas Gilbert 
1803c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1804c65b1445SDouglas Gilbert 	if (power_cond) {
180522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1806c65b1445SDouglas Gilbert 		return check_condition_result;
1807c65b1445SDouglas Gilbert 	}
1808c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
18094f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1810c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
18114f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
18124f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18134f2c8bf6SDouglas Gilbert 	else
18144f2c8bf6SDouglas Gilbert 		return 0;
1815c65b1445SDouglas Gilbert }
1816c65b1445SDouglas Gilbert 
181728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
181828898873SFUJITA Tomonori {
1819773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1820773642d9SDouglas Gilbert 
1821773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1822773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1823773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
182428898873SFUJITA Tomonori 	else
182528898873SFUJITA Tomonori 		return sdebug_store_sectors;
182628898873SFUJITA Tomonori }
182728898873SFUJITA Tomonori 
18281da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18291da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18301da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18311da177e4SLinus Torvalds {
18321da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1833c65b1445SDouglas Gilbert 	unsigned int capac;
18341da177e4SLinus Torvalds 
1835c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
183628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18371da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1838c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1839c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1840773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1841773642d9SDouglas Gilbert 	} else
1842773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1843773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18441da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18451da177e4SLinus Torvalds }
18461da177e4SLinus Torvalds 
1847c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1848c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1849c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1850c65b1445SDouglas Gilbert {
185101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1852c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1853773642d9SDouglas Gilbert 	int alloc_len;
1854c65b1445SDouglas Gilbert 
1855773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1856c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
185728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1858c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1859773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1860773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1861773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1862773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
186344d92694SMartin K. Petersen 
1864be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18655b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1866760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1867760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1868760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1869760f3b03SDouglas Gilbert 		 */
1870760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1871760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1872be1dd78dSEric Sandeen 	}
187344d92694SMartin K. Petersen 
1874773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1875c6a44287SMartin K. Petersen 
1876760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1877773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1878c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1879c6a44287SMartin K. Petersen 	}
1880c6a44287SMartin K. Petersen 
1881c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
188287c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1883c65b1445SDouglas Gilbert }
1884c65b1445SDouglas Gilbert 
18855a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18865a09e398SHannes Reinecke 
18875a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18885a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18895a09e398SHannes Reinecke {
189001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
18915a09e398SHannes Reinecke 	unsigned char *arr;
18925a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
18935a09e398SHannes Reinecke 	int n, ret, alen, rlen;
18945a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
18955a09e398SHannes Reinecke 
1896773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
18976f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
18986f3cbf55SDouglas Gilbert 	if (! arr)
18996f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19005a09e398SHannes Reinecke 	/*
19015a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19025a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19035a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19045a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19055a09e398SHannes Reinecke 	 */
19065a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19075a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19085a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19095a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19105a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19115a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19125a09e398SHannes Reinecke 
19135a09e398SHannes Reinecke 	/*
19145a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19155a09e398SHannes Reinecke 	 */
19165a09e398SHannes Reinecke 	n = 4;
1917b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19185a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19195a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19205a09e398SHannes Reinecke 	} else {
19215a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1922773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19235a09e398SHannes Reinecke 	}
1924773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1925773642d9SDouglas Gilbert 	n += 2;
19265a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19275a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19285a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19295a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19305a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19315a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1932773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1933773642d9SDouglas Gilbert 	n += 2;
19345a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19355a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1936773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1937773642d9SDouglas Gilbert 	n += 2;
19385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19415a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1944773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1945773642d9SDouglas Gilbert 	n += 2;
19465a09e398SHannes Reinecke 
19475a09e398SHannes Reinecke 	rlen = n - 4;
1948773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19495a09e398SHannes Reinecke 
19505a09e398SHannes Reinecke 	/*
19515a09e398SHannes Reinecke 	 * Return the smallest value of either
19525a09e398SHannes Reinecke 	 * - The allocated length
19535a09e398SHannes Reinecke 	 * - The constructed command length
19545a09e398SHannes Reinecke 	 * - The maximum array size
19555a09e398SHannes Reinecke 	 */
195687c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
19575a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
195887c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19595a09e398SHannes Reinecke 	kfree(arr);
19605a09e398SHannes Reinecke 	return ret;
19615a09e398SHannes Reinecke }
19625a09e398SHannes Reinecke 
1963fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1964fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
196538d5c833SDouglas Gilbert {
196638d5c833SDouglas Gilbert 	bool rctd;
196738d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
196838d5c833SDouglas Gilbert 	u16 req_sa, u;
196938d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
197038d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
197138d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
197238d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
197338d5c833SDouglas Gilbert 	u8 *arr;
197438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
197538d5c833SDouglas Gilbert 
197638d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
197738d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
197838d5c833SDouglas Gilbert 	req_opcode = cmd[3];
197938d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
198038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19816d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
198238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
198338d5c833SDouglas Gilbert 		return check_condition_result;
198438d5c833SDouglas Gilbert 	}
198538d5c833SDouglas Gilbert 	if (alloc_len > 8192)
198638d5c833SDouglas Gilbert 		a_len = 8192;
198738d5c833SDouglas Gilbert 	else
198838d5c833SDouglas Gilbert 		a_len = alloc_len;
198999531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
199038d5c833SDouglas Gilbert 	if (NULL == arr) {
199138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
199238d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
199338d5c833SDouglas Gilbert 		return check_condition_result;
199438d5c833SDouglas Gilbert 	}
199538d5c833SDouglas Gilbert 	switch (reporting_opts) {
199638d5c833SDouglas Gilbert 	case 0:	/* all commands */
199738d5c833SDouglas Gilbert 		/* count number of commands */
199838d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
199938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
200038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
200138d5c833SDouglas Gilbert 				continue;
200238d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
200338d5c833SDouglas Gilbert 		}
200438d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
200538d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
200638d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
200738d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
200838d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
200938d5c833SDouglas Gilbert 				continue;
201038d5c833SDouglas Gilbert 			na = oip->num_attached;
201138d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
201238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
201338d5c833SDouglas Gilbert 			if (rctd)
201438d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
201538d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
201638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
201738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
201838d5c833SDouglas Gilbert 			if (rctd)
201938d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
202038d5c833SDouglas Gilbert 			r_oip = oip;
202138d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
202238d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
202338d5c833SDouglas Gilbert 					continue;
202438d5c833SDouglas Gilbert 				offset += bump;
202538d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
202638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
202738d5c833SDouglas Gilbert 				if (rctd)
202838d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
202938d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
203038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
203138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
203238d5c833SDouglas Gilbert 						   arr + offset + 6);
203338d5c833SDouglas Gilbert 				if (rctd)
203438d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
203538d5c833SDouglas Gilbert 							   arr + offset + 8);
203638d5c833SDouglas Gilbert 			}
203738d5c833SDouglas Gilbert 			oip = r_oip;
203838d5c833SDouglas Gilbert 			offset += bump;
203938d5c833SDouglas Gilbert 		}
204038d5c833SDouglas Gilbert 		break;
204138d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
204238d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
204338d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
204438d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
204538d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
204638d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
204738d5c833SDouglas Gilbert 			supp = 1;
204838d5c833SDouglas Gilbert 			offset = 4;
204938d5c833SDouglas Gilbert 		} else {
205038d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
205138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
205238d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
205338d5c833SDouglas Gilbert 							     2, 2);
205438d5c833SDouglas Gilbert 					kfree(arr);
205538d5c833SDouglas Gilbert 					return check_condition_result;
205638d5c833SDouglas Gilbert 				}
205738d5c833SDouglas Gilbert 				req_sa = 0;
205838d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
205938d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
206038d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
206138d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
206238d5c833SDouglas Gilbert 				return check_condition_result;
206338d5c833SDouglas Gilbert 			}
206438d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
206538d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
206638d5c833SDouglas Gilbert 				supp = 3;
206738d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
206838d5c833SDouglas Gilbert 				na = oip->num_attached;
206938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
207038d5c833SDouglas Gilbert 				     ++k, ++oip) {
207138d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
207238d5c833SDouglas Gilbert 						break;
207338d5c833SDouglas Gilbert 				}
207438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
207538d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
207638d5c833SDouglas Gilbert 				na = oip->num_attached;
207738d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
207838d5c833SDouglas Gilbert 				     ++k, ++oip) {
207938d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
208038d5c833SDouglas Gilbert 						break;
208138d5c833SDouglas Gilbert 				}
208238d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208338d5c833SDouglas Gilbert 			} else
208438d5c833SDouglas Gilbert 				supp = 3;
208538d5c833SDouglas Gilbert 			if (3 == supp) {
208638d5c833SDouglas Gilbert 				u = oip->len_mask[0];
208738d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
208838d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
208938d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
209038d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
209138d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
209238d5c833SDouglas Gilbert 				offset = 4 + u;
209338d5c833SDouglas Gilbert 			} else
209438d5c833SDouglas Gilbert 				offset = 4;
209538d5c833SDouglas Gilbert 		}
209638d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
209738d5c833SDouglas Gilbert 		if (rctd) {
209838d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
209938d5c833SDouglas Gilbert 			offset += 12;
210038d5c833SDouglas Gilbert 		}
210138d5c833SDouglas Gilbert 		break;
210238d5c833SDouglas Gilbert 	default:
210338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
210438d5c833SDouglas Gilbert 		kfree(arr);
210538d5c833SDouglas Gilbert 		return check_condition_result;
210638d5c833SDouglas Gilbert 	}
210738d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
210838d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
210938d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
211038d5c833SDouglas Gilbert 	kfree(arr);
211138d5c833SDouglas Gilbert 	return errsts;
211238d5c833SDouglas Gilbert }
211338d5c833SDouglas Gilbert 
2114fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2115fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
211638d5c833SDouglas Gilbert {
211738d5c833SDouglas Gilbert 	bool repd;
211838d5c833SDouglas Gilbert 	u32 alloc_len, len;
211938d5c833SDouglas Gilbert 	u8 arr[16];
212038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
212138d5c833SDouglas Gilbert 
212238d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
212338d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
212438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
212538d5c833SDouglas Gilbert 	if (alloc_len < 4) {
212638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
212738d5c833SDouglas Gilbert 		return check_condition_result;
212838d5c833SDouglas Gilbert 	}
212938d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
213038d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
213138d5c833SDouglas Gilbert 	if (repd) {
213238d5c833SDouglas Gilbert 		arr[3] = 0xc;
213338d5c833SDouglas Gilbert 		len = 16;
213438d5c833SDouglas Gilbert 	} else
213538d5c833SDouglas Gilbert 		len = 4;
213638d5c833SDouglas Gilbert 
213738d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
213838d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
213938d5c833SDouglas Gilbert }
214038d5c833SDouglas Gilbert 
21411da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21421da177e4SLinus Torvalds 
21431da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21441da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21451da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21461da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21491da177e4SLinus Torvalds 	if (1 == pcontrol)
21501da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21511da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21521da177e4SLinus Torvalds }
21531da177e4SLinus Torvalds 
21541da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21551da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21561da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21571da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21581da177e4SLinus Torvalds 
21591da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21601da177e4SLinus Torvalds 	if (1 == pcontrol)
21611da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21621da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21631da177e4SLinus Torvalds }
21641da177e4SLinus Torvalds 
21651da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21661da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21671da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21681da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21691da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21701da177e4SLinus Torvalds 
21711da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2172773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2173773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2174773642d9SDouglas Gilbert 	if (sdebug_removable)
21751da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21761da177e4SLinus Torvalds 	if (1 == pcontrol)
21771da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21781da177e4SLinus Torvalds 	return sizeof(format_pg);
21791da177e4SLinus Torvalds }
21801da177e4SLinus Torvalds 
2181fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2182fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2183fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2184fd32119bSDouglas Gilbert 
21851da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21861da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2187cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2188cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2189cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21901da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
21911da177e4SLinus Torvalds 
2192773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2193cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
21941da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
21951da177e4SLinus Torvalds 	if (1 == pcontrol)
2196cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2197cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2198cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
21991da177e4SLinus Torvalds 	return sizeof(caching_pg);
22001da177e4SLinus Torvalds }
22011da177e4SLinus Torvalds 
2202fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2203fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2204fd32119bSDouglas Gilbert 
22051da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22061da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2207c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2208c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2209c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22101da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22111da177e4SLinus Torvalds 
2212773642d9SDouglas Gilbert 	if (sdebug_dsense)
22131da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2214c65b1445SDouglas Gilbert 	else
2215c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2216c6a44287SMartin K. Petersen 
2217773642d9SDouglas Gilbert 	if (sdebug_ato)
2218c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2219c6a44287SMartin K. Petersen 
22201da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22211da177e4SLinus Torvalds 	if (1 == pcontrol)
2222c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2223c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2224c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22251da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22261da177e4SLinus Torvalds }
22271da177e4SLinus Torvalds 
2228c65b1445SDouglas Gilbert 
22291da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22301da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2231c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22321da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2233c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2234c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2235c65b1445SDouglas Gilbert 
22361da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22371da177e4SLinus Torvalds 	if (1 == pcontrol)
2238c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2239c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2240c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22411da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22421da177e4SLinus Torvalds }
22431da177e4SLinus Torvalds 
2244c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2245c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2246c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2247c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2248c65b1445SDouglas Gilbert 
2249c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2250c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2251c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2252c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2253c65b1445SDouglas Gilbert }
2254c65b1445SDouglas Gilbert 
2255c65b1445SDouglas Gilbert 
2256c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2257c65b1445SDouglas Gilbert 			      int target_dev_id)
2258c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2259c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2260c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2261773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2262773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2263c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2264c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2265c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2266c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2267773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2268773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2269c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2270c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2271c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2272c65b1445SDouglas Gilbert 		};
2273c65b1445SDouglas Gilbert 	int port_a, port_b;
2274c65b1445SDouglas Gilbert 
22751b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22761b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22771b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22781b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2279c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2280c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2281c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2282773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2283773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2284c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2285c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2286c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2287c65b1445SDouglas Gilbert }
2288c65b1445SDouglas Gilbert 
2289c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2290c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2291c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2292c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2293c65b1445SDouglas Gilbert 		};
2294c65b1445SDouglas Gilbert 
2295c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2296c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2297c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2298c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2299c65b1445SDouglas Gilbert }
2300c65b1445SDouglas Gilbert 
23011da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23021da177e4SLinus Torvalds 
2303fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2304fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23051da177e4SLinus Torvalds {
230623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23071da177e4SLinus Torvalds 	unsigned char dev_spec;
2308760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2309c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23101da177e4SLinus Torvalds 	unsigned char *ap;
23111da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
231201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2313d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23141da177e4SLinus Torvalds 
2315760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23161da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23171da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23181da177e4SLinus Torvalds 	subpcode = cmd[3];
23191da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2320760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2321760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
232264e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2323d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
232423183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
232523183910SDouglas Gilbert 	else
232623183910SDouglas Gilbert 		bd_len = 0;
2327773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23281da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23291da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2330cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23311da177e4SLinus Torvalds 		return check_condition_result;
23321da177e4SLinus Torvalds 	}
2333c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2334c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2335d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2336d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2337b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23389447b6ceSMartin K. Petersen 		if (sdebug_wp)
23399447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23409447b6ceSMartin K. Petersen 	} else
234123183910SDouglas Gilbert 		dev_spec = 0x0;
23421da177e4SLinus Torvalds 	if (msense_6) {
23431da177e4SLinus Torvalds 		arr[2] = dev_spec;
234423183910SDouglas Gilbert 		arr[3] = bd_len;
23451da177e4SLinus Torvalds 		offset = 4;
23461da177e4SLinus Torvalds 	} else {
23471da177e4SLinus Torvalds 		arr[3] = dev_spec;
234823183910SDouglas Gilbert 		if (16 == bd_len)
234923183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
235023183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23511da177e4SLinus Torvalds 		offset = 8;
23521da177e4SLinus Torvalds 	}
23531da177e4SLinus Torvalds 	ap = arr + offset;
235428898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
235528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
235628898873SFUJITA Tomonori 
235723183910SDouglas Gilbert 	if (8 == bd_len) {
2358773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2359773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2360773642d9SDouglas Gilbert 		else
2361773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2362773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
236323183910SDouglas Gilbert 		offset += bd_len;
236423183910SDouglas Gilbert 		ap = arr + offset;
236523183910SDouglas Gilbert 	} else if (16 == bd_len) {
2366773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2367773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
236823183910SDouglas Gilbert 		offset += bd_len;
236923183910SDouglas Gilbert 		ap = arr + offset;
237023183910SDouglas Gilbert 	}
23711da177e4SLinus Torvalds 
2372c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2373c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
237422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23751da177e4SLinus Torvalds 		return check_condition_result;
23761da177e4SLinus Torvalds 	}
2377760f3b03SDouglas Gilbert 	bad_pcode = false;
2378760f3b03SDouglas Gilbert 
23791da177e4SLinus Torvalds 	switch (pcode) {
23801da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23811da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23821da177e4SLinus Torvalds 		offset += len;
23831da177e4SLinus Torvalds 		break;
23841da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23851da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23861da177e4SLinus Torvalds 		offset += len;
23871da177e4SLinus Torvalds 		break;
23881da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2389760f3b03SDouglas Gilbert 		if (is_disk) {
23901da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
23911da177e4SLinus Torvalds 			offset += len;
2392760f3b03SDouglas Gilbert 		} else
2393760f3b03SDouglas Gilbert 			bad_pcode = true;
23941da177e4SLinus Torvalds 		break;
23951da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2396d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
23971da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
23981da177e4SLinus Torvalds 			offset += len;
2399760f3b03SDouglas Gilbert 		} else
2400760f3b03SDouglas Gilbert 			bad_pcode = true;
24011da177e4SLinus Torvalds 		break;
24021da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24031da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24041da177e4SLinus Torvalds 		offset += len;
24051da177e4SLinus Torvalds 		break;
2406c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2407c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
240822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2409c65b1445SDouglas Gilbert 			return check_condition_result;
2410c65b1445SDouglas Gilbert 		}
2411c65b1445SDouglas Gilbert 		len = 0;
2412c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2413c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2414c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2415c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2416c65b1445SDouglas Gilbert 						  target_dev_id);
2417c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2418c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2419c65b1445SDouglas Gilbert 		offset += len;
2420c65b1445SDouglas Gilbert 		break;
24211da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24221da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24231da177e4SLinus Torvalds 		offset += len;
24241da177e4SLinus Torvalds 		break;
24251da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2426c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24271da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24281da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2429760f3b03SDouglas Gilbert 			if (is_disk) {
2430760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2431760f3b03SDouglas Gilbert 						      target);
2432760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2433760f3b03SDouglas Gilbert 						       target);
2434d36da305SDouglas Gilbert 			} else if (is_zbc) {
2435d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2436d36da305SDouglas Gilbert 						       target);
2437760f3b03SDouglas Gilbert 			}
24381da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2439c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2440c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2441c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2442c65b1445SDouglas Gilbert 						  target, target_dev_id);
2443c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2444c65b1445SDouglas Gilbert 			}
24451da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2446760f3b03SDouglas Gilbert 			offset += len;
2447c65b1445SDouglas Gilbert 		} else {
244822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2449c65b1445SDouglas Gilbert 			return check_condition_result;
2450c65b1445SDouglas Gilbert 		}
24511da177e4SLinus Torvalds 		break;
24521da177e4SLinus Torvalds 	default:
2453760f3b03SDouglas Gilbert 		bad_pcode = true;
2454760f3b03SDouglas Gilbert 		break;
2455760f3b03SDouglas Gilbert 	}
2456760f3b03SDouglas Gilbert 	if (bad_pcode) {
245722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24581da177e4SLinus Torvalds 		return check_condition_result;
24591da177e4SLinus Torvalds 	}
24601da177e4SLinus Torvalds 	if (msense_6)
24611da177e4SLinus Torvalds 		arr[0] = offset - 1;
2462773642d9SDouglas Gilbert 	else
2463773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
246487c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24651da177e4SLinus Torvalds }
24661da177e4SLinus Torvalds 
2467c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2468c65b1445SDouglas Gilbert 
2469fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2470fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2471c65b1445SDouglas Gilbert {
2472c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2473c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2474c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
247501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2476c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2477c65b1445SDouglas Gilbert 
2478c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2479c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2480c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2481773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2482c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
248322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2484c65b1445SDouglas Gilbert 		return check_condition_result;
2485c65b1445SDouglas Gilbert 	}
2486c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2487c65b1445SDouglas Gilbert 	if (-1 == res)
2488773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2489773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2490cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2491cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2492cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2493773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2494773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
249523183910SDouglas Gilbert 	if (md_len > 2) {
249622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2497c65b1445SDouglas Gilbert 		return check_condition_result;
2498c65b1445SDouglas Gilbert 	}
2499c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2500c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2501c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2502c65b1445SDouglas Gilbert 	if (ps) {
250322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2504c65b1445SDouglas Gilbert 		return check_condition_result;
2505c65b1445SDouglas Gilbert 	}
2506c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2507773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2508c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2509c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2510cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2511c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2512c65b1445SDouglas Gilbert 		return check_condition_result;
2513c65b1445SDouglas Gilbert 	}
2514c65b1445SDouglas Gilbert 	switch (mpage) {
2515cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2516cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2517cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2518cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2519cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2520cbf67842SDouglas Gilbert 		}
2521cbf67842SDouglas Gilbert 		break;
2522c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2523c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2524c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2525c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25269447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25279447b6ceSMartin K. Petersen 				sdebug_wp = true;
25289447b6ceSMartin K. Petersen 			else
25299447b6ceSMartin K. Petersen 				sdebug_wp = false;
2530773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2531cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2532c65b1445SDouglas Gilbert 		}
2533c65b1445SDouglas Gilbert 		break;
2534c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2535c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2536c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2537c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2538cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2539c65b1445SDouglas Gilbert 		}
2540c65b1445SDouglas Gilbert 		break;
2541c65b1445SDouglas Gilbert 	default:
2542c65b1445SDouglas Gilbert 		break;
2543c65b1445SDouglas Gilbert 	}
254422017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2545c65b1445SDouglas Gilbert 	return check_condition_result;
2546cbf67842SDouglas Gilbert set_mode_changed_ua:
2547cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2548cbf67842SDouglas Gilbert 	return 0;
2549c65b1445SDouglas Gilbert }
2550c65b1445SDouglas Gilbert 
2551c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2552c65b1445SDouglas Gilbert {
2553c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2554c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2555c65b1445SDouglas Gilbert 		};
2556c65b1445SDouglas Gilbert 
2557c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2558c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2559c65b1445SDouglas Gilbert }
2560c65b1445SDouglas Gilbert 
2561c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2562c65b1445SDouglas Gilbert {
2563c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2564c65b1445SDouglas Gilbert 		};
2565c65b1445SDouglas Gilbert 
2566c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2567c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2568c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2569c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2570c65b1445SDouglas Gilbert 	}
2571c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2572c65b1445SDouglas Gilbert }
2573c65b1445SDouglas Gilbert 
2574c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2575c65b1445SDouglas Gilbert 
2576c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2577c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2578c65b1445SDouglas Gilbert {
2579ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2580c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
258101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2582c65b1445SDouglas Gilbert 
2583c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2584c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2585c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2586c65b1445SDouglas Gilbert 	if (ppc || sp) {
258722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2588c65b1445SDouglas Gilbert 		return check_condition_result;
2589c65b1445SDouglas Gilbert 	}
2590c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
259123183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2592773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2593c65b1445SDouglas Gilbert 	arr[0] = pcode;
259423183910SDouglas Gilbert 	if (0 == subpcode) {
2595c65b1445SDouglas Gilbert 		switch (pcode) {
2596c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2597c65b1445SDouglas Gilbert 			n = 4;
2598c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2599c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2600c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2601c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2602c65b1445SDouglas Gilbert 			break;
2603c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2604c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2605c65b1445SDouglas Gilbert 			break;
2606c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2607c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2608c65b1445SDouglas Gilbert 			break;
2609c65b1445SDouglas Gilbert 		default:
261022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2611c65b1445SDouglas Gilbert 			return check_condition_result;
2612c65b1445SDouglas Gilbert 		}
261323183910SDouglas Gilbert 	} else if (0xff == subpcode) {
261423183910SDouglas Gilbert 		arr[0] |= 0x40;
261523183910SDouglas Gilbert 		arr[1] = subpcode;
261623183910SDouglas Gilbert 		switch (pcode) {
261723183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
261823183910SDouglas Gilbert 			n = 4;
261923183910SDouglas Gilbert 			arr[n++] = 0x0;
262023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
262123183910SDouglas Gilbert 			arr[n++] = 0x0;
262223183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
262323183910SDouglas Gilbert 			arr[n++] = 0xd;
262423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
262523183910SDouglas Gilbert 			arr[n++] = 0x2f;
262623183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
262723183910SDouglas Gilbert 			arr[3] = n - 4;
262823183910SDouglas Gilbert 			break;
262923183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
263023183910SDouglas Gilbert 			n = 4;
263123183910SDouglas Gilbert 			arr[n++] = 0xd;
263223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
263323183910SDouglas Gilbert 			arr[3] = n - 4;
263423183910SDouglas Gilbert 			break;
263523183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
263623183910SDouglas Gilbert 			n = 4;
263723183910SDouglas Gilbert 			arr[n++] = 0x2f;
263823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
263923183910SDouglas Gilbert 			arr[3] = n - 4;
264023183910SDouglas Gilbert 			break;
264123183910SDouglas Gilbert 		default:
264222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
264323183910SDouglas Gilbert 			return check_condition_result;
264423183910SDouglas Gilbert 		}
264523183910SDouglas Gilbert 	} else {
264622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
264723183910SDouglas Gilbert 		return check_condition_result;
264823183910SDouglas Gilbert 	}
264987c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2650c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
265187c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2652c65b1445SDouglas Gilbert }
2653c65b1445SDouglas Gilbert 
2654f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2655f0d1cf93SDouglas Gilbert {
2656f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2657f0d1cf93SDouglas Gilbert }
2658f0d1cf93SDouglas Gilbert 
2659f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2660f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2661f0d1cf93SDouglas Gilbert {
2662108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2663f0d1cf93SDouglas Gilbert }
2664f0d1cf93SDouglas Gilbert 
2665f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2666f0d1cf93SDouglas Gilbert {
266764e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2668f0d1cf93SDouglas Gilbert }
2669f0d1cf93SDouglas Gilbert 
2670f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2671f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2672f0d1cf93SDouglas Gilbert {
2673f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2674f0d1cf93SDouglas Gilbert 
2675f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2676f0d1cf93SDouglas Gilbert 		return;
2677f0d1cf93SDouglas Gilbert 
2678f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2679f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2680f0d1cf93SDouglas Gilbert 		return;
2681f0d1cf93SDouglas Gilbert 
2682f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2683f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2684f0d1cf93SDouglas Gilbert 	else
2685f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2686f0d1cf93SDouglas Gilbert 
2687f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2688f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2689f0d1cf93SDouglas Gilbert 	} else {
2690f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2691f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2692f0d1cf93SDouglas Gilbert 	}
2693f0d1cf93SDouglas Gilbert }
2694f0d1cf93SDouglas Gilbert 
2695f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2696f0d1cf93SDouglas Gilbert {
2697f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2698f0d1cf93SDouglas Gilbert 	unsigned int i;
2699f0d1cf93SDouglas Gilbert 
2700f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2701f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2702f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2703f0d1cf93SDouglas Gilbert 			return;
2704f0d1cf93SDouglas Gilbert 		}
2705f0d1cf93SDouglas Gilbert 	}
2706f0d1cf93SDouglas Gilbert }
2707f0d1cf93SDouglas Gilbert 
2708f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2709f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2710f0d1cf93SDouglas Gilbert {
2711f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2712f0d1cf93SDouglas Gilbert 
2713f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2714f0d1cf93SDouglas Gilbert 		return;
2715f0d1cf93SDouglas Gilbert 
2716f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2717f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2718f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2719f0d1cf93SDouglas Gilbert 		return;
2720f0d1cf93SDouglas Gilbert 
2721f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2722f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2723f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2724f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2725f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2726f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2727f0d1cf93SDouglas Gilbert 
2728f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2729f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2730f0d1cf93SDouglas Gilbert 	if (explicit) {
2731f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2732f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2733f0d1cf93SDouglas Gilbert 	} else {
2734f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2735f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2736f0d1cf93SDouglas Gilbert 	}
2737f0d1cf93SDouglas Gilbert }
2738f0d1cf93SDouglas Gilbert 
2739f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2740f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2741f0d1cf93SDouglas Gilbert {
2742f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
274364e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2744f0d1cf93SDouglas Gilbert 
2745f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2746f0d1cf93SDouglas Gilbert 		return;
2747f0d1cf93SDouglas Gilbert 
274864e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2749f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
275064e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2751f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
275264e14eceSDamien Le Moal 		return;
275364e14eceSDamien Le Moal 	}
275464e14eceSDamien Le Moal 
275564e14eceSDamien Le Moal 	while (num) {
275664e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
275764e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
275864e14eceSDamien Le Moal 
275964e14eceSDamien Le Moal 		end = lba + num;
276064e14eceSDamien Le Moal 		if (end >= zend) {
276164e14eceSDamien Le Moal 			n = zend - lba;
276264e14eceSDamien Le Moal 			zsp->z_wp = zend;
276364e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
276464e14eceSDamien Le Moal 			n = num;
276564e14eceSDamien Le Moal 			zsp->z_wp = end;
276664e14eceSDamien Le Moal 		} else {
276764e14eceSDamien Le Moal 			n = num;
276864e14eceSDamien Le Moal 		}
276964e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
277064e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
277164e14eceSDamien Le Moal 
277264e14eceSDamien Le Moal 		num -= n;
277364e14eceSDamien Le Moal 		lba += n;
277464e14eceSDamien Le Moal 		if (num) {
277564e14eceSDamien Le Moal 			zsp++;
277664e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
277764e14eceSDamien Le Moal 		}
277864e14eceSDamien Le Moal 	}
2779f0d1cf93SDouglas Gilbert }
2780f0d1cf93SDouglas Gilbert 
2781f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27829447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27831da177e4SLinus Torvalds {
2784f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2785f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2786f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2787f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2788f0d1cf93SDouglas Gilbert 
2789f0d1cf93SDouglas Gilbert 	if (!write) {
279064e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
279164e14eceSDamien Le Moal 			return 0;
279264e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2793f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2794f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2795f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2796f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2797f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2798f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2799f0d1cf93SDouglas Gilbert 			return check_condition_result;
2800f0d1cf93SDouglas Gilbert 		}
2801f0d1cf93SDouglas Gilbert 		return 0;
2802f0d1cf93SDouglas Gilbert 	}
2803f0d1cf93SDouglas Gilbert 
2804f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2805f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2806f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2807f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2808f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2809f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2810f0d1cf93SDouglas Gilbert 			return check_condition_result;
2811f0d1cf93SDouglas Gilbert 		}
2812f0d1cf93SDouglas Gilbert 		return 0;
2813f0d1cf93SDouglas Gilbert 	}
2814f0d1cf93SDouglas Gilbert 
281564e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2816f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2817f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2818f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2819f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2820f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2821f0d1cf93SDouglas Gilbert 			return check_condition_result;
2822f0d1cf93SDouglas Gilbert 		}
2823f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2824f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2825f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2826f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2827f0d1cf93SDouglas Gilbert 			return check_condition_result;
2828f0d1cf93SDouglas Gilbert 		}
2829f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2830f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2831f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2832f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2833f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2834f0d1cf93SDouglas Gilbert 			return check_condition_result;
2835f0d1cf93SDouglas Gilbert 		}
283664e14eceSDamien Le Moal 	}
2837f0d1cf93SDouglas Gilbert 
2838f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2839f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2840f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2841f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2842f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2843f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2844f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2845f0d1cf93SDouglas Gilbert 			return check_condition_result;
2846f0d1cf93SDouglas Gilbert 		}
2847f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2848f0d1cf93SDouglas Gilbert 	}
2849f0d1cf93SDouglas Gilbert 
2850f0d1cf93SDouglas Gilbert 	return 0;
2851f0d1cf93SDouglas Gilbert }
2852f0d1cf93SDouglas Gilbert 
2853f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2854f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2855f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2856f0d1cf93SDouglas Gilbert {
2857f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2858f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2859f0d1cf93SDouglas Gilbert 
2860c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
286122017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28621da177e4SLinus Torvalds 		return check_condition_result;
28631da177e4SLinus Torvalds 	}
2864c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2865c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
286622017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2867cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2868c65b1445SDouglas Gilbert 		return check_condition_result;
2869c65b1445SDouglas Gilbert 	}
28709447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28719447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28729447b6ceSMartin K. Petersen 		return check_condition_result;
28739447b6ceSMartin K. Petersen 	}
2874f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2875f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2876f0d1cf93SDouglas Gilbert 
287719789100SFUJITA Tomonori 	return 0;
287819789100SFUJITA Tomonori }
287919789100SFUJITA Tomonori 
2880b6ff8ca7SDouglas Gilbert /*
2881b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2882b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2883b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2884b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2885b6ff8ca7SDouglas Gilbert  */
2886b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2887b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
288887c715dcSDouglas Gilbert {
2889b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2890b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2891b6ff8ca7SDouglas Gilbert 		return NULL;
2892b6ff8ca7SDouglas Gilbert 	}
2893b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
289487c715dcSDouglas Gilbert }
289587c715dcSDouglas Gilbert 
2896a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
289787c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
289887c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
289919789100SFUJITA Tomonori {
290019789100SFUJITA Tomonori 	int ret;
2901c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2902a4517511SAkinobu Mita 	enum dma_data_direction dir;
290387c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
290487c715dcSDouglas Gilbert 	u8 *fsp;
290519789100SFUJITA Tomonori 
2906c2248fc9SDouglas Gilbert 	if (do_write) {
2907a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
29084f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2909a4517511SAkinobu Mita 	} else {
2910a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2911a4517511SAkinobu Mita 	}
2912a4517511SAkinobu Mita 
291387c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2914a4517511SAkinobu Mita 		return 0;
291587c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2916a4517511SAkinobu Mita 		return -1;
291787c715dcSDouglas Gilbert 	fsp = sip->storep;
291819789100SFUJITA Tomonori 
291919789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
292019789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
292119789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
292219789100SFUJITA Tomonori 
2923386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
292487c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29250a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2926773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2927a4517511SAkinobu Mita 		return ret;
2928a4517511SAkinobu Mita 
2929a4517511SAkinobu Mita 	if (rest) {
2930386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
293187c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29320a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29330a7e69c7SDouglas Gilbert 			    do_write);
2934a4517511SAkinobu Mita 	}
293519789100SFUJITA Tomonori 
293619789100SFUJITA Tomonori 	return ret;
293719789100SFUJITA Tomonori }
293819789100SFUJITA Tomonori 
293987c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
294087c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
294187c715dcSDouglas Gilbert {
294287c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
294387c715dcSDouglas Gilbert 
294487c715dcSDouglas Gilbert 	if (!sdb->length)
294587c715dcSDouglas Gilbert 		return 0;
294687c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
294787c715dcSDouglas Gilbert 		return -1;
294887c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
294987c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
295087c715dcSDouglas Gilbert }
295187c715dcSDouglas Gilbert 
295287c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
295387c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
295438d5c833SDouglas Gilbert  * return false. */
295587c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2956c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
295738d5c833SDouglas Gilbert {
295838d5c833SDouglas Gilbert 	bool res;
295938d5c833SDouglas Gilbert 	u64 block, rest = 0;
296038d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2961773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
296287c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
296338d5c833SDouglas Gilbert 
296438d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
296538d5c833SDouglas Gilbert 	if (block + num > store_blks)
296638d5c833SDouglas Gilbert 		rest = block + num - store_blks;
296738d5c833SDouglas Gilbert 
296887c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
296938d5c833SDouglas Gilbert 	if (!res)
297038d5c833SDouglas Gilbert 		return res;
297138d5c833SDouglas Gilbert 	if (rest)
297287c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
297338d5c833SDouglas Gilbert 			     rest * lb_size);
297438d5c833SDouglas Gilbert 	if (!res)
297538d5c833SDouglas Gilbert 		return res;
2976c3e2fe92SDouglas Gilbert 	if (compare_only)
2977c3e2fe92SDouglas Gilbert 		return true;
297838d5c833SDouglas Gilbert 	arr += num * lb_size;
297987c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
298038d5c833SDouglas Gilbert 	if (rest)
298187c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
298238d5c833SDouglas Gilbert 	return res;
298338d5c833SDouglas Gilbert }
298438d5c833SDouglas Gilbert 
298551d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2986beb40ea4SAkinobu Mita {
298751d648afSAkinobu Mita 	__be16 csum;
2988beb40ea4SAkinobu Mita 
2989773642d9SDouglas Gilbert 	if (sdebug_guard)
299051d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
299151d648afSAkinobu Mita 	else
2992beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
299351d648afSAkinobu Mita 
2994beb40ea4SAkinobu Mita 	return csum;
2995beb40ea4SAkinobu Mita }
2996beb40ea4SAkinobu Mita 
29976ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2998beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2999beb40ea4SAkinobu Mita {
3000773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3001beb40ea4SAkinobu Mita 
3002beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3003c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3004beb40ea4SAkinobu Mita 			(unsigned long)sector,
3005beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3006beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3007beb40ea4SAkinobu Mita 		return 0x01;
3008beb40ea4SAkinobu Mita 	}
30098475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3010beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3011c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3012c1287970STomas Winkler 			(unsigned long)sector);
3013beb40ea4SAkinobu Mita 		return 0x03;
3014beb40ea4SAkinobu Mita 	}
30158475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3016beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3017c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3018c1287970STomas Winkler 			(unsigned long)sector);
3019beb40ea4SAkinobu Mita 		return 0x03;
3020beb40ea4SAkinobu Mita 	}
3021beb40ea4SAkinobu Mita 	return 0;
3022beb40ea4SAkinobu Mita }
3023beb40ea4SAkinobu Mita 
302487c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
302565f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3026c6a44287SMartin K. Petersen {
3027be4e11beSAkinobu Mita 	size_t resid;
3028c6a44287SMartin K. Petersen 	void *paddr;
302987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3030b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
303187c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
303214faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3033be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3034c6a44287SMartin K. Petersen 
3035e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3036e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3037c6a44287SMartin K. Petersen 
303887c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
303987c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3040be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3041be4e11beSAkinobu Mita 
3042be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
304387c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
304487c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3045be4e11beSAkinobu Mita 		size_t rest = 0;
304614faa944SAkinobu Mita 
304714faa944SAkinobu Mita 		if (dif_store_end < start + len)
304814faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3049c6a44287SMartin K. Petersen 
3050be4e11beSAkinobu Mita 		paddr = miter.addr;
305114faa944SAkinobu Mita 
305265f72f2aSAkinobu Mita 		if (read)
305365f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
305465f72f2aSAkinobu Mita 		else
305565f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
305665f72f2aSAkinobu Mita 
305765f72f2aSAkinobu Mita 		if (rest) {
305865f72f2aSAkinobu Mita 			if (read)
305914faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
306065f72f2aSAkinobu Mita 			else
306165f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
306265f72f2aSAkinobu Mita 		}
3063c6a44287SMartin K. Petersen 
3064e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3065c6a44287SMartin K. Petersen 		resid -= len;
3066c6a44287SMartin K. Petersen 	}
3067be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3068bb8c063cSAkinobu Mita }
3069c6a44287SMartin K. Petersen 
307087c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3071bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3072bb8c063cSAkinobu Mita {
3073bb8c063cSAkinobu Mita 	unsigned int i;
3074bb8c063cSAkinobu Mita 	sector_t sector;
307587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3076b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
307787c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3078bb8c063cSAkinobu Mita 
3079c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3080bb8c063cSAkinobu Mita 		int ret;
3081bb8c063cSAkinobu Mita 
3082bb8c063cSAkinobu Mita 		sector = start_sec + i;
308387c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3084bb8c063cSAkinobu Mita 
308551d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3086bb8c063cSAkinobu Mita 			continue;
3087bb8c063cSAkinobu Mita 
308887c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
308987c715dcSDouglas Gilbert 				 ei_lba);
3090bb8c063cSAkinobu Mita 		if (ret) {
3091bb8c063cSAkinobu Mita 			dif_errors++;
3092bb8c063cSAkinobu Mita 			return ret;
3093bb8c063cSAkinobu Mita 		}
3094bb8c063cSAkinobu Mita 	}
3095bb8c063cSAkinobu Mita 
309687c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3097c6a44287SMartin K. Petersen 	dix_reads++;
3098c6a44287SMartin K. Petersen 
3099c6a44287SMartin K. Petersen 	return 0;
3100c6a44287SMartin K. Petersen }
3101c6a44287SMartin K. Petersen 
3102fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
310319789100SFUJITA Tomonori {
310487c715dcSDouglas Gilbert 	bool check_prot;
3105c2248fc9SDouglas Gilbert 	u32 num;
3106c2248fc9SDouglas Gilbert 	u32 ei_lba;
310719789100SFUJITA Tomonori 	int ret;
310887c715dcSDouglas Gilbert 	u64 lba;
3109b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
311087c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
311187c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
311287c715dcSDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
311319789100SFUJITA Tomonori 
3114c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3115c2248fc9SDouglas Gilbert 	case READ_16:
3116c2248fc9SDouglas Gilbert 		ei_lba = 0;
3117c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3118c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3119c2248fc9SDouglas Gilbert 		check_prot = true;
3120c2248fc9SDouglas Gilbert 		break;
3121c2248fc9SDouglas Gilbert 	case READ_10:
3122c2248fc9SDouglas Gilbert 		ei_lba = 0;
3123c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3124c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3125c2248fc9SDouglas Gilbert 		check_prot = true;
3126c2248fc9SDouglas Gilbert 		break;
3127c2248fc9SDouglas Gilbert 	case READ_6:
3128c2248fc9SDouglas Gilbert 		ei_lba = 0;
3129c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3130c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3131c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3132c2248fc9SDouglas Gilbert 		check_prot = true;
3133c2248fc9SDouglas Gilbert 		break;
3134c2248fc9SDouglas Gilbert 	case READ_12:
3135c2248fc9SDouglas Gilbert 		ei_lba = 0;
3136c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3137c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3138c2248fc9SDouglas Gilbert 		check_prot = true;
3139c2248fc9SDouglas Gilbert 		break;
3140c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3141c2248fc9SDouglas Gilbert 		ei_lba = 0;
3142c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3143c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3144c2248fc9SDouglas Gilbert 		check_prot = false;
3145c2248fc9SDouglas Gilbert 		break;
3146c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3147c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3148c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3149c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3150c2248fc9SDouglas Gilbert 		check_prot = false;
3151c2248fc9SDouglas Gilbert 		break;
3152c2248fc9SDouglas Gilbert 	}
3153f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31548475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3155c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3156c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3157c2248fc9SDouglas Gilbert 			return check_condition_result;
3158c2248fc9SDouglas Gilbert 		}
31598475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31608475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3161c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3162c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3163c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3164c2248fc9SDouglas Gilbert 	}
3165f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3166c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
3167c2248fc9SDouglas Gilbert 
3168c4837394SDouglas Gilbert 		if (sqcp) {
3169c4837394SDouglas Gilbert 			if (sqcp->inj_short)
3170c2248fc9SDouglas Gilbert 				num /= 2;
3171c2248fc9SDouglas Gilbert 		}
3172c4837394SDouglas Gilbert 	} else
3173c4837394SDouglas Gilbert 		sqcp = NULL;
3174c2248fc9SDouglas Gilbert 
31759447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31769447b6ceSMartin K. Petersen 	if (ret)
31779447b6ceSMartin K. Petersen 		return ret;
3178f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3179d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3180d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3181c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3182c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3183c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3184c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3185c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
318632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
318732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3188c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3189c65b1445SDouglas Gilbert 		}
3190c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
31911da177e4SLinus Torvalds 		return check_condition_result;
31921da177e4SLinus Torvalds 	}
3193c6a44287SMartin K. Petersen 
319467da413fSDouglas Gilbert 	read_lock(macc_lckp);
31956c78cc06SAkinobu Mita 
3196c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3197f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3198c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
3199c6a44287SMartin K. Petersen 
3200c6a44287SMartin K. Petersen 		if (prot_ret) {
320167da413fSDouglas Gilbert 			read_unlock(macc_lckp);
3202c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
3203c6a44287SMartin K. Petersen 			return illegal_condition_result;
3204c6a44287SMartin K. Petersen 		}
3205c6a44287SMartin K. Petersen 	}
3206c6a44287SMartin K. Petersen 
320787c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
320867da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3209f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3210a4517511SAkinobu Mita 		return DID_ERROR << 16;
3211a4517511SAkinobu Mita 
321242d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3213a4517511SAkinobu Mita 
3214c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
3215c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
3216c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
3217c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
3218c2248fc9SDouglas Gilbert 			return check_condition_result;
3219c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
3220c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
3221c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3222c2248fc9SDouglas Gilbert 			return check_condition_result;
3223c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
3224c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3225c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3226c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3227c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
3228c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3229c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3230c2248fc9SDouglas Gilbert 		}
3231c2248fc9SDouglas Gilbert 	}
3232a4517511SAkinobu Mita 	return 0;
32331da177e4SLinus Torvalds }
32341da177e4SLinus Torvalds 
323558a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
3236c6a44287SMartin K. Petersen {
3237cbf67842SDouglas Gilbert 	int i, j, n;
3238c6a44287SMartin K. Petersen 
3239cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
3240c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
3241cbf67842SDouglas Gilbert 		char b[128];
3242c6a44287SMartin K. Petersen 
3243cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
3244c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
3245c6a44287SMartin K. Petersen 
3246cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
3247cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3248cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
3249cbf67842SDouglas Gilbert 			else
3250cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3251cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
3252cbf67842SDouglas Gilbert 		}
3253cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
3254c6a44287SMartin K. Petersen 	}
3255c6a44287SMartin K. Petersen }
3256c6a44287SMartin K. Petersen 
3257c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3258395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3259c6a44287SMartin K. Petersen {
3260be4e11beSAkinobu Mita 	int ret;
32616ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3262be4e11beSAkinobu Mita 	void *daddr;
326365f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3264c6a44287SMartin K. Petersen 	int ppage_offset;
3265be4e11beSAkinobu Mita 	int dpage_offset;
3266be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3267be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3268c6a44287SMartin K. Petersen 
3269c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3270c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3271c6a44287SMartin K. Petersen 
3272be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3273be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3274be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3275be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3276be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3277c6a44287SMartin K. Petersen 
3278be4e11beSAkinobu Mita 	/* For each protection page */
3279be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3280be4e11beSAkinobu Mita 		dpage_offset = 0;
3281be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3282be4e11beSAkinobu Mita 			ret = 0x01;
3283be4e11beSAkinobu Mita 			goto out;
3284c6a44287SMartin K. Petersen 		}
3285c6a44287SMartin K. Petersen 
3286be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32876ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3288be4e11beSAkinobu Mita 			/* If we're at the end of the current
3289be4e11beSAkinobu Mita 			 * data page advance to the next one
3290be4e11beSAkinobu Mita 			 */
3291be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3292be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3293be4e11beSAkinobu Mita 					ret = 0x01;
3294be4e11beSAkinobu Mita 					goto out;
3295be4e11beSAkinobu Mita 				}
3296be4e11beSAkinobu Mita 				dpage_offset = 0;
3297be4e11beSAkinobu Mita 			}
3298c6a44287SMartin K. Petersen 
3299be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3300be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3301be4e11beSAkinobu Mita 
3302be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
3303beb40ea4SAkinobu Mita 			if (ret) {
3304773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
3305395cef03SMartin K. Petersen 				goto out;
3306395cef03SMartin K. Petersen 			}
3307395cef03SMartin K. Petersen 
3308c6a44287SMartin K. Petersen 			sector++;
3309395cef03SMartin K. Petersen 			ei_lba++;
3310773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3311c6a44287SMartin K. Petersen 		}
3312be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3313be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3314c6a44287SMartin K. Petersen 	}
3315be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3316c6a44287SMartin K. Petersen 
331765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3318c6a44287SMartin K. Petersen 	dix_writes++;
3319c6a44287SMartin K. Petersen 
3320c6a44287SMartin K. Petersen 	return 0;
3321c6a44287SMartin K. Petersen 
3322c6a44287SMartin K. Petersen out:
3323c6a44287SMartin K. Petersen 	dif_errors++;
3324be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3325be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3326c6a44287SMartin K. Petersen 	return ret;
3327c6a44287SMartin K. Petersen }
3328c6a44287SMartin K. Petersen 
3329b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3330b90ebc3dSAkinobu Mita {
3331773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3332773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3333773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3334b90ebc3dSAkinobu Mita 	return lba;
3335b90ebc3dSAkinobu Mita }
3336b90ebc3dSAkinobu Mita 
3337b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3338b90ebc3dSAkinobu Mita {
3339773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3340a027b5b9SAkinobu Mita 
3341773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3342773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3343a027b5b9SAkinobu Mita 	return lba;
3344a027b5b9SAkinobu Mita }
3345a027b5b9SAkinobu Mita 
334687c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
334787c715dcSDouglas Gilbert 			      unsigned int *num)
334844d92694SMartin K. Petersen {
3349b90ebc3dSAkinobu Mita 	sector_t end;
3350b90ebc3dSAkinobu Mita 	unsigned int mapped;
3351b90ebc3dSAkinobu Mita 	unsigned long index;
3352b90ebc3dSAkinobu Mita 	unsigned long next;
335344d92694SMartin K. Petersen 
3354b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
335587c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
335644d92694SMartin K. Petersen 
335744d92694SMartin K. Petersen 	if (mapped)
335887c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
335944d92694SMartin K. Petersen 	else
336087c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
336144d92694SMartin K. Petersen 
3362b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
336344d92694SMartin K. Petersen 	*num = end - lba;
336444d92694SMartin K. Petersen 	return mapped;
336544d92694SMartin K. Petersen }
336644d92694SMartin K. Petersen 
336787c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
336887c715dcSDouglas Gilbert 		       unsigned int len)
336944d92694SMartin K. Petersen {
337044d92694SMartin K. Petersen 	sector_t end = lba + len;
337144d92694SMartin K. Petersen 
337244d92694SMartin K. Petersen 	while (lba < end) {
3373b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
337444d92694SMartin K. Petersen 
3375b90ebc3dSAkinobu Mita 		if (index < map_size)
337687c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
337744d92694SMartin K. Petersen 
3378b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
337944d92694SMartin K. Petersen 	}
338044d92694SMartin K. Petersen }
338144d92694SMartin K. Petersen 
338287c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
338387c715dcSDouglas Gilbert 			 unsigned int len)
338444d92694SMartin K. Petersen {
338544d92694SMartin K. Petersen 	sector_t end = lba + len;
338687c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
338744d92694SMartin K. Petersen 
338844d92694SMartin K. Petersen 	while (lba < end) {
3389b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
339044d92694SMartin K. Petersen 
3391b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3392773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3393b90ebc3dSAkinobu Mita 		    index < map_size) {
339487c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3395760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
339687c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3397760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3398773642d9SDouglas Gilbert 				       sdebug_sector_size *
3399773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3400be1dd78dSEric Sandeen 			}
340187c715dcSDouglas Gilbert 			if (sip->dif_storep) {
340287c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
340387c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3404773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3405e9926b43SAkinobu Mita 			}
3406b90ebc3dSAkinobu Mita 		}
3407b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
340844d92694SMartin K. Petersen 	}
340944d92694SMartin K. Petersen }
341044d92694SMartin K. Petersen 
3411fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34121da177e4SLinus Torvalds {
341387c715dcSDouglas Gilbert 	bool check_prot;
3414c2248fc9SDouglas Gilbert 	u32 num;
3415c2248fc9SDouglas Gilbert 	u32 ei_lba;
341619789100SFUJITA Tomonori 	int ret;
341787c715dcSDouglas Gilbert 	u64 lba;
3418b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3419b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
342087c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
34211da177e4SLinus Torvalds 
3422c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3423c2248fc9SDouglas Gilbert 	case WRITE_16:
3424c2248fc9SDouglas Gilbert 		ei_lba = 0;
3425c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3426c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3427c2248fc9SDouglas Gilbert 		check_prot = true;
3428c2248fc9SDouglas Gilbert 		break;
3429c2248fc9SDouglas Gilbert 	case WRITE_10:
3430c2248fc9SDouglas Gilbert 		ei_lba = 0;
3431c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3432c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3433c2248fc9SDouglas Gilbert 		check_prot = true;
3434c2248fc9SDouglas Gilbert 		break;
3435c2248fc9SDouglas Gilbert 	case WRITE_6:
3436c2248fc9SDouglas Gilbert 		ei_lba = 0;
3437c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3438c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3439c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3440c2248fc9SDouglas Gilbert 		check_prot = true;
3441c2248fc9SDouglas Gilbert 		break;
3442c2248fc9SDouglas Gilbert 	case WRITE_12:
3443c2248fc9SDouglas Gilbert 		ei_lba = 0;
3444c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3445c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3446c2248fc9SDouglas Gilbert 		check_prot = true;
3447c2248fc9SDouglas Gilbert 		break;
3448c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3449c2248fc9SDouglas Gilbert 		ei_lba = 0;
3450c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3451c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3452c2248fc9SDouglas Gilbert 		check_prot = false;
3453c2248fc9SDouglas Gilbert 		break;
3454c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3455c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3456c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3457c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3458c2248fc9SDouglas Gilbert 		check_prot = false;
3459c2248fc9SDouglas Gilbert 		break;
3460c2248fc9SDouglas Gilbert 	}
3461f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34628475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3463c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3464c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3465c2248fc9SDouglas Gilbert 			return check_condition_result;
3466c2248fc9SDouglas Gilbert 		}
34678475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34688475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3469c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3470c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3471c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3472c2248fc9SDouglas Gilbert 	}
3473f0d1cf93SDouglas Gilbert 
347467da413fSDouglas Gilbert 	write_lock(macc_lckp);
3475f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3476f0d1cf93SDouglas Gilbert 	if (ret) {
3477f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3478f0d1cf93SDouglas Gilbert 		return ret;
3479f0d1cf93SDouglas Gilbert 	}
34806c78cc06SAkinobu Mita 
3481c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3482f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3483c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3484c6a44287SMartin K. Petersen 
3485c6a44287SMartin K. Petersen 		if (prot_ret) {
348667da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3487c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3488c6a44287SMartin K. Petersen 			return illegal_condition_result;
3489c6a44287SMartin K. Petersen 		}
3490c6a44287SMartin K. Petersen 	}
3491c6a44287SMartin K. Petersen 
349287c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3493f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
349487c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3495f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3496f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3497f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
349867da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3499f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3500773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3501c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3502c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3503c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3504cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3505773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
350644d92694SMartin K. Petersen 
3507f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3508c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3509c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3510c2248fc9SDouglas Gilbert 
3511c4837394SDouglas Gilbert 		if (sqcp) {
3512c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3513c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3514c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3515c2248fc9SDouglas Gilbert 				return check_condition_result;
3516c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3517c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3518c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3519c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3520c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3521c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3522c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3523c2248fc9SDouglas Gilbert 			}
3524c2248fc9SDouglas Gilbert 		}
3525c4837394SDouglas Gilbert 	}
35261da177e4SLinus Torvalds 	return 0;
35271da177e4SLinus Torvalds }
35281da177e4SLinus Torvalds 
3529481b5e5cSDouglas Gilbert /*
3530481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3531481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3532481b5e5cSDouglas Gilbert  */
3533481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3534481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3535481b5e5cSDouglas Gilbert {
3536481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3537481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3538481b5e5cSDouglas Gilbert 	u8 *up;
3539b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3540b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
3541481b5e5cSDouglas Gilbert 	u8 wrprotect;
3542481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3543481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3544481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3545481b5e5cSDouglas Gilbert 	u32 ei_lba;
3546481b5e5cSDouglas Gilbert 	u64 lba;
3547481b5e5cSDouglas Gilbert 	int ret, res;
3548481b5e5cSDouglas Gilbert 	bool is_16;
3549481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3550481b5e5cSDouglas Gilbert 
3551481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3552481b5e5cSDouglas Gilbert 		is_16 = false;
3553481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3554481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3555481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3556481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3557481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3558481b5e5cSDouglas Gilbert 		is_16 = true;
3559481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3560481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3561481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3562481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3563481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3564481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3565481b5e5cSDouglas Gilbert 			    wrprotect) {
3566481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3567481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3568481b5e5cSDouglas Gilbert 			}
3569481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3570481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3571481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3572481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3573481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3574481b5e5cSDouglas Gilbert 		}
3575481b5e5cSDouglas Gilbert 	}
3576481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3577481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3578481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3579481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3580481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3581481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3582481b5e5cSDouglas Gilbert 				my_name, __func__);
3583481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3584481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3585481b5e5cSDouglas Gilbert 	}
3586481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3587481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3588481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3589481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3590481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3591481b5e5cSDouglas Gilbert 				my_name, __func__);
3592481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3593481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3594481b5e5cSDouglas Gilbert 	}
3595481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3596481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3597481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3598481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3599481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3600481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3601481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3602481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3603481b5e5cSDouglas Gilbert 	if (res == -1) {
3604481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3605481b5e5cSDouglas Gilbert 		goto err_out;
3606481b5e5cSDouglas Gilbert 	}
3607481b5e5cSDouglas Gilbert 
360867da413fSDouglas Gilbert 	write_lock(macc_lckp);
3609481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3610481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3611481b5e5cSDouglas Gilbert 	cum_lb = 0;
3612481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3613481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3614481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3615481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3616481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3617481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3618481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3619481b5e5cSDouglas Gilbert 		if (num == 0)
3620481b5e5cSDouglas Gilbert 			continue;
36219447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3622481b5e5cSDouglas Gilbert 		if (ret)
3623481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3624481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3625481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3626481b5e5cSDouglas Gilbert 
3627481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3628481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3629481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3630481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3631481b5e5cSDouglas Gilbert 				    my_name, __func__);
3632481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3633481b5e5cSDouglas Gilbert 					0);
3634481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3635481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3636481b5e5cSDouglas Gilbert 		}
3637481b5e5cSDouglas Gilbert 
3638481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3639481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3640481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3641481b5e5cSDouglas Gilbert 							 ei_lba);
3642481b5e5cSDouglas Gilbert 
3643481b5e5cSDouglas Gilbert 			if (prot_ret) {
3644481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3645481b5e5cSDouglas Gilbert 						prot_ret);
3646481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3647481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3648481b5e5cSDouglas Gilbert 			}
3649481b5e5cSDouglas Gilbert 		}
3650481b5e5cSDouglas Gilbert 
365187c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3652f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3653f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3654f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3655481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
365687c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3657481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3658481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3659481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3660481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3661481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3662481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3663481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3664481b5e5cSDouglas Gilbert 
3665481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3666481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3667481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3668481b5e5cSDouglas Gilbert 
3669481b5e5cSDouglas Gilbert 			if (sqcp) {
3670481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3671481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3672481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3673481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3674481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3675481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3676481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3677481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3678481b5e5cSDouglas Gilbert 							0x10, 1);
3679481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3680481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3681481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3682481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3683481b5e5cSDouglas Gilbert 							0x10, 1);
3684481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3685481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3686481b5e5cSDouglas Gilbert 				}
3687481b5e5cSDouglas Gilbert 			}
3688481b5e5cSDouglas Gilbert 		}
3689481b5e5cSDouglas Gilbert 		sg_off += num_by;
3690481b5e5cSDouglas Gilbert 		cum_lb += num;
3691481b5e5cSDouglas Gilbert 	}
3692481b5e5cSDouglas Gilbert 	ret = 0;
3693481b5e5cSDouglas Gilbert err_out_unlock:
369467da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3695481b5e5cSDouglas Gilbert err_out:
3696481b5e5cSDouglas Gilbert 	kfree(lrdp);
3697481b5e5cSDouglas Gilbert 	return ret;
3698481b5e5cSDouglas Gilbert }
3699481b5e5cSDouglas Gilbert 
3700fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3701fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
370244d92694SMartin K. Petersen {
3703f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3704f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
370544d92694SMartin K. Petersen 	unsigned long long i;
370640d07b52SDouglas Gilbert 	u64 block, lbaa;
370787c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
370887c715dcSDouglas Gilbert 	int ret;
370987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3710b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
3711b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
371240d07b52SDouglas Gilbert 	u8 *fs1p;
371387c715dcSDouglas Gilbert 	u8 *fsp;
371444d92694SMartin K. Petersen 
371567da413fSDouglas Gilbert 	write_lock(macc_lckp);
371644d92694SMartin K. Petersen 
3717f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3718f0d1cf93SDouglas Gilbert 	if (ret) {
3719f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3720f0d1cf93SDouglas Gilbert 		return ret;
3721f0d1cf93SDouglas Gilbert 	}
3722f0d1cf93SDouglas Gilbert 
37239ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
372487c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
372544d92694SMartin K. Petersen 		goto out;
372644d92694SMartin K. Petersen 	}
372740d07b52SDouglas Gilbert 	lbaa = lba;
372840d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3729c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
373087c715dcSDouglas Gilbert 	fsp = sip->storep;
373187c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3732c2248fc9SDouglas Gilbert 	if (ndob) {
373340d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3734c2248fc9SDouglas Gilbert 		ret = 0;
3735c2248fc9SDouglas Gilbert 	} else
373640d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
373744d92694SMartin K. Petersen 
373844d92694SMartin K. Petersen 	if (-1 == ret) {
373967da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3740773642d9SDouglas Gilbert 		return DID_ERROR << 16;
374140d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3742c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3743e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
374440d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
374544d92694SMartin K. Petersen 
374644d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
374740d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
374840d07b52SDouglas Gilbert 		lbaa = lba + i;
374940d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
375087c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
375140d07b52SDouglas Gilbert 	}
37529ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
375387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3754f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3755f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3756f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
375744d92694SMartin K. Petersen out:
375867da413fSDouglas Gilbert 	write_unlock(macc_lckp);
375944d92694SMartin K. Petersen 
376044d92694SMartin K. Petersen 	return 0;
376144d92694SMartin K. Petersen }
376244d92694SMartin K. Petersen 
3763fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3764fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3765c2248fc9SDouglas Gilbert {
3766c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3767c2248fc9SDouglas Gilbert 	u32 lba;
3768c2248fc9SDouglas Gilbert 	u16 num;
3769c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3770c2248fc9SDouglas Gilbert 	bool unmap = false;
3771c2248fc9SDouglas Gilbert 
3772c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3773773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3774c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3775c2248fc9SDouglas Gilbert 			return check_condition_result;
3776c2248fc9SDouglas Gilbert 		} else
3777c2248fc9SDouglas Gilbert 			unmap = true;
3778c2248fc9SDouglas Gilbert 	}
3779c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3780c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3781773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3782c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3783c2248fc9SDouglas Gilbert 		return check_condition_result;
3784c2248fc9SDouglas Gilbert 	}
3785c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3786c2248fc9SDouglas Gilbert }
3787c2248fc9SDouglas Gilbert 
3788fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3789fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3790c2248fc9SDouglas Gilbert {
3791c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3792c2248fc9SDouglas Gilbert 	u64 lba;
3793c2248fc9SDouglas Gilbert 	u32 num;
3794c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3795c2248fc9SDouglas Gilbert 	bool unmap = false;
3796c2248fc9SDouglas Gilbert 	bool ndob = false;
3797c2248fc9SDouglas Gilbert 
3798c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3799773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3800c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3801c2248fc9SDouglas Gilbert 			return check_condition_result;
3802c2248fc9SDouglas Gilbert 		} else
3803c2248fc9SDouglas Gilbert 			unmap = true;
3804c2248fc9SDouglas Gilbert 	}
3805c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3806c2248fc9SDouglas Gilbert 		ndob = true;
3807c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3808c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3809773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3810c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3811c2248fc9SDouglas Gilbert 		return check_condition_result;
3812c2248fc9SDouglas Gilbert 	}
3813c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3814c2248fc9SDouglas Gilbert }
3815c2248fc9SDouglas Gilbert 
3816acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3817acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3818acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3819fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3820fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3821acafd0b9SEwan D. Milne {
3822acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3823acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3824acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3825acafd0b9SEwan D. Milne 	u8 mode;
3826acafd0b9SEwan D. Milne 
3827acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3828acafd0b9SEwan D. Milne 	switch (mode) {
3829acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3830acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3831acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3832acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3833acafd0b9SEwan D. Milne 		break;
3834acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3835acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3836acafd0b9SEwan D. Milne 		break;
3837acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3838acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3839acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3840acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3841acafd0b9SEwan D. Milne 				    dev_list)
3842acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3843acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3844acafd0b9SEwan D. Milne 				if (devip != dp)
3845acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3846acafd0b9SEwan D. Milne 						dp->uas_bm);
3847acafd0b9SEwan D. Milne 			}
3848acafd0b9SEwan D. Milne 		break;
3849acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3850acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3851acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3852acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3853acafd0b9SEwan D. Milne 				    dev_list)
3854acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3855acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3856acafd0b9SEwan D. Milne 					dp->uas_bm);
3857acafd0b9SEwan D. Milne 		break;
3858acafd0b9SEwan D. Milne 	default:
3859acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3860acafd0b9SEwan D. Milne 		break;
3861acafd0b9SEwan D. Milne 	}
3862acafd0b9SEwan D. Milne 	return 0;
3863acafd0b9SEwan D. Milne }
3864acafd0b9SEwan D. Milne 
3865fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3866fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
386738d5c833SDouglas Gilbert {
386838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
386938d5c833SDouglas Gilbert 	u8 *arr;
3870b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3871b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
387238d5c833SDouglas Gilbert 	u64 lba;
387338d5c833SDouglas Gilbert 	u32 dnum;
3874773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
387538d5c833SDouglas Gilbert 	u8 num;
387638d5c833SDouglas Gilbert 	int ret;
3877d467d31fSDouglas Gilbert 	int retval = 0;
387838d5c833SDouglas Gilbert 
3879d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
388038d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
388138d5c833SDouglas Gilbert 	if (0 == num)
388238d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38838475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
388438d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
388538d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
388638d5c833SDouglas Gilbert 		return check_condition_result;
388738d5c833SDouglas Gilbert 	}
38888475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
38898475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
389038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
389138d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
389238d5c833SDouglas Gilbert 			    "to DIF device\n");
38939447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
38949447b6ceSMartin K. Petersen 	if (ret)
38959447b6ceSMartin K. Petersen 		return ret;
3896d467d31fSDouglas Gilbert 	dnum = 2 * num;
38976396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3898d467d31fSDouglas Gilbert 	if (NULL == arr) {
3899d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3900d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3901d467d31fSDouglas Gilbert 		return check_condition_result;
3902d467d31fSDouglas Gilbert 	}
390338d5c833SDouglas Gilbert 
390467da413fSDouglas Gilbert 	write_lock(macc_lckp);
390538d5c833SDouglas Gilbert 
390687c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
390738d5c833SDouglas Gilbert 	if (ret == -1) {
3908d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3909d467d31fSDouglas Gilbert 		goto cleanup;
3910773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
391138d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
391238d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
391338d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3914c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
391538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3916d467d31fSDouglas Gilbert 		retval = check_condition_result;
3917d467d31fSDouglas Gilbert 		goto cleanup;
391838d5c833SDouglas Gilbert 	}
391938d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
392087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3921d467d31fSDouglas Gilbert cleanup:
392267da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3923d467d31fSDouglas Gilbert 	kfree(arr);
3924d467d31fSDouglas Gilbert 	return retval;
392538d5c833SDouglas Gilbert }
392638d5c833SDouglas Gilbert 
392744d92694SMartin K. Petersen struct unmap_block_desc {
392844d92694SMartin K. Petersen 	__be64	lba;
392944d92694SMartin K. Petersen 	__be32	blocks;
393044d92694SMartin K. Petersen 	__be32	__reserved;
393144d92694SMartin K. Petersen };
393244d92694SMartin K. Petersen 
3933fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
393444d92694SMartin K. Petersen {
393544d92694SMartin K. Petersen 	unsigned char *buf;
393644d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
3937b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3938b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
393944d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
394044d92694SMartin K. Petersen 	int ret;
394144d92694SMartin K. Petersen 
3942c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3943c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3944c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3945c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
394644d92694SMartin K. Petersen 
394744d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3948773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3949c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
395044d92694SMartin K. Petersen 		return check_condition_result;
3951c2248fc9SDouglas Gilbert 	}
395244d92694SMartin K. Petersen 
3953b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3954c2248fc9SDouglas Gilbert 	if (!buf) {
3955c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3956c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3957c2248fc9SDouglas Gilbert 		return check_condition_result;
3958c2248fc9SDouglas Gilbert 	}
3959c2248fc9SDouglas Gilbert 
3960c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
396144d92694SMartin K. Petersen 
396244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
396344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
396444d92694SMartin K. Petersen 
396544d92694SMartin K. Petersen 	desc = (void *)&buf[8];
396644d92694SMartin K. Petersen 
396767da413fSDouglas Gilbert 	write_lock(macc_lckp);
39686c78cc06SAkinobu Mita 
396944d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
397044d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
397144d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
397244d92694SMartin K. Petersen 
39739447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
397444d92694SMartin K. Petersen 		if (ret)
397544d92694SMartin K. Petersen 			goto out;
397644d92694SMartin K. Petersen 
397787c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
397844d92694SMartin K. Petersen 	}
397944d92694SMartin K. Petersen 
398044d92694SMartin K. Petersen 	ret = 0;
398144d92694SMartin K. Petersen 
398244d92694SMartin K. Petersen out:
398367da413fSDouglas Gilbert 	write_unlock(macc_lckp);
398444d92694SMartin K. Petersen 	kfree(buf);
398544d92694SMartin K. Petersen 
398644d92694SMartin K. Petersen 	return ret;
398744d92694SMartin K. Petersen }
398844d92694SMartin K. Petersen 
398944d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
399044d92694SMartin K. Petersen 
3991fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3992fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
399344d92694SMartin K. Petersen {
3994c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3995c2248fc9SDouglas Gilbert 	u64 lba;
3996c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
399744d92694SMartin K. Petersen 	int ret;
399887c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
399944d92694SMartin K. Petersen 
4000c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4001c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
400244d92694SMartin K. Petersen 
400344d92694SMartin K. Petersen 	if (alloc_len < 24)
400444d92694SMartin K. Petersen 		return 0;
400544d92694SMartin K. Petersen 
40069447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
400744d92694SMartin K. Petersen 	if (ret)
400844d92694SMartin K. Petersen 		return ret;
400944d92694SMartin K. Petersen 
4010b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4011b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4012b6ff8ca7SDouglas Gilbert 
401387c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4014b6ff8ca7SDouglas Gilbert 	} else {
4015c2248fc9SDouglas Gilbert 		mapped = 1;
4016c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4017c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4018c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4019c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4020c2248fc9SDouglas Gilbert 		else
4021c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4022c2248fc9SDouglas Gilbert 	}
402344d92694SMartin K. Petersen 
402444d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4025c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4026c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4027c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4028c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
402944d92694SMartin K. Petersen 
4030c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
403144d92694SMartin K. Petersen }
403244d92694SMartin K. Petersen 
403380c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
403480c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
403580c49563SDouglas Gilbert {
40364f2c8bf6SDouglas Gilbert 	int res = 0;
403780c49563SDouglas Gilbert 	u64 lba;
403880c49563SDouglas Gilbert 	u32 num_blocks;
403980c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
404080c49563SDouglas Gilbert 
404180c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
404280c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
404380c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
404480c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
404580c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
404680c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
404780c49563SDouglas Gilbert 	}
404880c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
404980c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
405080c49563SDouglas Gilbert 		return check_condition_result;
405180c49563SDouglas Gilbert 	}
40524f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
40534f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40544f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40554f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40564f2c8bf6SDouglas Gilbert 	return res;
405780c49563SDouglas Gilbert }
405880c49563SDouglas Gilbert 
4059ed9f3e25SDouglas Gilbert /*
4060ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4061ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4062ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4063ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4064ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4065ed9f3e25SDouglas Gilbert  */
4066ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4067ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4068ed9f3e25SDouglas Gilbert {
4069ed9f3e25SDouglas Gilbert 	int res = 0;
4070ed9f3e25SDouglas Gilbert 	u64 lba;
4071ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4072ed9f3e25SDouglas Gilbert 	u32 nblks;
4073ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4074b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4075b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4076b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4077ed9f3e25SDouglas Gilbert 
4078ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4079ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4080ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4081ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4082ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4083ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4084ed9f3e25SDouglas Gilbert 	}
4085ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4086ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4087ed9f3e25SDouglas Gilbert 		return check_condition_result;
4088ed9f3e25SDouglas Gilbert 	}
4089ed9f3e25SDouglas Gilbert 	if (!fsp)
4090ed9f3e25SDouglas Gilbert 		goto fini;
4091ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4092ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4093ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4094ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4095ed9f3e25SDouglas Gilbert 
4096ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4097ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4098ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4099ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4100ed9f3e25SDouglas Gilbert 	if (rest)
4101ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4102ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4103ed9f3e25SDouglas Gilbert fini:
4104ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4105ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4106ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4107ed9f3e25SDouglas Gilbert }
4108ed9f3e25SDouglas Gilbert 
4109fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4110fb0cc8d1SDouglas Gilbert 
41118d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
41128d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
41138d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
41148d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41158d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
41168d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
41178d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
41188d039e22SDouglas Gilbert  */
41191da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
41201da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
41211da177e4SLinus Torvalds {
412201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
41238d039e22SDouglas Gilbert 	unsigned int alloc_len;
41248d039e22SDouglas Gilbert 	unsigned char select_report;
41258d039e22SDouglas Gilbert 	u64 lun;
41268d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4127fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41288d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41298d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
41308d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
41318d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4132fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4133fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4134fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41351da177e4SLinus Torvalds 
413619c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41378d039e22SDouglas Gilbert 
41388d039e22SDouglas Gilbert 	select_report = cmd[2];
41398d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41408d039e22SDouglas Gilbert 
41418d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41428d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41438d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41441da177e4SLinus Torvalds 		return check_condition_result;
41451da177e4SLinus Torvalds 	}
41468d039e22SDouglas Gilbert 
41478d039e22SDouglas Gilbert 	switch (select_report) {
41488d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4149773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41508d039e22SDouglas Gilbert 		wlun_cnt = 0;
41518d039e22SDouglas Gilbert 		break;
41528d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4153c65b1445SDouglas Gilbert 		lun_cnt = 0;
41548d039e22SDouglas Gilbert 		wlun_cnt = 1;
41558d039e22SDouglas Gilbert 		break;
41568d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41578d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41588d039e22SDouglas Gilbert 		wlun_cnt = 1;
41598d039e22SDouglas Gilbert 		break;
41608d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41618d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41628d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41638d039e22SDouglas Gilbert 	default:
41648d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41658d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41668d039e22SDouglas Gilbert 		return check_condition_result;
41678d039e22SDouglas Gilbert 	}
41688d039e22SDouglas Gilbert 
41698d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4170c65b1445SDouglas Gilbert 		--lun_cnt;
41718d039e22SDouglas Gilbert 
41728d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4173fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4174fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41758d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41768d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41778d039e22SDouglas Gilbert 
4178fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41798d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4180fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4181fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4182fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4183fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4184fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4185fb0cc8d1SDouglas Gilbert 			++lun_p;
4186fb0cc8d1SDouglas Gilbert 			j = 1;
4187fb0cc8d1SDouglas Gilbert 		}
4188fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4189fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4190fb0cc8d1SDouglas Gilbert 				break;
4191fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4192fb0cc8d1SDouglas Gilbert 		}
4193fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4194fb0cc8d1SDouglas Gilbert 			break;
4195fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4196fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4197fb0cc8d1SDouglas Gilbert 		if (res)
4198fb0cc8d1SDouglas Gilbert 			return res;
4199fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4200fb0cc8d1SDouglas Gilbert 	}
4201fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4202fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4203fb0cc8d1SDouglas Gilbert 		++j;
4204fb0cc8d1SDouglas Gilbert 	}
4205fb0cc8d1SDouglas Gilbert 	if (j > 0)
4206fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
42078d039e22SDouglas Gilbert 	return res;
42081da177e4SLinus Torvalds }
42091da177e4SLinus Torvalds 
4210c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4211c3e2fe92SDouglas Gilbert {
4212c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4213c3e2fe92SDouglas Gilbert 	u8 bytchk;
4214c3e2fe92SDouglas Gilbert 	int ret, j;
4215c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4216c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4217c3e2fe92SDouglas Gilbert 	u64 lba;
4218c3e2fe92SDouglas Gilbert 	u8 *arr;
4219c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4220b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4221b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4222c3e2fe92SDouglas Gilbert 
4223c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4224c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4225c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4226c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4227c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4228c3e2fe92SDouglas Gilbert 		return check_condition_result;
4229c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4230c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4231c3e2fe92SDouglas Gilbert 	}
4232c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4233c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4234c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4235c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4236c3e2fe92SDouglas Gilbert 		break;
4237c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4238c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4239c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4240c3e2fe92SDouglas Gilbert 		break;
4241c3e2fe92SDouglas Gilbert 	default:
4242c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4243c3e2fe92SDouglas Gilbert 		return check_condition_result;
4244c3e2fe92SDouglas Gilbert 	}
4245c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4246c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4247c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4248c3e2fe92SDouglas Gilbert 	if (ret)
4249c3e2fe92SDouglas Gilbert 		return ret;
4250c3e2fe92SDouglas Gilbert 
4251c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4252c3e2fe92SDouglas Gilbert 	if (!arr) {
4253c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4254c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4255c3e2fe92SDouglas Gilbert 		return check_condition_result;
4256c3e2fe92SDouglas Gilbert 	}
4257c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
425867da413fSDouglas Gilbert 	read_lock(macc_lckp);
4259c3e2fe92SDouglas Gilbert 
4260c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4261c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4262c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4263c3e2fe92SDouglas Gilbert 		goto cleanup;
4264c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4265c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4266c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4267c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4268c3e2fe92SDouglas Gilbert 	}
4269c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4270c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4271c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4272c3e2fe92SDouglas Gilbert 	}
4273c3e2fe92SDouglas Gilbert 	ret = 0;
4274c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4275c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4276c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4277c3e2fe92SDouglas Gilbert 		goto cleanup;
4278c3e2fe92SDouglas Gilbert 	}
4279c3e2fe92SDouglas Gilbert cleanup:
428067da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4281c3e2fe92SDouglas Gilbert 	kfree(arr);
4282c3e2fe92SDouglas Gilbert 	return ret;
4283c3e2fe92SDouglas Gilbert }
4284c3e2fe92SDouglas Gilbert 
4285f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4286f0d1cf93SDouglas Gilbert 
4287f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4288f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4289f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4290f0d1cf93SDouglas Gilbert {
4291f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4292f0d1cf93SDouglas Gilbert 	int ret = 0;
4293f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4294f0d1cf93SDouglas Gilbert 	bool partial;
4295f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4296f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4297f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4298f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4299b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4300f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4301f0d1cf93SDouglas Gilbert 
4302f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4303f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4304f0d1cf93SDouglas Gilbert 		return check_condition_result;
4305f0d1cf93SDouglas Gilbert 	}
4306f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4307f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4308f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4309f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4310f0d1cf93SDouglas Gilbert 
4311f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4312f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4313f0d1cf93SDouglas Gilbert 		return check_condition_result;
4314f0d1cf93SDouglas Gilbert 	}
4315f0d1cf93SDouglas Gilbert 
4316108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4317f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4318f0d1cf93SDouglas Gilbert 			    max_zones);
4319f0d1cf93SDouglas Gilbert 
4320f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4321f0d1cf93SDouglas Gilbert 	if (!arr) {
4322f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4323f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4324f0d1cf93SDouglas Gilbert 		return check_condition_result;
4325f0d1cf93SDouglas Gilbert 	}
4326f0d1cf93SDouglas Gilbert 
4327f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4328f0d1cf93SDouglas Gilbert 
4329f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4330f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4331f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4332f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4333f0d1cf93SDouglas Gilbert 			break;
4334f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4335f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4336f0d1cf93SDouglas Gilbert 		case 0x00:
4337f0d1cf93SDouglas Gilbert 			/* All zones */
4338f0d1cf93SDouglas Gilbert 			break;
4339f0d1cf93SDouglas Gilbert 		case 0x01:
4340f0d1cf93SDouglas Gilbert 			/* Empty zones */
4341f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4342f0d1cf93SDouglas Gilbert 				continue;
4343f0d1cf93SDouglas Gilbert 			break;
4344f0d1cf93SDouglas Gilbert 		case 0x02:
4345f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4346f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4347f0d1cf93SDouglas Gilbert 				continue;
4348f0d1cf93SDouglas Gilbert 			break;
4349f0d1cf93SDouglas Gilbert 		case 0x03:
4350f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4351f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4352f0d1cf93SDouglas Gilbert 				continue;
4353f0d1cf93SDouglas Gilbert 			break;
4354f0d1cf93SDouglas Gilbert 		case 0x04:
4355f0d1cf93SDouglas Gilbert 			/* Closed zones */
4356f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4357f0d1cf93SDouglas Gilbert 				continue;
4358f0d1cf93SDouglas Gilbert 			break;
4359f0d1cf93SDouglas Gilbert 		case 0x05:
4360f0d1cf93SDouglas Gilbert 			/* Full zones */
4361f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4362f0d1cf93SDouglas Gilbert 				continue;
4363f0d1cf93SDouglas Gilbert 			break;
4364f0d1cf93SDouglas Gilbert 		case 0x06:
4365f0d1cf93SDouglas Gilbert 		case 0x07:
4366f0d1cf93SDouglas Gilbert 		case 0x10:
4367f0d1cf93SDouglas Gilbert 			/*
436864e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
436964e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4370f0d1cf93SDouglas Gilbert 			 */
4371f0d1cf93SDouglas Gilbert 			continue;
437264e14eceSDamien Le Moal 		case 0x11:
437364e14eceSDamien Le Moal 			/* non-seq-resource set */
437464e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
437564e14eceSDamien Le Moal 				continue;
437664e14eceSDamien Le Moal 			break;
4377f0d1cf93SDouglas Gilbert 		case 0x3f:
4378f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4379f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4380f0d1cf93SDouglas Gilbert 				continue;
4381f0d1cf93SDouglas Gilbert 			break;
4382f0d1cf93SDouglas Gilbert 		default:
4383f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4384f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4385f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4386f0d1cf93SDouglas Gilbert 			goto fini;
4387f0d1cf93SDouglas Gilbert 		}
4388f0d1cf93SDouglas Gilbert 
4389f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4390f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
439164e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4392f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
439364e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
439464e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4395f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4396f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4397f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4398f0d1cf93SDouglas Gilbert 			desc += 64;
4399f0d1cf93SDouglas Gilbert 		}
4400f0d1cf93SDouglas Gilbert 
4401f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4402f0d1cf93SDouglas Gilbert 			break;
4403f0d1cf93SDouglas Gilbert 
4404f0d1cf93SDouglas Gilbert 		nrz++;
4405f0d1cf93SDouglas Gilbert 	}
4406f0d1cf93SDouglas Gilbert 
4407f0d1cf93SDouglas Gilbert 	/* Report header */
4408f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4409f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4410f0d1cf93SDouglas Gilbert 
4411f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4412f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4413f0d1cf93SDouglas Gilbert 
4414f0d1cf93SDouglas Gilbert fini:
4415f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4416f0d1cf93SDouglas Gilbert 	kfree(arr);
4417f0d1cf93SDouglas Gilbert 	return ret;
4418f0d1cf93SDouglas Gilbert }
4419f0d1cf93SDouglas Gilbert 
4420f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4421f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4422f0d1cf93SDouglas Gilbert {
4423f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4424f0d1cf93SDouglas Gilbert 	unsigned int i;
4425f0d1cf93SDouglas Gilbert 
4426f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4427f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4428f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4429f0d1cf93SDouglas Gilbert 	}
4430f0d1cf93SDouglas Gilbert }
4431f0d1cf93SDouglas Gilbert 
4432f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4433f0d1cf93SDouglas Gilbert {
4434f0d1cf93SDouglas Gilbert 	int res = 0;
4435f0d1cf93SDouglas Gilbert 	u64 z_id;
4436f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4437f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4438f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4439f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4440b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4441f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4442f0d1cf93SDouglas Gilbert 
4443f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4444f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4445f0d1cf93SDouglas Gilbert 		return check_condition_result;
4446f0d1cf93SDouglas Gilbert 	}
4447f0d1cf93SDouglas Gilbert 
4448f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4449f0d1cf93SDouglas Gilbert 
4450f0d1cf93SDouglas Gilbert 	if (all) {
4451f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4452f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4453f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4454f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4455f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4456f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4457f0d1cf93SDouglas Gilbert 			goto fini;
4458f0d1cf93SDouglas Gilbert 		}
4459f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4460f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4461f0d1cf93SDouglas Gilbert 		goto fini;
4462f0d1cf93SDouglas Gilbert 	}
4463f0d1cf93SDouglas Gilbert 
4464f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4465f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4466f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4467f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4468f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4469f0d1cf93SDouglas Gilbert 		goto fini;
4470f0d1cf93SDouglas Gilbert 	}
4471f0d1cf93SDouglas Gilbert 
4472f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4473f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4474f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4475f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4476f0d1cf93SDouglas Gilbert 		goto fini;
4477f0d1cf93SDouglas Gilbert 	}
4478f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4479f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4480f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4481f0d1cf93SDouglas Gilbert 		goto fini;
4482f0d1cf93SDouglas Gilbert 	}
4483f0d1cf93SDouglas Gilbert 
4484f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4485f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4486f0d1cf93SDouglas Gilbert 		goto fini;
4487f0d1cf93SDouglas Gilbert 
4488f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4489f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4490f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4491f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4492f0d1cf93SDouglas Gilbert 		goto fini;
4493f0d1cf93SDouglas Gilbert 	}
4494f0d1cf93SDouglas Gilbert 
4495f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
4496f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4497f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4498f0d1cf93SDouglas Gilbert fini:
4499f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4500f0d1cf93SDouglas Gilbert 	return res;
4501f0d1cf93SDouglas Gilbert }
4502f0d1cf93SDouglas Gilbert 
4503f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4504f0d1cf93SDouglas Gilbert {
4505f0d1cf93SDouglas Gilbert 	unsigned int i;
4506f0d1cf93SDouglas Gilbert 
4507f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4508f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4509f0d1cf93SDouglas Gilbert }
4510f0d1cf93SDouglas Gilbert 
4511f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4512f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4513f0d1cf93SDouglas Gilbert {
4514f0d1cf93SDouglas Gilbert 	int res = 0;
4515f0d1cf93SDouglas Gilbert 	u64 z_id;
4516f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4517f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4518f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4519b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4520f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4521f0d1cf93SDouglas Gilbert 
4522f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4523f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4524f0d1cf93SDouglas Gilbert 		return check_condition_result;
4525f0d1cf93SDouglas Gilbert 	}
4526f0d1cf93SDouglas Gilbert 
4527f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4528f0d1cf93SDouglas Gilbert 
4529f0d1cf93SDouglas Gilbert 	if (all) {
4530f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4531f0d1cf93SDouglas Gilbert 		goto fini;
4532f0d1cf93SDouglas Gilbert 	}
4533f0d1cf93SDouglas Gilbert 
4534f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4535f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4536f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4537f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4538f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4539f0d1cf93SDouglas Gilbert 		goto fini;
4540f0d1cf93SDouglas Gilbert 	}
4541f0d1cf93SDouglas Gilbert 
4542f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4543f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4544f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4545f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4546f0d1cf93SDouglas Gilbert 		goto fini;
4547f0d1cf93SDouglas Gilbert 	}
4548f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4549f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4550f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4551f0d1cf93SDouglas Gilbert 		goto fini;
4552f0d1cf93SDouglas Gilbert 	}
4553f0d1cf93SDouglas Gilbert 
4554f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4555f0d1cf93SDouglas Gilbert fini:
4556f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4557f0d1cf93SDouglas Gilbert 	return res;
4558f0d1cf93SDouglas Gilbert }
4559f0d1cf93SDouglas Gilbert 
4560f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4561f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4562f0d1cf93SDouglas Gilbert {
4563f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4564f0d1cf93SDouglas Gilbert 
4565f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4566f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4567f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4568f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4569f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4570f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4571f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4572f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4573f0d1cf93SDouglas Gilbert 	}
4574f0d1cf93SDouglas Gilbert }
4575f0d1cf93SDouglas Gilbert 
4576f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4577f0d1cf93SDouglas Gilbert {
4578f0d1cf93SDouglas Gilbert 	unsigned int i;
4579f0d1cf93SDouglas Gilbert 
4580f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4581f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4582f0d1cf93SDouglas Gilbert }
4583f0d1cf93SDouglas Gilbert 
4584f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4585f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4586f0d1cf93SDouglas Gilbert {
4587f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4588f0d1cf93SDouglas Gilbert 	int res = 0;
4589f0d1cf93SDouglas Gilbert 	u64 z_id;
4590f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4591f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4592b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4593f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4594f0d1cf93SDouglas Gilbert 
4595f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4596f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4597f0d1cf93SDouglas Gilbert 		return check_condition_result;
4598f0d1cf93SDouglas Gilbert 	}
4599f0d1cf93SDouglas Gilbert 
4600f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4601f0d1cf93SDouglas Gilbert 
4602f0d1cf93SDouglas Gilbert 	if (all) {
4603f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4604f0d1cf93SDouglas Gilbert 		goto fini;
4605f0d1cf93SDouglas Gilbert 	}
4606f0d1cf93SDouglas Gilbert 
4607f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4608f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4609f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4610f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4611f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4612f0d1cf93SDouglas Gilbert 		goto fini;
4613f0d1cf93SDouglas Gilbert 	}
4614f0d1cf93SDouglas Gilbert 
4615f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4616f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4617f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4618f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4619f0d1cf93SDouglas Gilbert 		goto fini;
4620f0d1cf93SDouglas Gilbert 	}
4621f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4622f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4623f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4624f0d1cf93SDouglas Gilbert 		goto fini;
4625f0d1cf93SDouglas Gilbert 	}
4626f0d1cf93SDouglas Gilbert 
4627f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4628f0d1cf93SDouglas Gilbert fini:
4629f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4630f0d1cf93SDouglas Gilbert 	return res;
4631f0d1cf93SDouglas Gilbert }
4632f0d1cf93SDouglas Gilbert 
4633f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4634f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4635f0d1cf93SDouglas Gilbert {
4636f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4637f0d1cf93SDouglas Gilbert 
4638f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4639f0d1cf93SDouglas Gilbert 		return;
4640f0d1cf93SDouglas Gilbert 
4641f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4642f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4643f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4644f0d1cf93SDouglas Gilbert 
4645f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4646f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4647f0d1cf93SDouglas Gilbert 
464864e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4649f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4650f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4651f0d1cf93SDouglas Gilbert }
4652f0d1cf93SDouglas Gilbert 
4653f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4654f0d1cf93SDouglas Gilbert {
4655f0d1cf93SDouglas Gilbert 	unsigned int i;
4656f0d1cf93SDouglas Gilbert 
4657f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4658f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4659f0d1cf93SDouglas Gilbert }
4660f0d1cf93SDouglas Gilbert 
4661f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4662f0d1cf93SDouglas Gilbert {
4663f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4664f0d1cf93SDouglas Gilbert 	int res = 0;
4665f0d1cf93SDouglas Gilbert 	u64 z_id;
4666f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4667f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4668b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4669f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4670f0d1cf93SDouglas Gilbert 
4671f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4672f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4673f0d1cf93SDouglas Gilbert 		return check_condition_result;
4674f0d1cf93SDouglas Gilbert 	}
4675f0d1cf93SDouglas Gilbert 
4676f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4677f0d1cf93SDouglas Gilbert 
4678f0d1cf93SDouglas Gilbert 	if (all) {
4679f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4680f0d1cf93SDouglas Gilbert 		goto fini;
4681f0d1cf93SDouglas Gilbert 	}
4682f0d1cf93SDouglas Gilbert 
4683f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4684f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4685f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4686f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4687f0d1cf93SDouglas Gilbert 		goto fini;
4688f0d1cf93SDouglas Gilbert 	}
4689f0d1cf93SDouglas Gilbert 
4690f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4691f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4692f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4693f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4694f0d1cf93SDouglas Gilbert 		goto fini;
4695f0d1cf93SDouglas Gilbert 	}
4696f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4697f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4698f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4699f0d1cf93SDouglas Gilbert 		goto fini;
4700f0d1cf93SDouglas Gilbert 	}
4701f0d1cf93SDouglas Gilbert 
4702f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4703f0d1cf93SDouglas Gilbert fini:
4704f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4705f0d1cf93SDouglas Gilbert 	return res;
4706f0d1cf93SDouglas Gilbert }
4707f0d1cf93SDouglas Gilbert 
4708c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4709c4837394SDouglas Gilbert {
4710c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
4711c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
4712c4837394SDouglas Gilbert 
4713458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4714458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4715458df78bSBart Van Assche 		hwq = 0;
4716458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4717c4837394SDouglas Gilbert }
4718c4837394SDouglas Gilbert 
4719c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4720fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47211da177e4SLinus Torvalds {
47227382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4723c4837394SDouglas Gilbert 	int qc_idx;
4724cbf67842SDouglas Gilbert 	int retiring = 0;
47251da177e4SLinus Torvalds 	unsigned long iflags;
4726c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4727cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4728cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4729cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47301da177e4SLinus Torvalds 
473110bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
47327382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47337382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4734c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4735c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4736c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4737cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4738c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4739c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4740c4837394SDouglas Gilbert 	}
4741c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4742c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47431da177e4SLinus Torvalds 		return;
47441da177e4SLinus Torvalds 	}
4745c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4746c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4747cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4748b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4749c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4750c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
4751c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
47521da177e4SLinus Torvalds 		return;
47531da177e4SLinus Torvalds 	}
4754cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4755f46eb0e9SDouglas Gilbert 	if (likely(devip))
4756cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4757cbf67842SDouglas Gilbert 	else
4758c1287970STomas Winkler 		pr_err("devip=NULL\n");
4759f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4760cbf67842SDouglas Gilbert 		retiring = 1;
4761cbf67842SDouglas Gilbert 
4762cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4763c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4764c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4765c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4766cbf67842SDouglas Gilbert 		return;
47671da177e4SLinus Torvalds 	}
47681da177e4SLinus Torvalds 
4769cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4770cbf67842SDouglas Gilbert 		int k, retval;
4771cbf67842SDouglas Gilbert 
4772cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4773c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4774c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4775c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4776cbf67842SDouglas Gilbert 			return;
4777cbf67842SDouglas Gilbert 		}
4778c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4779773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4780cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4781cbf67842SDouglas Gilbert 		else
4782cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4783cbf67842SDouglas Gilbert 	}
4784c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47857382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
47867382f9d8SDouglas Gilbert 		if (sdebug_verbose)
47877382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
47887382f9d8SDouglas Gilbert 		return;
47897382f9d8SDouglas Gilbert 	}
4790cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4791cbf67842SDouglas Gilbert }
4792cbf67842SDouglas Gilbert 
4793cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4794fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4795cbf67842SDouglas Gilbert {
4796a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4797a10bc12aSDouglas Gilbert 						  hrt);
4798a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4799cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4800cbf67842SDouglas Gilbert }
48011da177e4SLinus Torvalds 
4802a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4803fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4804a10bc12aSDouglas Gilbert {
4805a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4806a10bc12aSDouglas Gilbert 						  ew.work);
4807a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4808a10bc12aSDouglas Gilbert }
4809a10bc12aSDouglas Gilbert 
481009ba24c1SDouglas Gilbert static bool got_shared_uuid;
4811bf476433SChristoph Hellwig static uuid_t shared_uuid;
481209ba24c1SDouglas Gilbert 
4813f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4814f0d1cf93SDouglas Gilbert {
4815f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4816f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4817f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4818f0d1cf93SDouglas Gilbert 	unsigned int i;
4819f0d1cf93SDouglas Gilbert 
4820f0d1cf93SDouglas Gilbert 	/*
482198e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
482298e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4823f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4824f0d1cf93SDouglas Gilbert 	 * created for the device.
4825f0d1cf93SDouglas Gilbert 	 */
482698e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4827f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4828f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4829f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4830f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4831f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4832f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4833f0d1cf93SDouglas Gilbert 			return -EINVAL;
4834f0d1cf93SDouglas Gilbert 		}
4835f0d1cf93SDouglas Gilbert 	} else {
4836108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4837108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4838108e36f0SDamien Le Moal 			return -EINVAL;
4839108e36f0SDamien Le Moal 		}
484098e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4841f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4842f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4843f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4844f0d1cf93SDouglas Gilbert 			return -EINVAL;
4845f0d1cf93SDouglas Gilbert 		}
4846f0d1cf93SDouglas Gilbert 	}
4847f0d1cf93SDouglas Gilbert 
4848f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4849f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4850f0d1cf93SDouglas Gilbert 
4851aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4852aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4853aa8fecf9SDamien Le Moal 		return -EINVAL;
4854aa8fecf9SDamien Le Moal 	}
4855aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4856aa8fecf9SDamien Le Moal 
485764e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
485864e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4859380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4860f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4861f0d1cf93SDouglas Gilbert 		else
4862380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
486364e14eceSDamien Le Moal 	}
4864f0d1cf93SDouglas Gilbert 
4865f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4866f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4867f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4868f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4869f0d1cf93SDouglas Gilbert 
4870f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4871f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4872f0d1cf93SDouglas Gilbert 
4873f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4874f0d1cf93SDouglas Gilbert 
4875aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
487664e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4877f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4878f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4879f0d1cf93SDouglas Gilbert 		} else {
488064e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
488164e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
488264e14eceSDamien Le Moal 			else
488364e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4884f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4885f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4886f0d1cf93SDouglas Gilbert 		}
4887f0d1cf93SDouglas Gilbert 
4888f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4889f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4890f0d1cf93SDouglas Gilbert 		else
4891f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4892f0d1cf93SDouglas Gilbert 
4893f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4894f0d1cf93SDouglas Gilbert 	}
4895f0d1cf93SDouglas Gilbert 
4896f0d1cf93SDouglas Gilbert 	return 0;
4897f0d1cf93SDouglas Gilbert }
4898f0d1cf93SDouglas Gilbert 
4899fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4900fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
49015cb2fc06SFUJITA Tomonori {
49025cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
49035cb2fc06SFUJITA Tomonori 
49045cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
49055cb2fc06SFUJITA Tomonori 	if (devip) {
490609ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4907bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
490809ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
490909ba24c1SDouglas Gilbert 			if (got_shared_uuid)
491009ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
491109ba24c1SDouglas Gilbert 			else {
4912bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
491309ba24c1SDouglas Gilbert 				got_shared_uuid = true;
491409ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
491509ba24c1SDouglas Gilbert 			}
491609ba24c1SDouglas Gilbert 		}
49175cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4918f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
491964e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4920f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4921f0d1cf93SDouglas Gilbert 				kfree(devip);
4922f0d1cf93SDouglas Gilbert 				return NULL;
4923f0d1cf93SDouglas Gilbert 			}
492464e14eceSDamien Le Moal 		} else {
492564e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4926f0d1cf93SDouglas Gilbert 		}
4927f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
49285cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49295cb2fc06SFUJITA Tomonori 	}
49305cb2fc06SFUJITA Tomonori 	return devip;
49315cb2fc06SFUJITA Tomonori }
49325cb2fc06SFUJITA Tomonori 
4933f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49341da177e4SLinus Torvalds {
49351da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49361da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4937f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49381da177e4SLinus Torvalds 
4939d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49401da177e4SLinus Torvalds 	if (!sdbg_host) {
4941c1287970STomas Winkler 		pr_err("Host info NULL\n");
49421da177e4SLinus Torvalds 		return NULL;
49431da177e4SLinus Torvalds 	}
49441da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49451da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49461da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49471da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49481da177e4SLinus Torvalds 			return devip;
49491da177e4SLinus Torvalds 		else {
49501da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49511da177e4SLinus Torvalds 				open_devip = devip;
49521da177e4SLinus Torvalds 		}
49531da177e4SLinus Torvalds 	}
49545cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49555cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49565cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4957c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49581da177e4SLinus Torvalds 			return NULL;
49591da177e4SLinus Torvalds 		}
49601da177e4SLinus Torvalds 	}
4961a75869d1SFUJITA Tomonori 
49621da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
49631da177e4SLinus Torvalds 	open_devip->target = sdev->id;
49641da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
49651da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4966cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4967cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4968c2248fc9SDouglas Gilbert 	open_devip->used = true;
49691da177e4SLinus Torvalds 	return open_devip;
49701da177e4SLinus Torvalds }
49711da177e4SLinus Torvalds 
49728dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
49731da177e4SLinus Torvalds {
4974773642d9SDouglas Gilbert 	if (sdebug_verbose)
4975c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
49768dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49778dea0d02SFUJITA Tomonori 	return 0;
49788dea0d02SFUJITA Tomonori }
49791da177e4SLinus Torvalds 
49808dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
49818dea0d02SFUJITA Tomonori {
4982f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4983f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4984a34c4e98SFUJITA Tomonori 
4985773642d9SDouglas Gilbert 	if (sdebug_verbose)
4986c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
49878dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4988b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4989b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4990b01f6f83SDouglas Gilbert 	if (devip == NULL) {
4991f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
4992b01f6f83SDouglas Gilbert 		if (devip == NULL)
49938dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
4994f46eb0e9SDouglas Gilbert 	}
4995c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
4996773642d9SDouglas Gilbert 	if (sdebug_no_uld)
499778d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
49989b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
49998dea0d02SFUJITA Tomonori 	return 0;
50008dea0d02SFUJITA Tomonori }
50018dea0d02SFUJITA Tomonori 
50028dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
50038dea0d02SFUJITA Tomonori {
50048dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
50058dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
50068dea0d02SFUJITA Tomonori 
5007773642d9SDouglas Gilbert 	if (sdebug_verbose)
5008c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
50098dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50108dea0d02SFUJITA Tomonori 	if (devip) {
501125985edcSLucas De Marchi 		/* make this slot available for re-use */
5012c2248fc9SDouglas Gilbert 		devip->used = false;
50138dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
50148dea0d02SFUJITA Tomonori 	}
50158dea0d02SFUJITA Tomonori }
50168dea0d02SFUJITA Tomonori 
501710bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
501810bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5019c4837394SDouglas Gilbert {
5020c4837394SDouglas Gilbert 	if (!sd_dp)
5021c4837394SDouglas Gilbert 		return;
502210bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5023c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
502410bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5025c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5026c4837394SDouglas Gilbert }
5027c4837394SDouglas Gilbert 
5028a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5029a10bc12aSDouglas Gilbert    returns false */
5030a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50318dea0d02SFUJITA Tomonori {
50328dea0d02SFUJITA Tomonori 	unsigned long iflags;
5033c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
503410bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5035c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50368dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5037cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5038a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50398dea0d02SFUJITA Tomonori 
5040c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5041c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5042773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5043cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5044cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5045cbf67842SDouglas Gilbert 			qmax = r_qmax;
5046cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5047c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5048c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5049a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5050a10bc12aSDouglas Gilbert 					continue;
5051c4837394SDouglas Gilbert 				/* found */
5052db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5053db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5054db525fceSDouglas Gilbert 				if (devip)
5055db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5056db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5057a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
505810bde980SDouglas Gilbert 				if (sd_dp) {
505910bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
506010bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
506110bde980SDouglas Gilbert 				} else
506210bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5063c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
506410bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5065c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5066a10bc12aSDouglas Gilbert 				return true;
50678dea0d02SFUJITA Tomonori 			}
5068cbf67842SDouglas Gilbert 		}
5069c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5070c4837394SDouglas Gilbert 	}
5071a10bc12aSDouglas Gilbert 	return false;
50728dea0d02SFUJITA Tomonori }
50738dea0d02SFUJITA Tomonori 
5074a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
50758dea0d02SFUJITA Tomonori static void stop_all_queued(void)
50768dea0d02SFUJITA Tomonori {
50778dea0d02SFUJITA Tomonori 	unsigned long iflags;
5078c4837394SDouglas Gilbert 	int j, k;
507910bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5080c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50818dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5082cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5083a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50848dea0d02SFUJITA Tomonori 
5085c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5086c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5087c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5088c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5089c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5090c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5091a10bc12aSDouglas Gilbert 					continue;
5092db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5093db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5094db525fceSDouglas Gilbert 				if (devip)
5095db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5096db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5097a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
509810bde980SDouglas Gilbert 				if (sd_dp) {
509910bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
510010bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
510110bde980SDouglas Gilbert 				} else
510210bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5103c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
510410bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5105c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5106c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
51078dea0d02SFUJITA Tomonori 			}
51088dea0d02SFUJITA Tomonori 		}
5109c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5110c4837394SDouglas Gilbert 	}
5111cbf67842SDouglas Gilbert }
5112cbf67842SDouglas Gilbert 
5113cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5114cbf67842SDouglas Gilbert static void free_all_queued(void)
5115cbf67842SDouglas Gilbert {
5116c4837394SDouglas Gilbert 	int j, k;
5117c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5118cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5119cbf67842SDouglas Gilbert 
5120c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5121c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5122c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5123a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5124a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5125cbf67842SDouglas Gilbert 		}
51261da177e4SLinus Torvalds 	}
5127c4837394SDouglas Gilbert }
51281da177e4SLinus Torvalds 
51291da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51301da177e4SLinus Torvalds {
5131a10bc12aSDouglas Gilbert 	bool ok;
5132a10bc12aSDouglas Gilbert 
51331da177e4SLinus Torvalds 	++num_aborts;
5134cbf67842SDouglas Gilbert 	if (SCpnt) {
5135a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5136a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5137a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5138a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5139a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5140cbf67842SDouglas Gilbert 	}
51411da177e4SLinus Torvalds 	return SUCCESS;
51421da177e4SLinus Torvalds }
51431da177e4SLinus Torvalds 
51441da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51451da177e4SLinus Torvalds {
51461da177e4SLinus Torvalds 	++num_dev_resets;
5147cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5148cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5149f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5150f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5151cbf67842SDouglas Gilbert 
5152773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5153cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51541da177e4SLinus Torvalds 		if (devip)
5155cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51561da177e4SLinus Torvalds 	}
51571da177e4SLinus Torvalds 	return SUCCESS;
51581da177e4SLinus Torvalds }
51591da177e4SLinus Torvalds 
5160cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5161cbf67842SDouglas Gilbert {
5162cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5163cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5164cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5165cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5166cbf67842SDouglas Gilbert 	int k = 0;
5167cbf67842SDouglas Gilbert 
5168cbf67842SDouglas Gilbert 	++num_target_resets;
5169cbf67842SDouglas Gilbert 	if (!SCpnt)
5170cbf67842SDouglas Gilbert 		goto lie;
5171cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5172cbf67842SDouglas Gilbert 	if (!sdp)
5173cbf67842SDouglas Gilbert 		goto lie;
5174773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5175cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5176cbf67842SDouglas Gilbert 	hp = sdp->host;
5177cbf67842SDouglas Gilbert 	if (!hp)
5178cbf67842SDouglas Gilbert 		goto lie;
5179cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5180cbf67842SDouglas Gilbert 	if (sdbg_host) {
5181cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5182cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5183cbf67842SDouglas Gilbert 				    dev_list)
5184cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5185cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5186cbf67842SDouglas Gilbert 				++k;
5187cbf67842SDouglas Gilbert 			}
5188cbf67842SDouglas Gilbert 	}
5189773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5190cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5191cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5192cbf67842SDouglas Gilbert lie:
5193cbf67842SDouglas Gilbert 	return SUCCESS;
5194cbf67842SDouglas Gilbert }
5195cbf67842SDouglas Gilbert 
51961da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
51971da177e4SLinus Torvalds {
51981da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5199cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
52001da177e4SLinus Torvalds 	struct scsi_device *sdp;
52011da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5202cbf67842SDouglas Gilbert 	int k = 0;
52031da177e4SLinus Torvalds 
52041da177e4SLinus Torvalds 	++num_bus_resets;
5205cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5206cbf67842SDouglas Gilbert 		goto lie;
5207cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5208773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5209cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5210cbf67842SDouglas Gilbert 	hp = sdp->host;
5211cbf67842SDouglas Gilbert 	if (hp) {
5212d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52131da177e4SLinus Torvalds 		if (sdbg_host) {
5214cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
52151da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5216cbf67842SDouglas Gilbert 					    dev_list) {
5217cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5218cbf67842SDouglas Gilbert 				++k;
52191da177e4SLinus Torvalds 			}
52201da177e4SLinus Torvalds 		}
5221cbf67842SDouglas Gilbert 	}
5222773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5223cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5224cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5225cbf67842SDouglas Gilbert lie:
52261da177e4SLinus Torvalds 	return SUCCESS;
52271da177e4SLinus Torvalds }
52281da177e4SLinus Torvalds 
52291da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52301da177e4SLinus Torvalds {
52311da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5232cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5233cbf67842SDouglas Gilbert 	int k = 0;
52341da177e4SLinus Torvalds 
52351da177e4SLinus Torvalds 	++num_host_resets;
5236773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5237cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52381da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52391da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5240cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5241cbf67842SDouglas Gilbert 				    dev_list) {
5242cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5243cbf67842SDouglas Gilbert 			++k;
5244cbf67842SDouglas Gilbert 		}
52451da177e4SLinus Torvalds 	}
52461da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52471da177e4SLinus Torvalds 	stop_all_queued();
5248773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5249cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5250cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
52511da177e4SLinus Torvalds 	return SUCCESS;
52521da177e4SLinus Torvalds }
52531da177e4SLinus Torvalds 
525487c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52551da177e4SLinus Torvalds {
52561442f76dSChristoph Hellwig 	struct msdos_partition *pp;
52571da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
52581da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
52591da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
52601da177e4SLinus Torvalds 
52611da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5262773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
52631da177e4SLinus Torvalds 		return;
5264773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5265773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5266c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
52671da177e4SLinus Torvalds 	}
5268c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
52691da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5270773642d9SDouglas Gilbert 			   / sdebug_num_parts;
52711da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
52721da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5273773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
52741da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
52751da177e4SLinus Torvalds 			    * heads_by_sects;
5276773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5277773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
52781da177e4SLinus Torvalds 
52791da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
52801da177e4SLinus Torvalds 	ramp[511] = 0xAA;
52811442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
52821da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
52831da177e4SLinus Torvalds 		start_sec = starts[k];
52841da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
52851da177e4SLinus Torvalds 		pp->boot_ind = 0;
52861da177e4SLinus Torvalds 
52871da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
52881da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
52891da177e4SLinus Torvalds 			   / sdebug_sectors_per;
52901da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
52911da177e4SLinus Torvalds 
52921da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
52931da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
52941da177e4SLinus Torvalds 			       / sdebug_sectors_per;
52951da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
52961da177e4SLinus Torvalds 
5297150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5298150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
52991da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
53001da177e4SLinus Torvalds 	}
53011da177e4SLinus Torvalds }
53021da177e4SLinus Torvalds 
5303c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5304c4837394SDouglas Gilbert {
5305c4837394SDouglas Gilbert 	int j;
5306c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5307c4837394SDouglas Gilbert 
5308c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5309c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5310c4837394SDouglas Gilbert }
5311c4837394SDouglas Gilbert 
5312c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5313c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5314c4837394SDouglas Gilbert  */
5315c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5316c4837394SDouglas Gilbert {
5317c4837394SDouglas Gilbert 	int count, modulo;
5318c4837394SDouglas Gilbert 
5319c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5320c4837394SDouglas Gilbert 	if (modulo < 2)
5321c4837394SDouglas Gilbert 		return;
5322c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5323c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5324c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5325c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5326c4837394SDouglas Gilbert }
5327c4837394SDouglas Gilbert 
5328c4837394SDouglas Gilbert static void clear_queue_stats(void)
5329c4837394SDouglas Gilbert {
5330c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5331c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5332c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5333c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5334c4837394SDouglas Gilbert }
5335c4837394SDouglas Gilbert 
5336c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
5337c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
5338c4837394SDouglas Gilbert {
5339f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
5340f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
5341f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
5342f9ba7af8SMartin Wilck 				= sqcp->inj_dif
53437382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
53447382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
5345c4837394SDouglas Gilbert 		return;
5346f9ba7af8SMartin Wilck 	}
5347c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
5348c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
5349c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
5350c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
5351c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
53527ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
53537382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
5354c4837394SDouglas Gilbert }
5355c4837394SDouglas Gilbert 
5356a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5357a2aede97SDouglas Gilbert 
5358c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5359c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5360c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5361c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5362c4837394SDouglas Gilbert  */
5363fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5364f66b8517SMartin Wilck 			 int scsi_result,
5365f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5366f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5367f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
53681da177e4SLinus Torvalds {
5369a2aede97SDouglas Gilbert 	bool new_sd_dp;
5370cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
5371a2aede97SDouglas Gilbert 	unsigned long iflags;
5372a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5373c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5374c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5375299b6c07STomas Winkler 	struct scsi_device *sdp;
5376a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53771da177e4SLinus Torvalds 
5378b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5379b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5380f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5381f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
53821da177e4SLinus Torvalds 	}
5383299b6c07STomas Winkler 	sdp = cmnd->device;
5384299b6c07STomas Winkler 
5385cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5386cd62b7daSDouglas Gilbert 		goto respond_in_thread;
53871da177e4SLinus Torvalds 
5388c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5389c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5390c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5391c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5392c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5393c4837394SDouglas Gilbert 	}
5394cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5395cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5396cbf67842SDouglas Gilbert 	inject = 0;
5397f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5398cd62b7daSDouglas Gilbert 		if (scsi_result) {
5399c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5400cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5401cd62b7daSDouglas Gilbert 		} else
5402cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5403c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5404773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5405f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5406cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5407cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5408773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5409cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
5410cbf67842SDouglas Gilbert 			inject = 1;
5411cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
54121da177e4SLinus Torvalds 		}
5413cbf67842SDouglas Gilbert 	}
5414cbf67842SDouglas Gilbert 
5415c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5416f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5417c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5418cd62b7daSDouglas Gilbert 		if (scsi_result)
5419cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5420773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5421cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5422773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5423cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5424cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5425773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5426cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5427cbf67842SDouglas Gilbert 						    "report: host busy"));
5428cd62b7daSDouglas Gilbert 		if (scsi_result)
5429cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5430cd62b7daSDouglas Gilbert 		else
5431cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
54321da177e4SLinus Torvalds 	}
543374595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5434cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5435c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
54361da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5437c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5438a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5439c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5440c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
5441c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
544274595c04SDouglas Gilbert 	if (!sd_dp) {
544310bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
544474595c04SDouglas Gilbert 		if (!sd_dp) {
544574595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
544674595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
544710bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
544874595c04SDouglas Gilbert 		}
5449a2aede97SDouglas Gilbert 		new_sd_dp = true;
5450a2aede97SDouglas Gilbert 	} else {
5451a2aede97SDouglas Gilbert 		new_sd_dp = false;
545210bde980SDouglas Gilbert 	}
5453f66b8517SMartin Wilck 
5454a2aede97SDouglas Gilbert 	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
5455a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5456a2aede97SDouglas Gilbert 
5457a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
5458f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5459f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5460f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5461f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5462f66b8517SMartin Wilck 	}
5463f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5464f66b8517SMartin Wilck 		cmnd->result = scsi_result;
5465f66b8517SMartin Wilck 
5466f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5467f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5468f66b8517SMartin Wilck 			    __func__, cmnd->result);
5469f66b8517SMartin Wilck 
547010bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5471b333a819SDouglas Gilbert 		ktime_t kt;
5472cbf67842SDouglas Gilbert 
5473b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
54740c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
54750c4bc91dSDouglas Gilbert 
54760c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
54770c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
54780c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
54790c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
54800c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
54810c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
54820c4bc91dSDouglas Gilbert 				ns <<= 12;
54830c4bc91dSDouglas Gilbert 			}
54840c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
54850c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
54860c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
54870c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5488a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5489a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5490a2aede97SDouglas Gilbert 
5491a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5492a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5493a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5494a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5495a2aede97SDouglas Gilbert 					if (new_sd_dp)
5496a2aede97SDouglas Gilbert 						kfree(sd_dp);
5497a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
5498a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
5499a2aede97SDouglas Gilbert 					return 0;
5500a2aede97SDouglas Gilbert 				}
5501a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5502a2aede97SDouglas Gilbert 				kt -= d;
5503a2aede97SDouglas Gilbert 			}
55040c4bc91dSDouglas Gilbert 		}
550510bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
550610bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
5507a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5508a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5509c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
5510a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5511c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5512c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5513cbf67842SDouglas Gilbert 		}
5514c4837394SDouglas Gilbert 		if (sdebug_statistics)
5515c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
551610bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
5517a2aede97SDouglas Gilbert 		/* schedule the invocation of scsi_done() for a later time */
5518c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
5519c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
552010bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
552110bde980SDouglas Gilbert 			sd_dp->init_wq = true;
5522a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5523c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5524c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5525a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5526cbf67842SDouglas Gilbert 		}
5527c4837394SDouglas Gilbert 		if (sdebug_statistics)
5528c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
552910bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
55307382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
55317382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
5532a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
55337382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
55347382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
55357382f9d8SDouglas Gilbert 				    cmnd->request->tag);
55367382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
55377382f9d8SDouglas Gilbert 		}
5538cbf67842SDouglas Gilbert 	}
5539f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
5540f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
5541cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5542cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
5543cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
5544cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
55451da177e4SLinus Torvalds 	return 0;
5546cd62b7daSDouglas Gilbert 
5547cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5548f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5549f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5550f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5551cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
5552cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
5553cd62b7daSDouglas Gilbert 	return 0;
55541da177e4SLinus Torvalds }
5555cbf67842SDouglas Gilbert 
555623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
555723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
555823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
555923183910SDouglas Gilbert    as it can when the corresponding attribute in the
556023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
556123183910SDouglas Gilbert  */
5562773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5563773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
55649b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5565773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5566c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5567773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5568773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5569773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5570773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5571773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5572773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5573773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5574773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5575e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5576e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5577e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5578e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
55795d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
55805d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
55815d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5582773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5583773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5584773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5585773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5586773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5587773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
55885d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
55895d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
55905d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
55915d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5592773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5593773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5594773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5595773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5596773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5597773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
55985d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5599773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
560087c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
560187c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5602773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5603773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
56040c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5605773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5606773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5607773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5608c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5609773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5610c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5611773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5612773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5613773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5614773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
561509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
56165d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5617773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
561823183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56199447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5620773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
56215b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
56229267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5623380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5624aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
562598e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56261da177e4SLinus Torvalds 
56271da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56281da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
56291da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5630b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
56311da177e4SLinus Torvalds 
56325d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56335b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56349b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56350759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5636cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5637c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
56385b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
56395b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5640c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5641beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
564223183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
56435b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5644185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5645e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
56469b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
56479b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
56485d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
56495d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
56505d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
56515b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
56525b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
56535b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
56545b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5655c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5656cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5657d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
56585d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5659cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5660c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
566178d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
56621da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5663c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
566432c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
566586e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
56665d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
56675d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
56685d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
56691da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
56700c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5671d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5672760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5673ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5674c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5675c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5676c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
56775b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
56785b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
56796014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
56806014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
568109ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
568209ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5683c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
56845b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
56859447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
56865b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
56879267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5688380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5689aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
569098e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
56911da177e4SLinus Torvalds 
5692760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5693760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
56941da177e4SLinus Torvalds 
56951da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
56961da177e4SLinus Torvalds {
5697c4837394SDouglas Gilbert 	int k;
5698c4837394SDouglas Gilbert 
5699760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5700760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5701760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5702c4837394SDouglas Gilbert 		return sdebug_info;
5703760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5704760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5705760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5706760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
57071da177e4SLinus Torvalds 	return sdebug_info;
57081da177e4SLinus Torvalds }
57091da177e4SLinus Torvalds 
5710cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5711fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5712fd32119bSDouglas Gilbert 				 int length)
57131da177e4SLinus Torvalds {
57141da177e4SLinus Torvalds 	char arr[16];
5715c8ed555aSAl Viro 	int opts;
57161da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
57171da177e4SLinus Torvalds 
57181da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
57191da177e4SLinus Torvalds 		return -EACCES;
57201da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
57211da177e4SLinus Torvalds 	arr[minLen] = '\0';
5722c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
57231da177e4SLinus Torvalds 		return -EINVAL;
5724773642d9SDouglas Gilbert 	sdebug_opts = opts;
5725773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5726773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5727773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5728c4837394SDouglas Gilbert 		tweak_cmnd_count();
57291da177e4SLinus Torvalds 	return length;
57301da177e4SLinus Torvalds }
5731c8ed555aSAl Viro 
5732cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5733cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5734cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5735c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5736c8ed555aSAl Viro {
5737c4837394SDouglas Gilbert 	int f, j, l;
5738c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
573987c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5740cbf67842SDouglas Gilbert 
5741c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5742c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5743c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5744c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5745c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5746c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5747c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5748c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5749c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5750c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5751c4837394SDouglas Gilbert 		   num_aborts);
5752c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5753c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5754c4837394SDouglas Gilbert 		   num_host_resets);
5755c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5756c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5757458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5758458df78bSBart Van Assche 		   sdebug_statistics);
5759c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
5760c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5761c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5762c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
5763c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
5764cbf67842SDouglas Gilbert 
5765c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5766c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5767c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5768c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5769773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5770c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5771c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5772c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5773c4837394SDouglas Gilbert 		}
5774cbf67842SDouglas Gilbert 	}
577587c715dcSDouglas Gilbert 
577687c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
577787c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
577887c715dcSDouglas Gilbert 		bool niu;
577987c715dcSDouglas Gilbert 		int idx;
578087c715dcSDouglas Gilbert 		unsigned long l_idx;
578187c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
578287c715dcSDouglas Gilbert 
578387c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
578487c715dcSDouglas Gilbert 		j = 0;
578587c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
578687c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
578787c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
578887c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
578987c715dcSDouglas Gilbert 			++j;
579087c715dcSDouglas Gilbert 		}
579187c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
579287c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
579387c715dcSDouglas Gilbert 		j = 0;
579487c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
579587c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
579687c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
579787c715dcSDouglas Gilbert 			idx = (int)l_idx;
579887c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
579987c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
580087c715dcSDouglas Gilbert 			++j;
580187c715dcSDouglas Gilbert 		}
580287c715dcSDouglas Gilbert 	}
5803c8ed555aSAl Viro 	return 0;
58041da177e4SLinus Torvalds }
58051da177e4SLinus Torvalds 
580682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
58071da177e4SLinus Torvalds {
5808c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
58091da177e4SLinus Torvalds }
5810c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5811c4837394SDouglas Gilbert  * of delay is jiffies.
5812c4837394SDouglas Gilbert  */
581382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
581482069379SAkinobu Mita 			   size_t count)
58151da177e4SLinus Torvalds {
5816c2206098SDouglas Gilbert 	int jdelay, res;
58171da177e4SLinus Torvalds 
5818b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5819cbf67842SDouglas Gilbert 		res = count;
5820c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5821c4837394SDouglas Gilbert 			int j, k;
5822c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5823cbf67842SDouglas Gilbert 
5824c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5825c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5826c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5827c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5828c4837394SDouglas Gilbert 						   sdebug_max_queue);
5829c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5830c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5831c4837394SDouglas Gilbert 					break;
5832c4837394SDouglas Gilbert 				}
5833c4837394SDouglas Gilbert 			}
5834c4837394SDouglas Gilbert 			if (res > 0) {
5835c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5836773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
58371da177e4SLinus Torvalds 			}
5838c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5839cbf67842SDouglas Gilbert 		}
5840cbf67842SDouglas Gilbert 		return res;
58411da177e4SLinus Torvalds 	}
58421da177e4SLinus Torvalds 	return -EINVAL;
58431da177e4SLinus Torvalds }
584482069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
58451da177e4SLinus Torvalds 
5846cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5847cbf67842SDouglas Gilbert {
5848773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5849cbf67842SDouglas Gilbert }
5850cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5851c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5852cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5853cbf67842SDouglas Gilbert 			    size_t count)
5854cbf67842SDouglas Gilbert {
5855c4837394SDouglas Gilbert 	int ndelay, res;
5856cbf67842SDouglas Gilbert 
5857cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5858c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5859cbf67842SDouglas Gilbert 		res = count;
5860773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5861c4837394SDouglas Gilbert 			int j, k;
5862c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5863c4837394SDouglas Gilbert 
5864c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5865c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5866c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5867c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5868c4837394SDouglas Gilbert 						   sdebug_max_queue);
5869c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5870c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5871c4837394SDouglas Gilbert 					break;
5872c4837394SDouglas Gilbert 				}
5873c4837394SDouglas Gilbert 			}
5874c4837394SDouglas Gilbert 			if (res > 0) {
5875773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5876c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5877c2206098SDouglas Gilbert 							: DEF_JDELAY;
5878cbf67842SDouglas Gilbert 			}
5879c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5880cbf67842SDouglas Gilbert 		}
5881cbf67842SDouglas Gilbert 		return res;
5882cbf67842SDouglas Gilbert 	}
5883cbf67842SDouglas Gilbert 	return -EINVAL;
5884cbf67842SDouglas Gilbert }
5885cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5886cbf67842SDouglas Gilbert 
588782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
58881da177e4SLinus Torvalds {
5889773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
58901da177e4SLinus Torvalds }
58911da177e4SLinus Torvalds 
589282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
589382069379SAkinobu Mita 			  size_t count)
58941da177e4SLinus Torvalds {
58951da177e4SLinus Torvalds 	int opts;
58961da177e4SLinus Torvalds 	char work[20];
58971da177e4SLinus Torvalds 
58989a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
58999a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
59009a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
59011da177e4SLinus Torvalds 				goto opts_done;
59021da177e4SLinus Torvalds 		} else {
59039a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
59041da177e4SLinus Torvalds 				goto opts_done;
59051da177e4SLinus Torvalds 		}
59061da177e4SLinus Torvalds 	}
59071da177e4SLinus Torvalds 	return -EINVAL;
59081da177e4SLinus Torvalds opts_done:
5909773642d9SDouglas Gilbert 	sdebug_opts = opts;
5910773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5911773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5912c4837394SDouglas Gilbert 	tweak_cmnd_count();
59131da177e4SLinus Torvalds 	return count;
59141da177e4SLinus Torvalds }
591582069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
59161da177e4SLinus Torvalds 
591782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
59181da177e4SLinus Torvalds {
5919773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
59201da177e4SLinus Torvalds }
592182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
592282069379SAkinobu Mita 			   size_t count)
59231da177e4SLinus Torvalds {
59241da177e4SLinus Torvalds 	int n;
59251da177e4SLinus Torvalds 
5926f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5927f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5928f0d1cf93SDouglas Gilbert 		return -EINVAL;
5929f0d1cf93SDouglas Gilbert 
59301da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5931f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
5932f0d1cf93SDouglas Gilbert 			return -EINVAL;
5933773642d9SDouglas Gilbert 		sdebug_ptype = n;
59341da177e4SLinus Torvalds 		return count;
59351da177e4SLinus Torvalds 	}
59361da177e4SLinus Torvalds 	return -EINVAL;
59371da177e4SLinus Torvalds }
593882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
59391da177e4SLinus Torvalds 
594082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
59411da177e4SLinus Torvalds {
5942773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
59431da177e4SLinus Torvalds }
594482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
594582069379SAkinobu Mita 			    size_t count)
59461da177e4SLinus Torvalds {
59471da177e4SLinus Torvalds 	int n;
59481da177e4SLinus Torvalds 
59491da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5950773642d9SDouglas Gilbert 		sdebug_dsense = n;
59511da177e4SLinus Torvalds 		return count;
59521da177e4SLinus Torvalds 	}
59531da177e4SLinus Torvalds 	return -EINVAL;
59541da177e4SLinus Torvalds }
595582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
59561da177e4SLinus Torvalds 
595782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
595823183910SDouglas Gilbert {
5959773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
596023183910SDouglas Gilbert }
596182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
596282069379SAkinobu Mita 			     size_t count)
596323183910SDouglas Gilbert {
596487c715dcSDouglas Gilbert 	int n, idx;
596523183910SDouglas Gilbert 
596623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
596787c715dcSDouglas Gilbert 		bool want_store = (n == 0);
596887c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
596987c715dcSDouglas Gilbert 
5970cbf67842SDouglas Gilbert 		n = (n > 0);
5971773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
597287c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
597387c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
5974cbf67842SDouglas Gilbert 
597587c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
597687c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
597787c715dcSDouglas Gilbert 				idx = sdebug_add_store();
597887c715dcSDouglas Gilbert 				if (idx < 0)
597987c715dcSDouglas Gilbert 					return idx;
598087c715dcSDouglas Gilbert 			} else {
598187c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
598287c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
598387c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
5984cbf67842SDouglas Gilbert 			}
598587c715dcSDouglas Gilbert 			/* make all hosts use same store */
598687c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
598787c715dcSDouglas Gilbert 					    host_list) {
598887c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
598987c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
599087c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
599187c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
599287c715dcSDouglas Gilbert 				}
599387c715dcSDouglas Gilbert 			}
599487c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
599587c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
599687c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
5997cbf67842SDouglas Gilbert 		}
5998773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
599923183910SDouglas Gilbert 		return count;
600023183910SDouglas Gilbert 	}
600123183910SDouglas Gilbert 	return -EINVAL;
600223183910SDouglas Gilbert }
600382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
600423183910SDouglas Gilbert 
600582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6006c65b1445SDouglas Gilbert {
6007773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6008c65b1445SDouglas Gilbert }
600982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
601082069379SAkinobu Mita 			      size_t count)
6011c65b1445SDouglas Gilbert {
6012c65b1445SDouglas Gilbert 	int n;
6013c65b1445SDouglas Gilbert 
6014c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6015773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6016c65b1445SDouglas Gilbert 		return count;
6017c65b1445SDouglas Gilbert 	}
6018c65b1445SDouglas Gilbert 	return -EINVAL;
6019c65b1445SDouglas Gilbert }
602082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6021c65b1445SDouglas Gilbert 
602282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
60231da177e4SLinus Torvalds {
6024773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60251da177e4SLinus Torvalds }
602682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
602782069379SAkinobu Mita 			      size_t count)
60281da177e4SLinus Torvalds {
60291da177e4SLinus Torvalds 	int n;
60301da177e4SLinus Torvalds 
60311da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6032773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
60331da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
60341da177e4SLinus Torvalds 		return count;
60351da177e4SLinus Torvalds 	}
60361da177e4SLinus Torvalds 	return -EINVAL;
60371da177e4SLinus Torvalds }
603882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
60391da177e4SLinus Torvalds 
604082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
60411da177e4SLinus Torvalds {
6042773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
60431da177e4SLinus Torvalds }
604482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
60451da177e4SLinus Torvalds 
604687c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
604787c715dcSDouglas Gilbert {
604887c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
604987c715dcSDouglas Gilbert }
605087c715dcSDouglas Gilbert 
605187c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
605287c715dcSDouglas Gilbert 				    size_t count)
605387c715dcSDouglas Gilbert {
605487c715dcSDouglas Gilbert 	bool v;
605587c715dcSDouglas Gilbert 
605687c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
605787c715dcSDouglas Gilbert 		return -EINVAL;
605887c715dcSDouglas Gilbert 
605987c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
606087c715dcSDouglas Gilbert 	return count;
606187c715dcSDouglas Gilbert }
606287c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
606387c715dcSDouglas Gilbert 
606482069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
60651da177e4SLinus Torvalds {
6066773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
60671da177e4SLinus Torvalds }
606882069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
60691da177e4SLinus Torvalds 
607082069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
60711da177e4SLinus Torvalds {
6072773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
60731da177e4SLinus Torvalds }
607482069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
607582069379SAkinobu Mita 			       size_t count)
60761da177e4SLinus Torvalds {
60771da177e4SLinus Torvalds 	int nth;
60781da177e4SLinus Torvalds 
60791da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
6080773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
6081c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
6082c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
6083c4837394SDouglas Gilbert 			sdebug_statistics = true;
6084c4837394SDouglas Gilbert 		}
6085c4837394SDouglas Gilbert 		tweak_cmnd_count();
60861da177e4SLinus Torvalds 		return count;
60871da177e4SLinus Torvalds 	}
60881da177e4SLinus Torvalds 	return -EINVAL;
60891da177e4SLinus Torvalds }
609082069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
60911da177e4SLinus Torvalds 
609282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
60931da177e4SLinus Torvalds {
6094773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
60951da177e4SLinus Torvalds }
609682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
609782069379SAkinobu Mita 			      size_t count)
60981da177e4SLinus Torvalds {
60991da177e4SLinus Torvalds 	int n;
610019c8ead7SEwan D. Milne 	bool changed;
61011da177e4SLinus Torvalds 
61021da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
61038d039e22SDouglas Gilbert 		if (n > 256) {
61048d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
61058d039e22SDouglas Gilbert 			return -EINVAL;
61068d039e22SDouglas Gilbert 		}
6107773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6108773642d9SDouglas Gilbert 		sdebug_max_luns = n;
61091da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6110773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
611119c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
611219c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
611319c8ead7SEwan D. Milne 
611419c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
611519c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
611619c8ead7SEwan D. Milne 					    host_list) {
611719c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
611819c8ead7SEwan D. Milne 						    dev_list) {
611919c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
612019c8ead7SEwan D. Milne 						dp->uas_bm);
612119c8ead7SEwan D. Milne 				}
612219c8ead7SEwan D. Milne 			}
612319c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
612419c8ead7SEwan D. Milne 		}
61251da177e4SLinus Torvalds 		return count;
61261da177e4SLinus Torvalds 	}
61271da177e4SLinus Torvalds 	return -EINVAL;
61281da177e4SLinus Torvalds }
612982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
61301da177e4SLinus Torvalds 
613182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
613278d4e5a0SDouglas Gilbert {
6133773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
613478d4e5a0SDouglas Gilbert }
6135cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6136cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
613782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
613882069379SAkinobu Mita 			       size_t count)
613978d4e5a0SDouglas Gilbert {
6140c4837394SDouglas Gilbert 	int j, n, k, a;
6141c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
614278d4e5a0SDouglas Gilbert 
614378d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6144c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
6145c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6146c4837394SDouglas Gilbert 		k = 0;
6147c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6148c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6149c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6150c4837394SDouglas Gilbert 			if (a > k)
6151c4837394SDouglas Gilbert 				k = a;
6152c4837394SDouglas Gilbert 		}
6153773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6154c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6155cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6156cbf67842SDouglas Gilbert 		else if (k >= n)
6157cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6158cbf67842SDouglas Gilbert 		else
6159cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6160c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
616178d4e5a0SDouglas Gilbert 		return count;
616278d4e5a0SDouglas Gilbert 	}
616378d4e5a0SDouglas Gilbert 	return -EINVAL;
616478d4e5a0SDouglas Gilbert }
616582069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
616678d4e5a0SDouglas Gilbert 
616782069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
616878d4e5a0SDouglas Gilbert {
6169773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
617078d4e5a0SDouglas Gilbert }
617182069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
617278d4e5a0SDouglas Gilbert 
617382069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
61741da177e4SLinus Torvalds {
6175773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
61761da177e4SLinus Torvalds }
617782069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
61781da177e4SLinus Torvalds 
617982069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6180c65b1445SDouglas Gilbert {
6181773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6182c65b1445SDouglas Gilbert }
618382069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
618482069379SAkinobu Mita 				size_t count)
6185c65b1445SDouglas Gilbert {
6186c65b1445SDouglas Gilbert 	int n;
61870d01c5dfSDouglas Gilbert 	bool changed;
6188c65b1445SDouglas Gilbert 
6189f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6190f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6191f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6192f0d1cf93SDouglas Gilbert 
6193c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6194773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6195773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
619628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
61970d01c5dfSDouglas Gilbert 		if (changed) {
61980d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
61990d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
620028898873SFUJITA Tomonori 
62014bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
62020d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
62030d01c5dfSDouglas Gilbert 					    host_list) {
62040d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
62050d01c5dfSDouglas Gilbert 						    dev_list) {
62060d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
62070d01c5dfSDouglas Gilbert 						dp->uas_bm);
62080d01c5dfSDouglas Gilbert 				}
62090d01c5dfSDouglas Gilbert 			}
62104bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
62110d01c5dfSDouglas Gilbert 		}
6212c65b1445SDouglas Gilbert 		return count;
6213c65b1445SDouglas Gilbert 	}
6214c65b1445SDouglas Gilbert 	return -EINVAL;
6215c65b1445SDouglas Gilbert }
621682069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6217c65b1445SDouglas Gilbert 
621882069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
62191da177e4SLinus Torvalds {
622087c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
622187c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
62221da177e4SLinus Torvalds }
62231da177e4SLinus Torvalds 
622482069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
622582069379SAkinobu Mita 			      size_t count)
62261da177e4SLinus Torvalds {
622787c715dcSDouglas Gilbert 	bool found;
622887c715dcSDouglas Gilbert 	unsigned long idx;
622987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
623087c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
62311da177e4SLinus Torvalds 	int delta_hosts;
62321da177e4SLinus Torvalds 
6233f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
62341da177e4SLinus Torvalds 		return -EINVAL;
62351da177e4SLinus Torvalds 	if (delta_hosts > 0) {
62361da177e4SLinus Torvalds 		do {
623787c715dcSDouglas Gilbert 			found = false;
623887c715dcSDouglas Gilbert 			if (want_phs) {
623987c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
624087c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
624187c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
624287c715dcSDouglas Gilbert 					found = true;
624387c715dcSDouglas Gilbert 					break;
624487c715dcSDouglas Gilbert 				}
624587c715dcSDouglas Gilbert 				if (found)	/* re-use case */
624687c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
624787c715dcSDouglas Gilbert 				else
624887c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
624987c715dcSDouglas Gilbert 			} else {
625087c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
625187c715dcSDouglas Gilbert 			}
62521da177e4SLinus Torvalds 		} while (--delta_hosts);
62531da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
62541da177e4SLinus Torvalds 		do {
625587c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
62561da177e4SLinus Torvalds 		} while (++delta_hosts);
62571da177e4SLinus Torvalds 	}
62581da177e4SLinus Torvalds 	return count;
62591da177e4SLinus Torvalds }
626082069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
62611da177e4SLinus Torvalds 
626282069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
626323183910SDouglas Gilbert {
6264773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
626523183910SDouglas Gilbert }
626682069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
626782069379SAkinobu Mita 				    size_t count)
626823183910SDouglas Gilbert {
626923183910SDouglas Gilbert 	int n;
627023183910SDouglas Gilbert 
627123183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6272773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
627323183910SDouglas Gilbert 		return count;
627423183910SDouglas Gilbert 	}
627523183910SDouglas Gilbert 	return -EINVAL;
627623183910SDouglas Gilbert }
627782069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
627823183910SDouglas Gilbert 
6279c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6280c4837394SDouglas Gilbert {
6281c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6282c4837394SDouglas Gilbert }
6283c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6284c4837394SDouglas Gilbert 				size_t count)
6285c4837394SDouglas Gilbert {
6286c4837394SDouglas Gilbert 	int n;
6287c4837394SDouglas Gilbert 
6288c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6289c4837394SDouglas Gilbert 		if (n > 0)
6290c4837394SDouglas Gilbert 			sdebug_statistics = true;
6291c4837394SDouglas Gilbert 		else {
6292c4837394SDouglas Gilbert 			clear_queue_stats();
6293c4837394SDouglas Gilbert 			sdebug_statistics = false;
6294c4837394SDouglas Gilbert 		}
6295c4837394SDouglas Gilbert 		return count;
6296c4837394SDouglas Gilbert 	}
6297c4837394SDouglas Gilbert 	return -EINVAL;
6298c4837394SDouglas Gilbert }
6299c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6300c4837394SDouglas Gilbert 
630182069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6302597136abSMartin K. Petersen {
6303773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6304597136abSMartin K. Petersen }
630582069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6306597136abSMartin K. Petersen 
6307c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6308c4837394SDouglas Gilbert {
6309c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6310c4837394SDouglas Gilbert }
6311c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6312c4837394SDouglas Gilbert 
631382069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6314c6a44287SMartin K. Petersen {
6315773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6316c6a44287SMartin K. Petersen }
631782069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6318c6a44287SMartin K. Petersen 
631982069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6320c6a44287SMartin K. Petersen {
6321773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6322c6a44287SMartin K. Petersen }
632382069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6324c6a44287SMartin K. Petersen 
632582069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6326c6a44287SMartin K. Petersen {
6327773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6328c6a44287SMartin K. Petersen }
632982069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6330c6a44287SMartin K. Petersen 
633182069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6332c6a44287SMartin K. Petersen {
6333773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6334c6a44287SMartin K. Petersen }
633582069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6336c6a44287SMartin K. Petersen 
633782069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
633844d92694SMartin K. Petersen {
633987c715dcSDouglas Gilbert 	ssize_t count = 0;
634044d92694SMartin K. Petersen 
63415b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
634244d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
634344d92694SMartin K. Petersen 				 sdebug_store_sectors);
634444d92694SMartin K. Petersen 
634587c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
634687c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
634787c715dcSDouglas Gilbert 
634887c715dcSDouglas Gilbert 		if (sip)
6349c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
635087c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
635187c715dcSDouglas Gilbert 	}
635244d92694SMartin K. Petersen 	buf[count++] = '\n';
6353c7badc90STejun Heo 	buf[count] = '\0';
635444d92694SMartin K. Petersen 
635544d92694SMartin K. Petersen 	return count;
635644d92694SMartin K. Petersen }
635782069379SAkinobu Mita static DRIVER_ATTR_RO(map);
635844d92694SMartin K. Petersen 
63590c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
63600c4bc91dSDouglas Gilbert {
63610c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
63620c4bc91dSDouglas Gilbert }
63630c4bc91dSDouglas Gilbert 
63640c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
63650c4bc91dSDouglas Gilbert 			    size_t count)
63660c4bc91dSDouglas Gilbert {
63670c4bc91dSDouglas Gilbert 	bool v;
63680c4bc91dSDouglas Gilbert 
63690c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
63700c4bc91dSDouglas Gilbert 		return -EINVAL;
63710c4bc91dSDouglas Gilbert 
63720c4bc91dSDouglas Gilbert 	sdebug_random = v;
63730c4bc91dSDouglas Gilbert 	return count;
63740c4bc91dSDouglas Gilbert }
63750c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
63760c4bc91dSDouglas Gilbert 
637782069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6378d986788bSMartin Pitt {
6379773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6380d986788bSMartin Pitt }
638182069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
638282069379SAkinobu Mita 			       size_t count)
6383d986788bSMartin Pitt {
6384d986788bSMartin Pitt 	int n;
6385d986788bSMartin Pitt 
6386d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6387773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6388d986788bSMartin Pitt 		return count;
6389d986788bSMartin Pitt 	}
6390d986788bSMartin Pitt 	return -EINVAL;
6391d986788bSMartin Pitt }
639282069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6393d986788bSMartin Pitt 
6394cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6395cbf67842SDouglas Gilbert {
6396773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6397cbf67842SDouglas Gilbert }
6398185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6399cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6400cbf67842SDouglas Gilbert 			       size_t count)
6401cbf67842SDouglas Gilbert {
6402185dd232SDouglas Gilbert 	int n;
6403cbf67842SDouglas Gilbert 
6404cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6405185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6406185dd232SDouglas Gilbert 		return count;
6407cbf67842SDouglas Gilbert 	}
6408cbf67842SDouglas Gilbert 	return -EINVAL;
6409cbf67842SDouglas Gilbert }
6410cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6411cbf67842SDouglas Gilbert 
6412c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6413c2248fc9SDouglas Gilbert {
6414773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6415c2248fc9SDouglas Gilbert }
6416c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6417c2248fc9SDouglas Gilbert 			    size_t count)
6418c2248fc9SDouglas Gilbert {
6419c2248fc9SDouglas Gilbert 	int n;
6420c2248fc9SDouglas Gilbert 
6421c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6422773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6423c2248fc9SDouglas Gilbert 		return count;
6424c2248fc9SDouglas Gilbert 	}
6425c2248fc9SDouglas Gilbert 	return -EINVAL;
6426c2248fc9SDouglas Gilbert }
6427c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6428c2248fc9SDouglas Gilbert 
642909ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
643009ba24c1SDouglas Gilbert {
643109ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
643209ba24c1SDouglas Gilbert }
643309ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
643409ba24c1SDouglas Gilbert 
64359b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
64369b760fd8SDouglas Gilbert {
64379b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
64389b760fd8SDouglas Gilbert }
64399b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
64409b760fd8SDouglas Gilbert 			     size_t count)
64419b760fd8SDouglas Gilbert {
64429b760fd8SDouglas Gilbert 	int ret, n;
64439b760fd8SDouglas Gilbert 
64449b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
64459b760fd8SDouglas Gilbert 	if (ret)
64469b760fd8SDouglas Gilbert 		return ret;
64479b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
64489b760fd8SDouglas Gilbert 	all_config_cdb_len();
64499b760fd8SDouglas Gilbert 	return count;
64509b760fd8SDouglas Gilbert }
64519b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
64529b760fd8SDouglas Gilbert 
64539267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
64549267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
64559267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
64569267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
64579267e0ebSDouglas Gilbert };
64589267e0ebSDouglas Gilbert 
64599267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
64609267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
64619267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
64629267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
64639267e0ebSDouglas Gilbert };
64649267e0ebSDouglas Gilbert 
64659267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
64669267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
64679267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
64689267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
64699267e0ebSDouglas Gilbert };
64709267e0ebSDouglas Gilbert 
64719267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
64729267e0ebSDouglas Gilbert {
64739267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
64749267e0ebSDouglas Gilbert 
64759267e0ebSDouglas Gilbert 	if (res < 0) {
64769267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
64779267e0ebSDouglas Gilbert 		if (res < 0) {
64789267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
647947742bdeSDan Carpenter 			if (res < 0)
64809267e0ebSDouglas Gilbert 				return -EINVAL;
64819267e0ebSDouglas Gilbert 		}
64829267e0ebSDouglas Gilbert 	}
64839267e0ebSDouglas Gilbert 	return res;
64849267e0ebSDouglas Gilbert }
64859267e0ebSDouglas Gilbert 
64869267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
64879267e0ebSDouglas Gilbert {
64889267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
64899267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
64909267e0ebSDouglas Gilbert }
64919267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6492cbf67842SDouglas Gilbert 
649382069379SAkinobu Mita /* Note: The following array creates attribute files in the
649423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
649523183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
649623183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
649787c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
649823183910SDouglas Gilbert  */
64996ecaff7fSRandy Dunlap 
650082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
650182069379SAkinobu Mita 	&driver_attr_delay.attr,
650282069379SAkinobu Mita 	&driver_attr_opts.attr,
650382069379SAkinobu Mita 	&driver_attr_ptype.attr,
650482069379SAkinobu Mita 	&driver_attr_dsense.attr,
650582069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
650682069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
650782069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
650882069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
650982069379SAkinobu Mita 	&driver_attr_num_parts.attr,
651082069379SAkinobu Mita 	&driver_attr_every_nth.attr,
651182069379SAkinobu Mita 	&driver_attr_max_luns.attr,
651282069379SAkinobu Mita 	&driver_attr_max_queue.attr,
651382069379SAkinobu Mita 	&driver_attr_no_uld.attr,
651482069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
651582069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
651682069379SAkinobu Mita 	&driver_attr_add_host.attr,
651787c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
651882069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
651982069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6520c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6521c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
652282069379SAkinobu Mita 	&driver_attr_dix.attr,
652382069379SAkinobu Mita 	&driver_attr_dif.attr,
652482069379SAkinobu Mita 	&driver_attr_guard.attr,
652582069379SAkinobu Mita 	&driver_attr_ato.attr,
652682069379SAkinobu Mita 	&driver_attr_map.attr,
65270c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
652882069379SAkinobu Mita 	&driver_attr_removable.attr,
6529cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6530cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6531c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
653209ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
65339b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
65349267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
653582069379SAkinobu Mita 	NULL,
653682069379SAkinobu Mita };
653782069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
65381da177e4SLinus Torvalds 
653911ddcecaSAkinobu Mita static struct device *pseudo_primary;
65408dea0d02SFUJITA Tomonori 
65411da177e4SLinus Torvalds static int __init scsi_debug_init(void)
65421da177e4SLinus Torvalds {
654387c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
65445f2578e5SFUJITA Tomonori 	unsigned long sz;
654587c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
654687c715dcSDouglas Gilbert 	int idx = -1;
65471da177e4SLinus Torvalds 
654887c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
654987c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6550cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6551cbf67842SDouglas Gilbert 
6552773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6553c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6554773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6555773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6556c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6557cbf67842SDouglas Gilbert 
6558773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6559597136abSMartin K. Petersen 	case  512:
6560597136abSMartin K. Petersen 	case 1024:
6561597136abSMartin K. Petersen 	case 2048:
6562597136abSMartin K. Petersen 	case 4096:
6563597136abSMartin K. Petersen 		break;
6564597136abSMartin K. Petersen 	default:
6565773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6566597136abSMartin K. Petersen 		return -EINVAL;
6567597136abSMartin K. Petersen 	}
6568597136abSMartin K. Petersen 
6569773642d9SDouglas Gilbert 	switch (sdebug_dif) {
65708475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6571f46eb0e9SDouglas Gilbert 		break;
65728475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
65738475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
65748475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6575f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6576c6a44287SMartin K. Petersen 		break;
6577c6a44287SMartin K. Petersen 
6578c6a44287SMartin K. Petersen 	default:
6579c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6580c6a44287SMartin K. Petersen 		return -EINVAL;
6581c6a44287SMartin K. Petersen 	}
6582c6a44287SMartin K. Petersen 
6583aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6584aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6585aa5334c4SMaurizio Lombardi 		return -EINVAL;
6586aa5334c4SMaurizio Lombardi 	}
6587aa5334c4SMaurizio Lombardi 
6588773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6589c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6590c6a44287SMartin K. Petersen 		return -EINVAL;
6591c6a44287SMartin K. Petersen 	}
6592c6a44287SMartin K. Petersen 
6593773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6594c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6595c6a44287SMartin K. Petersen 		return -EINVAL;
6596c6a44287SMartin K. Petersen 	}
6597c6a44287SMartin K. Petersen 
6598773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6599773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6600ea61fca5SMartin K. Petersen 		return -EINVAL;
6601ea61fca5SMartin K. Petersen 	}
66028d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
66038d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
66048d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
66058d039e22SDouglas Gilbert 	}
6606ea61fca5SMartin K. Petersen 
6607773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6608773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6609ea61fca5SMartin K. Petersen 		return -EINVAL;
6610ea61fca5SMartin K. Petersen 	}
6611ea61fca5SMartin K. Petersen 
6612c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6613c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6614c4837394SDouglas Gilbert 		return -EINVAL;
6615c4837394SDouglas Gilbert 	}
6616c87bf24cSJohn Garry 
6617c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6618c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6619c87bf24cSJohn Garry 		return -EINVAL;
6620c87bf24cSJohn Garry 	}
6621c87bf24cSJohn Garry 
6622c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6623c4837394SDouglas Gilbert 			       GFP_KERNEL);
6624c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6625c4837394SDouglas Gilbert 		return -ENOMEM;
6626c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6627c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6628c4837394SDouglas Gilbert 
6629f0d1cf93SDouglas Gilbert 	/*
66309267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
66319267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6632f0d1cf93SDouglas Gilbert 	 */
66339267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
66349267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
66359267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
66369267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
66379267e0ebSDouglas Gilbert 		if (k < 0) {
66389267e0ebSDouglas Gilbert 			ret = k;
66399267e0ebSDouglas Gilbert 			goto free_vm;
66409267e0ebSDouglas Gilbert 		}
66419267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
66429267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
66439267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
664464e14eceSDamien Le Moal 		case BLK_ZONED_HA:
66459267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
66469267e0ebSDouglas Gilbert 			break;
66479267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
66489267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
66499267e0ebSDouglas Gilbert 			break;
66509267e0ebSDouglas Gilbert 		default:
66519267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
66529267e0ebSDouglas Gilbert 			return -EINVAL;
66539267e0ebSDouglas Gilbert 		}
66549267e0ebSDouglas Gilbert 	}
66559267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6656f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
66579267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
66589267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
66599267e0ebSDouglas Gilbert 	}
6660f0d1cf93SDouglas Gilbert 
66619267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
66629267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6663773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6664773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6665773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6666773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
666728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
66681da177e4SLinus Torvalds 
66691da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
66701da177e4SLinus Torvalds 	sdebug_heads = 8;
66711da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6672773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
66731da177e4SLinus Torvalds 		sdebug_heads = 64;
6674773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6675fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
66761da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
66771da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
66781da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
66791da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
66801da177e4SLinus Torvalds 		sdebug_heads = 255;
66811da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
66821da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
66831da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
66841da177e4SLinus Torvalds 	}
66855b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6686773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6687773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
66886014759cSMartin K. Petersen 
6689773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6690773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
66916014759cSMartin K. Petersen 
6692773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6693773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
66946014759cSMartin K. Petersen 
6695773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6696773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6697773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6698c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6699c4837394SDouglas Gilbert 			ret = -EINVAL;
670087c715dcSDouglas Gilbert 			goto free_q_arr;
670144d92694SMartin K. Petersen 		}
670244d92694SMartin K. Petersen 	}
670387c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
670487c715dcSDouglas Gilbert 	if (want_store) {
670587c715dcSDouglas Gilbert 		idx = sdebug_add_store();
670687c715dcSDouglas Gilbert 		if (idx < 0) {
670787c715dcSDouglas Gilbert 			ret = idx;
670887c715dcSDouglas Gilbert 			goto free_q_arr;
670987c715dcSDouglas Gilbert 		}
671044d92694SMartin K. Petersen 	}
671144d92694SMartin K. Petersen 
67129b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
67139b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6714c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
67159b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
67166ecaff7fSRandy Dunlap 		goto free_vm;
67176ecaff7fSRandy Dunlap 	}
67186ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
67196ecaff7fSRandy Dunlap 	if (ret < 0) {
6720c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
67216ecaff7fSRandy Dunlap 		goto dev_unreg;
67226ecaff7fSRandy Dunlap 	}
67236ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
67246ecaff7fSRandy Dunlap 	if (ret < 0) {
6725c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
67266ecaff7fSRandy Dunlap 		goto bus_unreg;
67276ecaff7fSRandy Dunlap 	}
67281da177e4SLinus Torvalds 
672987c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6730773642d9SDouglas Gilbert 	sdebug_add_host = 0;
67311da177e4SLinus Torvalds 
673287c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
673387c715dcSDouglas Gilbert 		if (want_store && k == 0) {
673487c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
673587c715dcSDouglas Gilbert 			if (ret < 0) {
673687c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
673787c715dcSDouglas Gilbert 				       k, -ret);
673887c715dcSDouglas Gilbert 				break;
673987c715dcSDouglas Gilbert 			}
674087c715dcSDouglas Gilbert 		} else {
674187c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
674287c715dcSDouglas Gilbert 						 sdebug_per_host_store);
674387c715dcSDouglas Gilbert 			if (ret < 0) {
674487c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
67451da177e4SLinus Torvalds 				break;
67461da177e4SLinus Torvalds 			}
67471da177e4SLinus Torvalds 		}
674887c715dcSDouglas Gilbert 	}
6749773642d9SDouglas Gilbert 	if (sdebug_verbose)
675087c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6751c1287970STomas Winkler 
67521da177e4SLinus Torvalds 	return 0;
67536ecaff7fSRandy Dunlap 
67546ecaff7fSRandy Dunlap bus_unreg:
67556ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
67566ecaff7fSRandy Dunlap dev_unreg:
67579b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
67586ecaff7fSRandy Dunlap free_vm:
675987c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6760c4837394SDouglas Gilbert free_q_arr:
6761c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
67626ecaff7fSRandy Dunlap 	return ret;
67631da177e4SLinus Torvalds }
67641da177e4SLinus Torvalds 
67651da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
67661da177e4SLinus Torvalds {
676787c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
67681da177e4SLinus Torvalds 
67691da177e4SLinus Torvalds 	stop_all_queued();
67701da177e4SLinus Torvalds 	for (; k; k--)
677187c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
677252ab9768SLuis Henriques 	free_all_queued();
67731da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
67741da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
67759b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
67761da177e4SLinus Torvalds 
677787c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
677887c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
67791da177e4SLinus Torvalds }
67801da177e4SLinus Torvalds 
67811da177e4SLinus Torvalds device_initcall(scsi_debug_init);
67821da177e4SLinus Torvalds module_exit(scsi_debug_exit);
67831da177e4SLinus Torvalds 
67841da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
67851da177e4SLinus Torvalds {
67861da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
67871da177e4SLinus Torvalds 
67881da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
67891da177e4SLinus Torvalds 	kfree(sdbg_host);
67901da177e4SLinus Torvalds }
67911da177e4SLinus Torvalds 
679287c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
679387c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
67941da177e4SLinus Torvalds {
679587c715dcSDouglas Gilbert 	if (idx < 0)
679687c715dcSDouglas Gilbert 		return;
679787c715dcSDouglas Gilbert 	if (!sip) {
679887c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
679987c715dcSDouglas Gilbert 			return;
680087c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
680187c715dcSDouglas Gilbert 		if (!sip)
680287c715dcSDouglas Gilbert 			return;
680387c715dcSDouglas Gilbert 	}
680487c715dcSDouglas Gilbert 	vfree(sip->map_storep);
680587c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
680687c715dcSDouglas Gilbert 	vfree(sip->storep);
680787c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
680887c715dcSDouglas Gilbert 	kfree(sip);
680987c715dcSDouglas Gilbert }
681087c715dcSDouglas Gilbert 
681187c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
681287c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
681387c715dcSDouglas Gilbert {
681487c715dcSDouglas Gilbert 	unsigned long idx;
681587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
681687c715dcSDouglas Gilbert 
681787c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
681887c715dcSDouglas Gilbert 		if (apart_from_first)
681987c715dcSDouglas Gilbert 			apart_from_first = false;
682087c715dcSDouglas Gilbert 		else
682187c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
682287c715dcSDouglas Gilbert 	}
682387c715dcSDouglas Gilbert 	if (apart_from_first)
682487c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
682587c715dcSDouglas Gilbert }
682687c715dcSDouglas Gilbert 
682787c715dcSDouglas Gilbert /*
682887c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
682987c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
683087c715dcSDouglas Gilbert  */
683187c715dcSDouglas Gilbert static int sdebug_add_store(void)
683287c715dcSDouglas Gilbert {
683387c715dcSDouglas Gilbert 	int res;
683487c715dcSDouglas Gilbert 	u32 n_idx;
683587c715dcSDouglas Gilbert 	unsigned long iflags;
683687c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
683787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
683887c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
683987c715dcSDouglas Gilbert 
684087c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
684187c715dcSDouglas Gilbert 	if (!sip)
684287c715dcSDouglas Gilbert 		return -ENOMEM;
684387c715dcSDouglas Gilbert 
684487c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
684587c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
684687c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
684787c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
684887c715dcSDouglas Gilbert 		kfree(sip);
684987c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
685087c715dcSDouglas Gilbert 		return res;
685187c715dcSDouglas Gilbert 	}
685287c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
685387c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
685487c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
685587c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
685687c715dcSDouglas Gilbert 
685787c715dcSDouglas Gilbert 	res = -ENOMEM;
685887c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
685987c715dcSDouglas Gilbert 	if (!sip->storep) {
686087c715dcSDouglas Gilbert 		pr_err("user data oom\n");
686187c715dcSDouglas Gilbert 		goto err;
686287c715dcSDouglas Gilbert 	}
686387c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
686487c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
686587c715dcSDouglas Gilbert 
686687c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
686787c715dcSDouglas Gilbert 	if (sdebug_dix) {
686887c715dcSDouglas Gilbert 		int dif_size;
686987c715dcSDouglas Gilbert 
687087c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
687187c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
687287c715dcSDouglas Gilbert 
687387c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
687487c715dcSDouglas Gilbert 			sip->dif_storep);
687587c715dcSDouglas Gilbert 
687687c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
687787c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
687887c715dcSDouglas Gilbert 			goto err;
687987c715dcSDouglas Gilbert 		}
688087c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
688187c715dcSDouglas Gilbert 	}
688287c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
688387c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
688487c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
688587c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
688687c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
688787c715dcSDouglas Gilbert 
688887c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
688987c715dcSDouglas Gilbert 
689087c715dcSDouglas Gilbert 		if (!sip->map_storep) {
689187c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
689287c715dcSDouglas Gilbert 			goto err;
689387c715dcSDouglas Gilbert 		}
689487c715dcSDouglas Gilbert 
689587c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
689687c715dcSDouglas Gilbert 
689787c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
689887c715dcSDouglas Gilbert 		if (sdebug_num_parts)
689987c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
690087c715dcSDouglas Gilbert 	}
690187c715dcSDouglas Gilbert 
690287c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
690387c715dcSDouglas Gilbert 	return (int)n_idx;
690487c715dcSDouglas Gilbert err:
690587c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
690687c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
690787c715dcSDouglas Gilbert 	return res;
690887c715dcSDouglas Gilbert }
690987c715dcSDouglas Gilbert 
691087c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
691187c715dcSDouglas Gilbert {
691287c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
691387c715dcSDouglas Gilbert 	int error = -ENOMEM;
69141da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
69158b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
69161da177e4SLinus Torvalds 
691724669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
691887c715dcSDouglas Gilbert 	if (!sdbg_host)
69191da177e4SLinus Torvalds 		return -ENOMEM;
692087c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
692187c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
692287c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
692387c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
69241da177e4SLinus Torvalds 
69251da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
69261da177e4SLinus Torvalds 
6927773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
69281da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
69295cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
693087c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
69311da177e4SLinus Torvalds 			goto clean;
69321da177e4SLinus Torvalds 	}
69331da177e4SLinus Torvalds 
69341da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
69351da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
69361da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
69371da177e4SLinus Torvalds 
69381da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
69399b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
69401da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
694187c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
69421da177e4SLinus Torvalds 
69431da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
69441da177e4SLinus Torvalds 	if (error)
69451da177e4SLinus Torvalds 		goto clean;
69461da177e4SLinus Torvalds 
694787c715dcSDouglas Gilbert 	++sdebug_num_hosts;
694887c715dcSDouglas Gilbert 	return 0;
69491da177e4SLinus Torvalds 
69501da177e4SLinus Torvalds clean:
69518b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
69528b40228fSFUJITA Tomonori 				 dev_list) {
69531da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
6954f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
69551da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
69561da177e4SLinus Torvalds 	}
69571da177e4SLinus Torvalds 	kfree(sdbg_host);
695887c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
69591da177e4SLinus Torvalds 	return error;
69601da177e4SLinus Torvalds }
69611da177e4SLinus Torvalds 
696287c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
69631da177e4SLinus Torvalds {
696487c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
696587c715dcSDouglas Gilbert 
696687c715dcSDouglas Gilbert 	if (mk_new_store) {
696787c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
696887c715dcSDouglas Gilbert 		if (ph_idx < 0)
696987c715dcSDouglas Gilbert 			return ph_idx;
697087c715dcSDouglas Gilbert 	}
697187c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
697287c715dcSDouglas Gilbert }
697387c715dcSDouglas Gilbert 
697487c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
697587c715dcSDouglas Gilbert {
697687c715dcSDouglas Gilbert 	int idx = -1;
69771da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
697887c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
69791da177e4SLinus Torvalds 
69801da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
69811da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
69821da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
69831da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
698487c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
69851da177e4SLinus Torvalds 	}
698687c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
698787c715dcSDouglas Gilbert 		bool unique = true;
698887c715dcSDouglas Gilbert 
698987c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
699087c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
699187c715dcSDouglas Gilbert 				continue;
699287c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
699387c715dcSDouglas Gilbert 				unique = false;
699487c715dcSDouglas Gilbert 				break;
699587c715dcSDouglas Gilbert 			}
699687c715dcSDouglas Gilbert 		}
699787c715dcSDouglas Gilbert 		if (unique) {
699887c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
699987c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
700087c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
700187c715dcSDouglas Gilbert 		}
700287c715dcSDouglas Gilbert 	}
700387c715dcSDouglas Gilbert 	if (sdbg_host)
700487c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
70051da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
70061da177e4SLinus Torvalds 
70071da177e4SLinus Torvalds 	if (!sdbg_host)
70081da177e4SLinus Torvalds 		return;
70091da177e4SLinus Torvalds 
70101da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
701187c715dcSDouglas Gilbert 	--sdebug_num_hosts;
70121da177e4SLinus Torvalds }
70131da177e4SLinus Torvalds 
7014fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7015cbf67842SDouglas Gilbert {
7016cbf67842SDouglas Gilbert 	int num_in_q = 0;
7017cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7018cbf67842SDouglas Gilbert 
7019c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
7020cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7021cbf67842SDouglas Gilbert 	if (NULL == devip) {
7022c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
7023cbf67842SDouglas Gilbert 		return	-ENODEV;
7024cbf67842SDouglas Gilbert 	}
7025cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7026c40ecc12SChristoph Hellwig 
7027cbf67842SDouglas Gilbert 	if (qdepth < 1)
7028cbf67842SDouglas Gilbert 		qdepth = 1;
7029c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
7030c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
7031c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
7032db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
7033cbf67842SDouglas Gilbert 
7034773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7035c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7036c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7037cbf67842SDouglas Gilbert 	}
7038c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
7039cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7040cbf67842SDouglas Gilbert }
7041cbf67842SDouglas Gilbert 
7042c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7043817fd66bSDouglas Gilbert {
7044c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7045773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7046773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7047773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7048c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7049773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7050817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7051c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7052817fd66bSDouglas Gilbert 	}
7053c4837394SDouglas Gilbert 	return false;
7054817fd66bSDouglas Gilbert }
7055817fd66bSDouglas Gilbert 
70567ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
70577ee6d1b4SBart Van Assche {
70587ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
70597ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
70607ee6d1b4SBart Van Assche }
70617ee6d1b4SBart Van Assche 
7062fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7063fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7064c2248fc9SDouglas Gilbert {
7065c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7066c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7067c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7068c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7069c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
707087c715dcSDouglas Gilbert 
7071c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7072c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7073f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7074c2248fc9SDouglas Gilbert 	int k, na;
7075c2248fc9SDouglas Gilbert 	int errsts = 0;
7076c2248fc9SDouglas Gilbert 	u32 flags;
7077c2248fc9SDouglas Gilbert 	u16 sa;
7078c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7079c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
7080c2248fc9SDouglas Gilbert 
7081c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
7082c4837394SDouglas Gilbert 	if (sdebug_statistics)
7083c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
7084f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7085f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7086c2248fc9SDouglas Gilbert 		char b[120];
7087c2248fc9SDouglas Gilbert 		int n, len, sb;
7088c2248fc9SDouglas Gilbert 
7089c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7090c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7091c2248fc9SDouglas Gilbert 		if (len > 32)
7092c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7093c2248fc9SDouglas Gilbert 		else {
7094c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7095c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7096c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7097c2248fc9SDouglas Gilbert 		}
7098458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7099458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
7100c2248fc9SDouglas Gilbert 	}
71017ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
71027ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
710334d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7104f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
7105f46eb0e9SDouglas Gilbert 		goto err_out;
7106c2248fc9SDouglas Gilbert 
7107c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7108c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7109c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7110f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7111f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7112c2248fc9SDouglas Gilbert 		if (NULL == devip)
7113f46eb0e9SDouglas Gilbert 			goto err_out;
7114c2248fc9SDouglas Gilbert 	}
7115c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7116c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7117c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7118c2248fc9SDouglas Gilbert 		r_oip = oip;
7119c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7120c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7121c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7122c2248fc9SDouglas Gilbert 			else
7123c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7124c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7125c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7126c2248fc9SDouglas Gilbert 					break;
7127c2248fc9SDouglas Gilbert 			}
7128c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7129c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7130c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7131c2248fc9SDouglas Gilbert 					break;
7132c2248fc9SDouglas Gilbert 			}
7133c2248fc9SDouglas Gilbert 		}
7134c2248fc9SDouglas Gilbert 		if (k > na) {
7135c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7136c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7137c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7138c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7139c2248fc9SDouglas Gilbert 			else
7140c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7141c2248fc9SDouglas Gilbert 			goto check_cond;
7142c2248fc9SDouglas Gilbert 		}
7143c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7144c2248fc9SDouglas Gilbert 	flags = oip->flags;
7145f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7146c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7147c2248fc9SDouglas Gilbert 		goto check_cond;
7148c2248fc9SDouglas Gilbert 	}
7149f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7150773642d9SDouglas Gilbert 		if (sdebug_verbose)
7151773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7152773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7153c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7154c2248fc9SDouglas Gilbert 		goto check_cond;
7155c2248fc9SDouglas Gilbert 	}
7156f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7157c2248fc9SDouglas Gilbert 		u8 rem;
7158c2248fc9SDouglas Gilbert 		int j;
7159c2248fc9SDouglas Gilbert 
7160c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7161c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7162c2248fc9SDouglas Gilbert 			if (rem) {
7163c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7164c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7165c2248fc9SDouglas Gilbert 						break;
7166c2248fc9SDouglas Gilbert 				}
7167c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7168c2248fc9SDouglas Gilbert 				goto check_cond;
7169c2248fc9SDouglas Gilbert 			}
7170c2248fc9SDouglas Gilbert 		}
7171c2248fc9SDouglas Gilbert 	}
7172f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7173b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7174b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7175f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7176c2248fc9SDouglas Gilbert 		if (errsts)
7177c2248fc9SDouglas Gilbert 			goto check_cond;
7178c2248fc9SDouglas Gilbert 	}
7179c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
7180c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7181773642d9SDouglas Gilbert 		if (sdebug_verbose)
7182c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
7183c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
7184c2248fc9SDouglas Gilbert 				    "required");
7185c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
7186c2248fc9SDouglas Gilbert 		goto fini;
7187c2248fc9SDouglas Gilbert 	}
7188773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7189c2248fc9SDouglas Gilbert 		goto fini;
7190f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7191c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7192c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7193c2248fc9SDouglas Gilbert 	}
7194f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7195f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7196f66b8517SMartin Wilck 	else
7197f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7198c2248fc9SDouglas Gilbert 
7199c2248fc9SDouglas Gilbert fini:
720067da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7201f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
720275aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
720375aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
720480c49563SDouglas Gilbert 		/*
720575aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
720675aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
720775aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
720875aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
720980c49563SDouglas Gilbert 		 */
721080c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
72114f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
721280c49563SDouglas Gilbert 
72134f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7214f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
721580c49563SDouglas Gilbert 	} else
7216f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
721710bde980SDouglas Gilbert 				     sdebug_ndelay);
7218c2248fc9SDouglas Gilbert check_cond:
7219f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7220f46eb0e9SDouglas Gilbert err_out:
7221f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7222c2248fc9SDouglas Gilbert }
7223c2248fc9SDouglas Gilbert 
72249e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7225c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7226c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
72279e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
72289e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
72299e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
72309e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
72319e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
72329e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
72339e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7234185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7235cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
72369e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
72379e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7238cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7239cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
72409e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7241c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
72429e603ca0SFUJITA Tomonori 	.this_id =		7,
724365e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7244cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
72456bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
724650c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
72479e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7248c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
72499e603ca0SFUJITA Tomonori };
72509e603ca0SFUJITA Tomonori 
72511da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
72521da177e4SLinus Torvalds {
72531da177e4SLinus Torvalds 	int error = 0;
72541da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72551da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7256f46eb0e9SDouglas Gilbert 	int hprot;
72571da177e4SLinus Torvalds 
72581da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
72591da177e4SLinus Torvalds 
7260773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
72612a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
72624af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
72634af14d11SChristoph Hellwig 
72641da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
72651da177e4SLinus Torvalds 	if (NULL == hpnt) {
7266c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
72671da177e4SLinus Torvalds 		error = -ENODEV;
72681da177e4SLinus Torvalds 		return error;
72691da177e4SLinus Torvalds 	}
7270c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
72719b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7272c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7273c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7274c4837394SDouglas Gilbert 	}
7275c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
7276c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
7277c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
72781da177e4SLinus Torvalds 
72791da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
72801da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7281773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7282773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
72831da177e4SLinus Torvalds 	else
7284773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7285773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7286f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
72871da177e4SLinus Torvalds 
7288f46eb0e9SDouglas Gilbert 	hprot = 0;
7289c6a44287SMartin K. Petersen 
7290773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7291c6a44287SMartin K. Petersen 
72928475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7293f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7294773642d9SDouglas Gilbert 		if (sdebug_dix)
7295f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7296c6a44287SMartin K. Petersen 		break;
7297c6a44287SMartin K. Petersen 
72988475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7299f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7300773642d9SDouglas Gilbert 		if (sdebug_dix)
7301f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7302c6a44287SMartin K. Petersen 		break;
7303c6a44287SMartin K. Petersen 
73048475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7305f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7306773642d9SDouglas Gilbert 		if (sdebug_dix)
7307f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7308c6a44287SMartin K. Petersen 		break;
7309c6a44287SMartin K. Petersen 
7310c6a44287SMartin K. Petersen 	default:
7311773642d9SDouglas Gilbert 		if (sdebug_dix)
7312f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7313c6a44287SMartin K. Petersen 		break;
7314c6a44287SMartin K. Petersen 	}
7315c6a44287SMartin K. Petersen 
7316f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7317c6a44287SMartin K. Petersen 
7318f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7319c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7320f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7321f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7322f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7323f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7324f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7325f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7326f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7327c6a44287SMartin K. Petersen 
7328773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7329c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7330c6a44287SMartin K. Petersen 	else
7331c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7332c6a44287SMartin K. Petersen 
7333773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7334773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7335c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7336c4837394SDouglas Gilbert 		sdebug_statistics = true;
73371da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
73381da177e4SLinus Torvalds 	if (error) {
7339c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
73401da177e4SLinus Torvalds 		error = -ENODEV;
73411da177e4SLinus Torvalds 		scsi_host_put(hpnt);
734287c715dcSDouglas Gilbert 	} else {
73431da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
734487c715dcSDouglas Gilbert 	}
73451da177e4SLinus Torvalds 
73461da177e4SLinus Torvalds 	return error;
73471da177e4SLinus Torvalds }
73481da177e4SLinus Torvalds 
73491da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
73501da177e4SLinus Torvalds {
73511da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
73528b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
73531da177e4SLinus Torvalds 
73541da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
73551da177e4SLinus Torvalds 
73561da177e4SLinus Torvalds 	if (!sdbg_host) {
7357c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
73581da177e4SLinus Torvalds 		return -ENODEV;
73591da177e4SLinus Torvalds 	}
73601da177e4SLinus Torvalds 
73611da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
73621da177e4SLinus Torvalds 
73638b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73648b40228fSFUJITA Tomonori 				 dev_list) {
73651da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7366f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73671da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73681da177e4SLinus Torvalds 	}
73691da177e4SLinus Torvalds 
73701da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
73711da177e4SLinus Torvalds 	return 0;
73721da177e4SLinus Torvalds }
73731da177e4SLinus Torvalds 
73748dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
73758dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
73761da177e4SLinus Torvalds {
73778dea0d02SFUJITA Tomonori 	return 1;
73788dea0d02SFUJITA Tomonori }
73791da177e4SLinus Torvalds 
73808dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
73818dea0d02SFUJITA Tomonori 	.name = "pseudo",
73828dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
73838dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
73848dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
738582069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
73868dea0d02SFUJITA Tomonori };
7387