xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision e208a1d7)
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  *
10500d0d24SDouglas Gilbert  * Copyright (C) 2001 - 2021 Douglas Gilbert
111da177e4SLinus Torvalds  *
1230f67481SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
194a5fc1c6SDamien Le Moal #include <linux/align.h>
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/fs.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/proc_fs.h>
291da177e4SLinus Torvalds #include <linux/vmalloc.h>
301da177e4SLinus Torvalds #include <linux/moduleparam.h>
31852e034dSJens Axboe #include <linux/scatterlist.h>
321da177e4SLinus Torvalds #include <linux/blkdev.h>
33c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
34cbf67842SDouglas Gilbert #include <linux/spinlock.h>
35cbf67842SDouglas Gilbert #include <linux/interrupt.h>
36cbf67842SDouglas Gilbert #include <linux/atomic.h>
37cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3809ba24c1SDouglas Gilbert #include <linux/uuid.h>
396ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
401442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
410c4bc91dSDouglas Gilbert #include <linux/random.h>
4287c715dcSDouglas Gilbert #include <linux/xarray.h>
43ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
44c6a44287SMartin K. Petersen 
45c6a44287SMartin K. Petersen #include <net/checksum.h>
469ff26eefSFUJITA Tomonori 
4744d92694SMartin K. Petersen #include <asm/unaligned.h>
4844d92694SMartin K. Petersen 
499ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
521da177e4SLinus Torvalds #include <scsi/scsi_host.h>
531da177e4SLinus Torvalds #include <scsi/scsicam.h>
54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
62500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191"	/* format to fit INQUIRY revision field */
63500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520";
64cbf67842SDouglas Gilbert 
65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
661da177e4SLinus Torvalds 
676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
779447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
85500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1
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
1014a5fc1c6SDamien Le Moal #define ATTEMPT_ACCESS_GAP 0x9
102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1031da177e4SLinus Torvalds 
1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1066f3cbf55SDouglas Gilbert 
1071da177e4SLinus Torvalds /* Default values for driver parameters */
1081da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1091da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1101da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1121da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1131da177e4SLinus Torvalds  */
1145b94e232SMartin K. Petersen #define DEF_ATO 1
1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
116c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1205b94e232SMartin K. Petersen #define DEF_DIF 0
1215b94e232SMartin K. Petersen #define DEF_DIX 0
12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1235b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1241da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1255b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1265b94e232SMartin K. Petersen #define DEF_GUARD 0
127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1285b94e232SMartin K. Petersen #define DEF_LBPU 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS 0
1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0
131be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
133cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1351da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1361da177e4SLinus Torvalds #define DEF_OPTS   0
13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
140b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false
142d986788bSMartin Pitt #define DEF_REMOVABLE false
143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
152c2248fc9SDouglas Gilbert #define DEF_STRICT 0
153c4837394SDouglas Gilbert #define DEF_STATISTICS false
154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1581da177e4SLinus Torvalds 
159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
163f0d1cf93SDouglas Gilbert 
164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
165b01f6f83SDouglas Gilbert 
166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
1777d5a129bSDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400	/* ignore */
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
179773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
180773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
181773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1827ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1837382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
185773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
186773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
187773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
188773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1897ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1907382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1917382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1923a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1933a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1941da177e4SLinus Torvalds 
195cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
196cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
197cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
198cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
200500d0d24SDouglas Gilbert #define SDEBUG_UA_POOCCUR 1	/* Power on occurred */
201500d0d24SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 2
202500d0d24SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 3
203500d0d24SDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 4
204500d0d24SDouglas Gilbert #define SDEBUG_UA_LUNS_CHANGED 5
205500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED 6	/* simulate firmware change */
206500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7
207500d0d24SDouglas Gilbert #define SDEBUG_NUM_UAS 8
208cbf67842SDouglas Gilbert 
209773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2101da177e4SLinus Torvalds  * sector on read commands: */
2111da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2131da177e4SLinus Torvalds 
214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
216c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
220c4837394SDouglas Gilbert  */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
223fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN  SDEBUG_CANQUEUE
224cbf67842SDouglas Gilbert 
225b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
226b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
227b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
228fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
229fd32119bSDouglas Gilbert #define F_D_UNKN		8
230b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
231b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
232b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
233b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
234b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
235b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
236b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
237b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
238b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
239b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
240fd32119bSDouglas Gilbert 
241b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
242fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24346f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
244fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2454f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
246fd32119bSDouglas Gilbert 
247fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
248fd32119bSDouglas Gilbert 
249b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
250fd32119bSDouglas Gilbert 
25187c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25287c715dcSDouglas Gilbert 
25364e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25464e14eceSDamien Le Moal enum sdebug_z_type {
25535dbe2b9SDamien Le Moal 	ZBC_ZTYPE_CNV	= 0x1,
25635dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWR	= 0x2,
25735dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWP	= 0x3,
2584a5fc1c6SDamien Le Moal 	/* ZBC_ZTYPE_SOBR = 0x4, */
2594a5fc1c6SDamien Le Moal 	ZBC_ZTYPE_GAP	= 0x5,
26064e14eceSDamien Le Moal };
26164e14eceSDamien Le Moal 
262f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
263f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
264f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
265f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
266f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
267f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
268f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
269f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
270f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
271f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
272f0d1cf93SDouglas Gilbert };
273f0d1cf93SDouglas Gilbert 
274f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
27564e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
276f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
27764e14eceSDamien Le Moal 	bool z_non_seq_resource;
278f0d1cf93SDouglas Gilbert 	unsigned int z_size;
279f0d1cf93SDouglas Gilbert 	sector_t z_start;
280f0d1cf93SDouglas Gilbert 	sector_t z_wp;
281f0d1cf93SDouglas Gilbert };
282fd32119bSDouglas Gilbert 
283fd32119bSDouglas Gilbert struct sdebug_dev_info {
284fd32119bSDouglas Gilbert 	struct list_head dev_list;
285fd32119bSDouglas Gilbert 	unsigned int channel;
286fd32119bSDouglas Gilbert 	unsigned int target;
287fd32119bSDouglas Gilbert 	u64 lun;
288bf476433SChristoph Hellwig 	uuid_t lu_name;
289fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
290fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
291fd32119bSDouglas Gilbert 	atomic_t num_in_q;
292fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
293fd32119bSDouglas Gilbert 	bool used;
294f0d1cf93SDouglas Gilbert 
295f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
29664e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
2974a5fc1c6SDamien Le Moal 	unsigned int zcap;
298f0d1cf93SDouglas Gilbert 	unsigned int zsize;
299f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
300f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
301aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
3024a5fc1c6SDamien Le Moal 	unsigned int nr_seq_zones;
303f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
304f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
305f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
306f0d1cf93SDouglas Gilbert 	unsigned int max_open;
307fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
308f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
309fd32119bSDouglas Gilbert };
310fd32119bSDouglas Gilbert 
311fd32119bSDouglas Gilbert struct sdebug_host_info {
312fd32119bSDouglas Gilbert 	struct list_head host_list;
31387c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
314fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
315fd32119bSDouglas Gilbert 	struct device dev;
316fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
317fd32119bSDouglas Gilbert };
318fd32119bSDouglas Gilbert 
31987c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
32087c715dcSDouglas Gilbert struct sdeb_store_info {
32187c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
32287c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
32387c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
32487c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32587c715dcSDouglas Gilbert };
32687c715dcSDouglas Gilbert 
327fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
328fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
329fd32119bSDouglas Gilbert 
33010bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3314a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
33210bde980SDouglas Gilbert 
333fd32119bSDouglas Gilbert struct sdebug_defer {
334fd32119bSDouglas Gilbert 	struct hrtimer hrt;
335fd32119bSDouglas Gilbert 	struct execute_work ew;
3364a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
337c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
338c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
339c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
340c4837394SDouglas Gilbert 	int issuing_cpu;
34110bde980SDouglas Gilbert 	bool init_hrt;
34210bde980SDouglas Gilbert 	bool init_wq;
3434a0c6f43SDouglas Gilbert 	bool init_poll;
3447382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34510bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
346fd32119bSDouglas Gilbert };
347fd32119bSDouglas Gilbert 
348fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
349c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
350c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
351c4837394SDouglas Gilbert 	 */
352fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
353fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
354fd32119bSDouglas Gilbert };
355fd32119bSDouglas Gilbert 
356c4837394SDouglas Gilbert struct sdebug_queue {
357c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
358c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
359c4837394SDouglas Gilbert 	spinlock_t qc_lock;
360c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
361fd32119bSDouglas Gilbert };
362fd32119bSDouglas Gilbert 
363c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
364c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
365c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
366c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3673a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3684a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
369c4837394SDouglas Gilbert 
370fd32119bSDouglas Gilbert struct opcode_info_t {
371b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
372b01f6f83SDouglas Gilbert 				/* for terminating element */
373fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
374fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
375fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
376fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
377fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3789a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3799a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
380fd32119bSDouglas Gilbert };
381fd32119bSDouglas Gilbert 
382fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
383c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
384c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
385c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
386c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
387c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
388c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
389c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
390c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
391c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
392c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
393c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
394c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
395c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39646f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39746f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
398c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
399c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
400c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
401481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
402c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
403c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
404c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
405c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
406c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
407c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
408c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
409c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
410c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
411c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
412c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
413ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
414f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
415f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
416f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
417c2248fc9SDouglas Gilbert };
418c2248fc9SDouglas Gilbert 
419c4837394SDouglas Gilbert 
420c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
421c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
422c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
423c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
424c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
425c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
426c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
427c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
428c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
429c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
430c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
431c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
432ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
433c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
434c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
435c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
436c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
437c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
438c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
439c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
440fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
441c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
442c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
443c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
444c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
445c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
446c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
447c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
448f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
449f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
45046f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
451c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
452c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
453c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
45446f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
45546f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
456c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
457c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
458c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
459c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
460c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
461c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
462c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
463c2248fc9SDouglas Gilbert };
464c2248fc9SDouglas Gilbert 
46580c49563SDouglas Gilbert /*
46680c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46780c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46880c49563SDouglas Gilbert  * command completion, they can mask their return value with
46980c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
47080c49563SDouglas Gilbert  */
47180c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
47280c49563SDouglas Gilbert 
473c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
482481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48838d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48938d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
490c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
491c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
492c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
49338d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
494acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
49580c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
496ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
497f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
498f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
499f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
500f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
501f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
502c2248fc9SDouglas Gilbert 
50387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
50487c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
50587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50687c715dcSDouglas Gilbert static int sdebug_add_store(void);
50787c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50887c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50987c715dcSDouglas Gilbert 
51046f64e70SDouglas Gilbert /*
51146f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
51246f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
51346f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
51446f64e70SDouglas Gilbert  */
51546f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
516c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
517c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
518c2248fc9SDouglas Gilbert };
519c2248fc9SDouglas Gilbert 
52046f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
521c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
522c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
523c2248fc9SDouglas Gilbert };
524c2248fc9SDouglas Gilbert 
52546f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52646f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
527b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
528c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52946f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
530c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53146f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
532b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
533c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
534c2248fc9SDouglas Gilbert };
535c2248fc9SDouglas Gilbert 
53646f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53746f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53846f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53946f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
54046f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
54146f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
54246f64e70SDouglas Gilbert 		   0, 0, 0} },
54346f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
54446f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54546f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
546c2248fc9SDouglas Gilbert };
547c2248fc9SDouglas Gilbert 
548c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
549c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
550c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
551c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
552c3e2fe92SDouglas Gilbert };
553c3e2fe92SDouglas Gilbert 
55446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
555c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
556c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55746f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
558c2248fc9SDouglas Gilbert };
559c2248fc9SDouglas Gilbert 
56046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
56146f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
562b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
563c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
564481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
565481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
566481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
567c2248fc9SDouglas Gilbert };
568c2248fc9SDouglas Gilbert 
56946f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
57038d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
571c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
57246f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
57338d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
574c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
57546f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
576c2248fc9SDouglas Gilbert };
577c2248fc9SDouglas Gilbert 
57846f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57946f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
580c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58146f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
582c2248fc9SDouglas Gilbert };
583c2248fc9SDouglas Gilbert 
58446f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
585c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
586c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
587c2248fc9SDouglas Gilbert };
588c2248fc9SDouglas Gilbert 
58946f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
590c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
591c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
592c2248fc9SDouglas Gilbert };
593c2248fc9SDouglas Gilbert 
59480c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5954f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59680c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59780c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59880c49563SDouglas Gilbert };
59980c49563SDouglas Gilbert 
600ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
601b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
602ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
604ed9f3e25SDouglas Gilbert };
605ed9f3e25SDouglas Gilbert 
606f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
607b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
608f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
609f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
610b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
611f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
613b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
614f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
615f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
616f0d1cf93SDouglas Gilbert };
617f0d1cf93SDouglas Gilbert 
618f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
619b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
620f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
621f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
622f0d1cf93SDouglas Gilbert };
623f0d1cf93SDouglas Gilbert 
624c2248fc9SDouglas Gilbert 
625c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
626c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
627c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
628ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
629c2248fc9SDouglas Gilbert /* 0 */
63046f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
631c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63246f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
633c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
634c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
635c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63646f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
637c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
638c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
639c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
640c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64146f64e70SDouglas Gilbert /* 5 */
64246f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
64346f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
64446f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64546f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64646f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64746f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64846f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
649c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
650c2248fc9SDouglas Gilbert 	     0, 0, 0} },
65146f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
652c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
653c2248fc9SDouglas Gilbert 	     0, 0} },
65446f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
65546f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65646f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
657c2248fc9SDouglas Gilbert /* 10 */
65846f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65946f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
66046f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66180c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6624f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
663c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
66446f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
66546f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66646f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66746f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
668481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
669481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
670481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
67146f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
67246f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
67346f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
67446f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
67546f64e70SDouglas Gilbert /* 15 */
676c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
677c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
678c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
679c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
680c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
681c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
68246f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
68346f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
68446f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
68546f64e70SDouglas Gilbert 	     0xff, 0xff} },
68646f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68746f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
688c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
689c2248fc9SDouglas Gilbert 	     0} },
69046f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
69146f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
692c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
693c2248fc9SDouglas Gilbert 	     0} },
694c2248fc9SDouglas Gilbert /* 20 */
695f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
696f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
697c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
698c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
699c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
700c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
701c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
702c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
70346f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
704b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
70546f64e70SDouglas Gilbert /* 25 */
706acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
707acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
708acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70946f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
71046f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
71146f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
71246f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7134f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
71480c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
715b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71680c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71746f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
718c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
719b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
720b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
721ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
722ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
723ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
724c2248fc9SDouglas Gilbert 
725ed9f3e25SDouglas Gilbert /* 30 */
726b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
727f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
728f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
729f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
730b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
731f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
732f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
733f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
734f0d1cf93SDouglas Gilbert /* sentinel */
735c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
736c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
737c2248fc9SDouglas Gilbert };
738c2248fc9SDouglas Gilbert 
739f19fe8f3SBart Van Assche static int sdebug_num_hosts;
74087c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
741773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7429b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
743c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7449267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
745773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
746773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
747773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
748773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
749773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
750773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
751c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
752773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
753773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
754c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
755d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
756d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
757cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
758c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
759773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
760773642d9SDouglas Gilbert static int sdebug_no_uld;
761773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
762773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
763773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
764773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
765773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76686e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
767b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
768773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
769773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
770fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
771773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
772773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
773773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
774773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
775773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
776773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
778773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
779773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
780773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
781773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
78209ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7830c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
78487c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
785773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
786773642d9SDouglas Gilbert static bool sdebug_clustering;
787773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
788773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
789817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
7907109f370SDouglas Gilbert static bool sdebug_no_rwlock;
791773642d9SDouglas Gilbert static bool sdebug_verbose;
792f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7934f2c8bf6SDouglas Gilbert static bool write_since_sync;
794c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7959447b6ceSMartin K. Petersen static bool sdebug_wp;
7969267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7979267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7989267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7991da177e4SLinus Torvalds 
800ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
801ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
802ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
803ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
804ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
805ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
806ad0c7775SDouglas Gilbert 
807c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8081da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8091da177e4SLinus Torvalds 
8101da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8111da177e4SLinus Torvalds    may still need them */
8121da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8131da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8141da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8171da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8181da177e4SLinus Torvalds 
81987c715dcSDouglas Gilbert static struct xarray per_store_arr;
82087c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
82187c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
82287c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
82387c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8241da177e4SLinus Torvalds 
82544d92694SMartin K. Petersen static unsigned long map_size;
826cbf67842SDouglas Gilbert static int num_aborts;
827cbf67842SDouglas Gilbert static int num_dev_resets;
828cbf67842SDouglas Gilbert static int num_target_resets;
829cbf67842SDouglas Gilbert static int num_bus_resets;
830cbf67842SDouglas Gilbert static int num_host_resets;
831c6a44287SMartin K. Petersen static int dix_writes;
832c6a44287SMartin K. Petersen static int dix_reads;
833c6a44287SMartin K. Petersen static int dif_errors;
8341da177e4SLinus Torvalds 
835f0d1cf93SDouglas Gilbert /* ZBC global data */
83664e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
8374a5fc1c6SDamien Le Moal static int sdeb_zbc_zone_cap_mb;
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) */
843c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
844c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
845fd32119bSDouglas Gilbert 
8461da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
84787c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84887c715dcSDouglas Gilbert 
84987c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8501da177e4SLinus Torvalds 
851cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
852cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8571da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8581da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8591da177e4SLinus Torvalds };
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds static const int check_condition_result =
862464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8631da177e4SLinus Torvalds 
864c6a44287SMartin K. Petersen static const int illegal_condition_result =
865464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
866c6a44287SMartin K. Petersen 
867cbf67842SDouglas Gilbert static const int device_qfull_result =
8687d5a129bSDouglas Gilbert 	(DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
869cbf67842SDouglas Gilbert 
870ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
871ed9f3e25SDouglas Gilbert 
872fd32119bSDouglas Gilbert 
873760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
874760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
875760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
876760f3b03SDouglas Gilbert  */
877760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
878fd32119bSDouglas Gilbert {
879fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
880fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
881fd32119bSDouglas Gilbert }
882c65b1445SDouglas Gilbert 
88387c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
88487c715dcSDouglas Gilbert 			    unsigned long long lba)
88514faa944SAkinobu Mita {
88687c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
88714faa944SAkinobu Mita 
88887c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88987c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
89087c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
89187c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
89287c715dcSDouglas Gilbert 	}
89387c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
89414faa944SAkinobu Mita }
89514faa944SAkinobu Mita 
89687c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
89787c715dcSDouglas Gilbert 				      sector_t sector)
89814faa944SAkinobu Mita {
89949413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
90014faa944SAkinobu Mita 
90187c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
90214faa944SAkinobu Mita }
90314faa944SAkinobu Mita 
9048dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9058dea0d02SFUJITA Tomonori {
9068dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9078dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9088dea0d02SFUJITA Tomonori 
9098dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9108dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9118dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9128dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
913773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
914773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9158dea0d02SFUJITA Tomonori 		else
916773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
917773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
918f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9198dea0d02SFUJITA Tomonori 	}
9208dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9218dea0d02SFUJITA Tomonori }
9228dea0d02SFUJITA Tomonori 
92322017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
92422017ed2SDouglas Gilbert 
92522017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
926fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
927fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92822017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92922017ed2SDouglas Gilbert {
93022017ed2SDouglas Gilbert 	unsigned char *sbuff;
93122017ed2SDouglas Gilbert 	u8 sks[4];
93222017ed2SDouglas Gilbert 	int sl, asc;
93322017ed2SDouglas Gilbert 
93422017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
93522017ed2SDouglas Gilbert 	if (!sbuff) {
93622017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
93722017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93822017ed2SDouglas Gilbert 		return;
93922017ed2SDouglas Gilbert 	}
94022017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
94122017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
942f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
94322017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
94422017ed2SDouglas Gilbert 	sks[0] = 0x80;
94522017ed2SDouglas Gilbert 	if (c_d)
94622017ed2SDouglas Gilbert 		sks[0] |= 0x40;
94722017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94822017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94922017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
95022017ed2SDouglas Gilbert 	}
95122017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
952773642d9SDouglas Gilbert 	if (sdebug_dsense) {
95322017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
95422017ed2SDouglas Gilbert 		sbuff[7] = sl;
95522017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
95622017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
95722017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95822017ed2SDouglas Gilbert 	} else
95922017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
960773642d9SDouglas Gilbert 	if (sdebug_verbose)
96122017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
96222017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
96322017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
96422017ed2SDouglas Gilbert }
96522017ed2SDouglas Gilbert 
966cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9678dea0d02SFUJITA Tomonori {
968f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
969cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
970cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
971cbf67842SDouglas Gilbert 		return;
972cbf67842SDouglas Gilbert 	}
973f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9748dea0d02SFUJITA Tomonori 
975f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9768dea0d02SFUJITA Tomonori 
977773642d9SDouglas Gilbert 	if (sdebug_verbose)
978cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
979cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
980cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9818dea0d02SFUJITA Tomonori }
9821da177e4SLinus Torvalds 
983fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
98422017ed2SDouglas Gilbert {
98522017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98622017ed2SDouglas Gilbert }
98722017ed2SDouglas Gilbert 
9886f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9896f4e626fSNathan Chancellor 			    void __user *arg)
9901da177e4SLinus Torvalds {
991773642d9SDouglas Gilbert 	if (sdebug_verbose) {
992cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
993cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
994cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
995cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
996cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
997cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
998cbf67842SDouglas Gilbert 				    __func__);
999cbf67842SDouglas Gilbert 		else
1000cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
1001cbf67842SDouglas Gilbert 				    __func__, cmd);
10021da177e4SLinus Torvalds 	}
10031da177e4SLinus Torvalds 	return -EINVAL;
10041da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
10079b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10089b760fd8SDouglas Gilbert {
10099b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10109b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10119b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10129b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10149b760fd8SDouglas Gilbert 		break;
10159b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10179b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10199b760fd8SDouglas Gilbert 		break;
10209b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10229b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10239b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10249b760fd8SDouglas Gilbert 		break;
10259b760fd8SDouglas Gilbert 	case 16:
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10279b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10289b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10299b760fd8SDouglas Gilbert 		break;
10309b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10329b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10339b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10349b760fd8SDouglas Gilbert 		break;
10359b760fd8SDouglas Gilbert 	default:
10369b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10379b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10389b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10399b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10409b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10419b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10429b760fd8SDouglas Gilbert 		break;
10439b760fd8SDouglas Gilbert 	}
10449b760fd8SDouglas Gilbert }
10459b760fd8SDouglas Gilbert 
10469b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10479b760fd8SDouglas Gilbert {
10489b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10499b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10509b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10519b760fd8SDouglas Gilbert 
10529b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10539b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10549b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10559b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10569b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10579b760fd8SDouglas Gilbert 		}
10589b760fd8SDouglas Gilbert 	}
10599b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10609b760fd8SDouglas Gilbert }
10619b760fd8SDouglas Gilbert 
106219c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
106319c8ead7SEwan D. Milne {
106419c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106519c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106619c8ead7SEwan D. Milne 
106719c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
106819c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106919c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
107019c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
107119c8ead7SEwan D. Milne 			    (devip->target == dp->target))
107219c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
107319c8ead7SEwan D. Milne 		}
107419c8ead7SEwan D. Milne 	}
107519c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107619c8ead7SEwan D. Milne }
107719c8ead7SEwan D. Milne 
1078f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10791da177e4SLinus Torvalds {
1080cbf67842SDouglas Gilbert 	int k;
1081cbf67842SDouglas Gilbert 
1082cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1083cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1084cbf67842SDouglas Gilbert 		const char *cp = NULL;
1085cbf67842SDouglas Gilbert 
1086cbf67842SDouglas Gilbert 		switch (k) {
1087cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1088f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1089f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1090773642d9SDouglas Gilbert 			if (sdebug_verbose)
1091cbf67842SDouglas Gilbert 				cp = "power on reset";
1092cbf67842SDouglas Gilbert 			break;
1093500d0d24SDouglas Gilbert 		case SDEBUG_UA_POOCCUR:
1094500d0d24SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1095500d0d24SDouglas Gilbert 					POWER_ON_OCCURRED_ASCQ);
1096500d0d24SDouglas Gilbert 			if (sdebug_verbose)
1097500d0d24SDouglas Gilbert 				cp = "power on occurred";
1098500d0d24SDouglas Gilbert 			break;
1099cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1100f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1101f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1102773642d9SDouglas Gilbert 			if (sdebug_verbose)
1103cbf67842SDouglas Gilbert 				cp = "bus reset";
1104cbf67842SDouglas Gilbert 			break;
1105cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1106f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1107f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1108773642d9SDouglas Gilbert 			if (sdebug_verbose)
1109cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1110cbf67842SDouglas Gilbert 			break;
11110d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1112f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1113f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1114773642d9SDouglas Gilbert 			if (sdebug_verbose)
11150d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1116f49accf1SEwan D. Milne 			break;
1117acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1118f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1119b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1120b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1121773642d9SDouglas Gilbert 			if (sdebug_verbose)
1122acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1123acafd0b9SEwan D. Milne 			break;
1124acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1125f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1126acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1127acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1128773642d9SDouglas Gilbert 			if (sdebug_verbose)
1129acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1130acafd0b9SEwan D. Milne 			break;
113119c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
113219c8ead7SEwan D. Milne 			/*
113319c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
113419c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
113519c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
113619c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1137773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
113819c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
113919c8ead7SEwan D. Milne 			 */
1140773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
114119c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1142f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
114319c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
114419c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1145773642d9SDouglas Gilbert 			if (sdebug_verbose)
114619c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
114719c8ead7SEwan D. Milne 			break;
1148cbf67842SDouglas Gilbert 		default:
1149773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1150773642d9SDouglas Gilbert 			if (sdebug_verbose)
1151cbf67842SDouglas Gilbert 				cp = "unknown";
1152cbf67842SDouglas Gilbert 			break;
1153cbf67842SDouglas Gilbert 		}
1154cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1155773642d9SDouglas Gilbert 		if (sdebug_verbose)
1156f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1157cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1158cbf67842SDouglas Gilbert 				   my_name, cp);
11591da177e4SLinus Torvalds 		return check_condition_result;
11601da177e4SLinus Torvalds 	}
11611da177e4SLinus Torvalds 	return 0;
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds 
1164fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11651da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11661da177e4SLinus Torvalds 				int arr_len)
11671da177e4SLinus Torvalds {
116821a61829SFUJITA Tomonori 	int act_len;
1169ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11701da177e4SLinus Torvalds 
1171072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11721da177e4SLinus Torvalds 		return 0;
1173ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1174773642d9SDouglas Gilbert 		return DID_ERROR << 16;
117521a61829SFUJITA Tomonori 
117621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
117721a61829SFUJITA Tomonori 				      arr, arr_len);
117842d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
117921a61829SFUJITA Tomonori 
11801da177e4SLinus Torvalds 	return 0;
11811da177e4SLinus Torvalds }
11821da177e4SLinus Torvalds 
1183fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1184fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1185fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1186fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1187fb0cc8d1SDouglas Gilbert  */
1188fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1189fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1190fb0cc8d1SDouglas Gilbert {
11919237f04eSDamien Le Moal 	unsigned int act_len, n;
1192ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1193fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1194fb0cc8d1SDouglas Gilbert 
1195fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1196fb0cc8d1SDouglas Gilbert 		return 0;
1197ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1198fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1199fb0cc8d1SDouglas Gilbert 
1200fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1201fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1202fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
120342d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
120442d387beSBart Van Assche 		 scsi_get_resid(scp));
12059237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
120636e07d7eSGeorge Kennedy 	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
1207fb0cc8d1SDouglas Gilbert 	return 0;
1208fb0cc8d1SDouglas Gilbert }
1209fb0cc8d1SDouglas Gilbert 
1210fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1211fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1212fb0cc8d1SDouglas Gilbert  */
12131da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
121421a61829SFUJITA Tomonori 			       int arr_len)
12151da177e4SLinus Torvalds {
121621a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12171da177e4SLinus Torvalds 		return 0;
1218ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12191da177e4SLinus Torvalds 		return -1;
122021a61829SFUJITA Tomonori 
122121a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12221da177e4SLinus Torvalds }
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 
1225e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1226e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12279b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12281b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12291b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12301b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12311b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12321da177e4SLinus Torvalds 
1233cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1234760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12355a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
123609ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1237bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12381da177e4SLinus Torvalds {
1239c65b1445SDouglas Gilbert 	int num, port_a;
1240c65b1445SDouglas Gilbert 	char b[32];
12411da177e4SLinus Torvalds 
1242c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12431da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12441da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12451da177e4SLinus Torvalds 	arr[1] = 0x1;
12461da177e4SLinus Torvalds 	arr[2] = 0x0;
1247e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1248e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12491da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12501da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12511da177e4SLinus Torvalds 	arr[3] = num;
12521da177e4SLinus Torvalds 	num += 4;
1253c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
125409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
125509ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
125609ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
125709ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
125809ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125909ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
126009ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
126109ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
126209ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
126309ba24c1SDouglas Gilbert 			num += 16;
126409ba24c1SDouglas Gilbert 		} else {
12651b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1266c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1267c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1268c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1269c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12701b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1271773642d9SDouglas Gilbert 			num += 8;
127209ba24c1SDouglas Gilbert 		}
1273c65b1445SDouglas Gilbert 		/* Target relative port number */
1274c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1275c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1276c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1277c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1278c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1279c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1280c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1281c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1282c65b1445SDouglas Gilbert 	}
12831b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1284c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1285c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1286c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1287c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12881b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1289773642d9SDouglas Gilbert 	num += 8;
12901b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12915a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12925a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12935a09e398SHannes Reinecke 	arr[num++] = 0x0;
12945a09e398SHannes Reinecke 	arr[num++] = 0x4;
12955a09e398SHannes Reinecke 	arr[num++] = 0;
12965a09e398SHannes Reinecke 	arr[num++] = 0;
1297773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1298773642d9SDouglas Gilbert 	num += 2;
12991b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1300c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1301c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1302c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1303c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
13041b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1305773642d9SDouglas Gilbert 	num += 8;
1306c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1307c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1308c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1309c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1310c65b1445SDouglas Gilbert 	arr[num++] = 24;
13111b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1312c65b1445SDouglas Gilbert 	num += 12;
1313c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1314c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1315c65b1445SDouglas Gilbert 	num += 8;
1316c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1317c65b1445SDouglas Gilbert 	num += 4;
1318c65b1445SDouglas Gilbert 	return num;
1319c65b1445SDouglas Gilbert }
1320c65b1445SDouglas Gilbert 
1321c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1322c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1323c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1324c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1325c65b1445SDouglas Gilbert };
1326c65b1445SDouglas Gilbert 
1327cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1328760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1329c65b1445SDouglas Gilbert {
1330c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1331c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1332c65b1445SDouglas Gilbert }
1333c65b1445SDouglas Gilbert 
1334cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1335760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1336c65b1445SDouglas Gilbert {
1337c65b1445SDouglas Gilbert 	int num = 0;
1338c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1339c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1340c65b1445SDouglas Gilbert 	int plen, olen;
1341c65b1445SDouglas Gilbert 
1342c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1343c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1344c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1345c65b1445SDouglas Gilbert 	olen = strlen(na1);
1346c65b1445SDouglas Gilbert 	plen = olen + 1;
1347c65b1445SDouglas Gilbert 	if (plen % 4)
1348c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1349c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1350c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1351c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1352c65b1445SDouglas Gilbert 	num += plen;
1353c65b1445SDouglas Gilbert 
1354c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1355c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1356c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1357c65b1445SDouglas Gilbert 	olen = strlen(na2);
1358c65b1445SDouglas Gilbert 	plen = olen + 1;
1359c65b1445SDouglas Gilbert 	if (plen % 4)
1360c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1361c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1362c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1363c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1364c65b1445SDouglas Gilbert 	num += plen;
1365c65b1445SDouglas Gilbert 
1366c65b1445SDouglas Gilbert 	return num;
1367c65b1445SDouglas Gilbert }
1368c65b1445SDouglas Gilbert 
1369c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1370760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1371c65b1445SDouglas Gilbert {
1372c65b1445SDouglas Gilbert 	int num = 0;
1373c65b1445SDouglas Gilbert 	int port_a, port_b;
1374c65b1445SDouglas Gilbert 
1375c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1376c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1380c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1381c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1382c65b1445SDouglas Gilbert 	num += 6;
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1384c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1385c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1386c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1387c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1389c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1391773642d9SDouglas Gilbert 	num += 8;
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1393c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1394c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1395c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1396c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1397c65b1445SDouglas Gilbert 	num += 6;
1398c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1399c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1400c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1401c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1402c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1403c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1404c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
14051b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1406773642d9SDouglas Gilbert 	num += 8;
1407c65b1445SDouglas Gilbert 
1408c65b1445SDouglas Gilbert 	return num;
1409c65b1445SDouglas Gilbert }
1410c65b1445SDouglas Gilbert 
1411c65b1445SDouglas Gilbert 
1412c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1413c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1414c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1415c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1416c65b1445SDouglas Gilbert '1','2','3','4',
1417c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1418c65b1445SDouglas Gilbert 0xec,0,0,0,
1419c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1420c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1421c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1422c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1423c65b1445SDouglas Gilbert 0x53,0x41,
1424c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1425c65b1445SDouglas Gilbert 0x20,0x20,
1426c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1427c65b1445SDouglas Gilbert 0x10,0x80,
1428c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1429c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1430c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1432c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1433c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1438c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1439c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1440c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1441c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1450c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1451c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1452c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1453c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1454c65b1445SDouglas Gilbert };
1455c65b1445SDouglas Gilbert 
1456cbf67842SDouglas Gilbert /* ATA Information VPD page */
1457760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1458c65b1445SDouglas Gilbert {
1459c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1460c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1461c65b1445SDouglas Gilbert }
1462c65b1445SDouglas Gilbert 
1463c65b1445SDouglas Gilbert 
1464c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14651e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14661e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14671e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14681e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1469c65b1445SDouglas Gilbert };
1470c65b1445SDouglas Gilbert 
1471cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1472760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1473c65b1445SDouglas Gilbert {
1474ea61fca5SMartin K. Petersen 	unsigned int gran;
1475ea61fca5SMartin K. Petersen 
1476c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1477e308b3d1SMartin K. Petersen 
1478e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
147986e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
148086e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
148186e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
148286e6828aSLukas Herbolt 	else
1483773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1484773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1485e308b3d1SMartin K. Petersen 
1486e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1487773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1488773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
148944d92694SMartin K. Petersen 
1490e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1491773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1492e308b3d1SMartin K. Petersen 
1493773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1494e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1495773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1496e308b3d1SMartin K. Petersen 
1497e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1498773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
149944d92694SMartin K. Petersen 	}
150044d92694SMartin K. Petersen 
1501e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1502773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1503773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
150444d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
150544d92694SMartin K. Petersen 	}
150644d92694SMartin K. Petersen 
1507e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1508773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
15096014759cSMartin K. Petersen 
15105b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1511773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15125b94e232SMartin K. Petersen 
15135b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
151444d92694SMartin K. Petersen 
1515c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds 
15181e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
151964e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1520eac6e8e4SMatthew Wilcox {
1521eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1522eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15231e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15241e49f785SDouglas Gilbert 	arr[2] = 0;
15251e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
152664e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
152764e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1528eac6e8e4SMatthew Wilcox 
1529eac6e8e4SMatthew Wilcox 	return 0x3c;
1530eac6e8e4SMatthew Wilcox }
15311da177e4SLinus Torvalds 
1532760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1533760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15346014759cSMartin K. Petersen {
15353f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15366014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1537773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15386014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1539773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15406014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1541773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15425b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1543760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1544760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1545760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1546760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1547760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15483f0bc3b3SMartin K. Petersen 	return 0x4;
15496014759cSMartin K. Petersen }
15506014759cSMartin K. Petersen 
1551d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1552f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1553d36da305SDouglas Gilbert {
1554d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1555d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1556d36da305SDouglas Gilbert 	/*
1557d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1558d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1559f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1560f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1561d36da305SDouglas Gilbert 	 */
1562d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1563d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
156464e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1565f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1566f0d1cf93SDouglas Gilbert 	else
1567d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
15684a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize) {
15694a5fc1c6SDamien Le Moal 		arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET;
15704a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, &arr[20]);
15714a5fc1c6SDamien Le Moal 	} else {
15724a5fc1c6SDamien Le Moal 		arr[19] = 0;
15734a5fc1c6SDamien Le Moal 	}
1574d36da305SDouglas Gilbert 	return 0x3c;
1575d36da305SDouglas Gilbert }
1576d36da305SDouglas Gilbert 
15771da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1578c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15791da177e4SLinus Torvalds 
1580c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15811da177e4SLinus Torvalds {
15821da177e4SLinus Torvalds 	unsigned char pq_pdt;
15835a09e398SHannes Reinecke 	unsigned char *arr;
158401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
158536e07d7eSGeorge Kennedy 	u32 alloc_len, n;
158636e07d7eSGeorge Kennedy 	int ret;
1587d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15881da177e4SLinus Torvalds 
1589773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15906f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15916f3cbf55SDouglas Gilbert 	if (! arr)
15926f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1593760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
159464e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1595d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1596b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1597c2248fc9SDouglas Gilbert 	if (have_wlun)
1598b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1599b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1600b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1601c65b1445SDouglas Gilbert 	else
1602773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
16031da177e4SLinus Torvalds 	arr[0] = pq_pdt;
16041da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
160522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
16065a09e398SHannes Reinecke 		kfree(arr);
16071da177e4SLinus Torvalds 		return check_condition_result;
16081da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
160936e07d7eSGeorge Kennedy 		int lu_id_num, port_group_id, target_dev_id;
161036e07d7eSGeorge Kennedy 		u32 len;
1611c65b1445SDouglas Gilbert 		char lu_id_str[6];
1612c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
16131da177e4SLinus Torvalds 
16145a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16155a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1616b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
161723183910SDouglas Gilbert 			host_no = 0;
1618c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1619c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1620c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1621c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1622c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16231da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1624c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1625c65b1445SDouglas Gilbert 			n = 4;
1626c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1627c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1628c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1629c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1630c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1631c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1632c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1633c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1634d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1635c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1636760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1637760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1638d36da305SDouglas Gilbert 				if (is_disk)
1639d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
164064e14eceSDamien Le Moal 				if (is_zbc)
1641d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1642760f3b03SDouglas Gilbert 			}
1643c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16441da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1645c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16461da177e4SLinus Torvalds 			arr[3] = len;
1647c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16481da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1649c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1650760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16515a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
165209ba24c1SDouglas Gilbert 						lu_id_str, len,
165309ba24c1SDouglas Gilbert 						&devip->lu_name);
1654c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1655c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1656760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1657c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1658c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1659760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1660c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1661c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1662c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16638475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1664c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1665760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1666c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1667c6a44287SMartin K. Petersen 			else
1668c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1669c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1670c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1671c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1672c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1673c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1674c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1675c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1676c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1677c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1678c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1679760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1680d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1681c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1682760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1683773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1684d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1685c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1686760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1687d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1688eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
168964e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1690760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16916014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1692760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1693d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1694d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1695f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16961da177e4SLinus Torvalds 		} else {
169722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16985a09e398SHannes Reinecke 			kfree(arr);
16991da177e4SLinus Torvalds 			return check_condition_result;
17001da177e4SLinus Torvalds 		}
170136e07d7eSGeorge Kennedy 		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
17025a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
170336e07d7eSGeorge Kennedy 			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
17045a09e398SHannes Reinecke 		kfree(arr);
17055a09e398SHannes Reinecke 		return ret;
17061da177e4SLinus Torvalds 	}
17071da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1708773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1709773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
17101da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
17111da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1712f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1713b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
171470bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1715c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17161da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1717c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1718e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1719e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1720e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17219b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17229b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17231da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1724760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1725760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1726c65b1445SDouglas Gilbert 	n = 62;
1727760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1728760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1729760f3b03SDouglas Gilbert 		n += 2;
1730760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1731760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1732760f3b03SDouglas Gilbert 		n += 2;
1733d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1734d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1735d36da305SDouglas Gilbert 		n += 2;
17361da177e4SLinus Torvalds 	}
1737760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17385a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
173936e07d7eSGeorge Kennedy 			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17405a09e398SHannes Reinecke 	kfree(arr);
17415a09e398SHannes Reinecke 	return ret;
17421da177e4SLinus Torvalds }
17431da177e4SLinus Torvalds 
174484905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1745fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1746fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1747fd32119bSDouglas Gilbert 
17481da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17491da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17501da177e4SLinus Torvalds {
175101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
175284905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
175384905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
175436e07d7eSGeorge Kennedy 	u32 alloc_len = cmd[4];
175536e07d7eSGeorge Kennedy 	u32 len = 18;
175684905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17571da177e4SLinus Torvalds 
1758c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
175984905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
176084905d34SDouglas Gilbert 		if (dsense) {
176184905d34SDouglas Gilbert 			arr[0] = 0x72;
176284905d34SDouglas Gilbert 			arr[1] = NOT_READY;
176384905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
176484905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
176584905d34SDouglas Gilbert 			len = 8;
176684905d34SDouglas Gilbert 		} else {
176784905d34SDouglas Gilbert 			arr[0] = 0x70;
176884905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
176984905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
177084905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
177184905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
177284905d34SDouglas Gilbert 		}
177384905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
177484905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1775c2248fc9SDouglas Gilbert 		if (dsense) {
1776c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1777c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1778c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
177984905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1780c2248fc9SDouglas Gilbert 			len = 8;
1781c65b1445SDouglas Gilbert 		} else {
1782c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1783c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1784c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1785c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
178684905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1787c65b1445SDouglas Gilbert 		}
178884905d34SDouglas Gilbert 	} else {	/* nothing to report */
1789c2248fc9SDouglas Gilbert 		if (dsense) {
1790c2248fc9SDouglas Gilbert 			len = 8;
179184905d34SDouglas Gilbert 			memset(arr, 0, len);
179284905d34SDouglas Gilbert 			arr[0] = 0x72;
1793c2248fc9SDouglas Gilbert 		} else {
179484905d34SDouglas Gilbert 			memset(arr, 0, len);
1795c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1796c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1797c2248fc9SDouglas Gilbert 		}
1798c65b1445SDouglas Gilbert 	}
179936e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
18001da177e4SLinus Torvalds }
18011da177e4SLinus Torvalds 
1802fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1803c65b1445SDouglas Gilbert {
180401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1805fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
18064f2c8bf6SDouglas Gilbert 	bool changing;
1807c65b1445SDouglas Gilbert 
1808c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1809c65b1445SDouglas Gilbert 	if (power_cond) {
181022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1811c65b1445SDouglas Gilbert 		return check_condition_result;
1812c65b1445SDouglas Gilbert 	}
1813fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1814fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1815fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1816fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1817fc13638aSDouglas Gilbert 
1818fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1819fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1820fc13638aSDouglas Gilbert 
1821fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1822fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1823fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1824fc13638aSDouglas Gilbert 				stopped_state = 0;
1825fc13638aSDouglas Gilbert 			}
1826fc13638aSDouglas Gilbert 		}
1827fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1828fc13638aSDouglas Gilbert 			if (want_stop) {
1829fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1830fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1831fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1832fc13638aSDouglas Gilbert 				return check_condition_result;
1833fc13638aSDouglas Gilbert 			}
1834fc13638aSDouglas Gilbert 		}
1835fc13638aSDouglas Gilbert 	}
1836fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1837fc13638aSDouglas Gilbert 	if (changing)
1838fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1839fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18404f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18414f2c8bf6SDouglas Gilbert 	else
18424f2c8bf6SDouglas Gilbert 		return 0;
1843c65b1445SDouglas Gilbert }
1844c65b1445SDouglas Gilbert 
184528898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
184628898873SFUJITA Tomonori {
1847773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1848773642d9SDouglas Gilbert 
1849773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1850773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1851773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
185228898873SFUJITA Tomonori 	else
185328898873SFUJITA Tomonori 		return sdebug_store_sectors;
185428898873SFUJITA Tomonori }
185528898873SFUJITA Tomonori 
18561da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18571da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18581da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18591da177e4SLinus Torvalds {
18601da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1861c65b1445SDouglas Gilbert 	unsigned int capac;
18621da177e4SLinus Torvalds 
1863c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18651da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1866c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1867c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1868773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1869773642d9SDouglas Gilbert 	} else
1870773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1871773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18721da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18731da177e4SLinus Torvalds }
18741da177e4SLinus Torvalds 
1875c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1876c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1877c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1878c65b1445SDouglas Gilbert {
187901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1880c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18814e3ace00SYe Bin 	u32 alloc_len;
1882c65b1445SDouglas Gilbert 
1883773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1884c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
188528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1886c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1887773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1888773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1889773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1890773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
189144d92694SMartin K. Petersen 
1892be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18935b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1894760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1895760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1896760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1897760f3b03SDouglas Gilbert 		 */
1898760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1899760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1900be1dd78dSEric Sandeen 	}
190144d92694SMartin K. Petersen 
1902ecb8c258SBart Van Assche 	/*
1903ecb8c258SBart Van Assche 	 * Since the scsi_debug READ CAPACITY implementation always reports the
1904ecb8c258SBart Van Assche 	 * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices.
1905ecb8c258SBart Van Assche 	 */
1906ecb8c258SBart Van Assche 	if (devip->zmodel == BLK_ZONED_HM)
1907ecb8c258SBart Van Assche 		arr[12] |= 1 << 4;
1908ecb8c258SBart Van Assche 
1909773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1910c6a44287SMartin K. Petersen 
1911760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1912773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1913c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1914c6a44287SMartin K. Petersen 	}
1915c6a44287SMartin K. Petersen 
1916c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
19174e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1918c65b1445SDouglas Gilbert }
1919c65b1445SDouglas Gilbert 
19205a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19215a09e398SHannes Reinecke 
19225a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19235a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19245a09e398SHannes Reinecke {
192501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19265a09e398SHannes Reinecke 	unsigned char *arr;
19275a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19285a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1929f347c268SYe Bin 	u32 alen, n, rlen;
1930f347c268SYe Bin 	int ret;
19315a09e398SHannes Reinecke 
1932773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19336f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19346f3cbf55SDouglas Gilbert 	if (! arr)
19356f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19365a09e398SHannes Reinecke 	/*
19375a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19385a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19395a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19405a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19415a09e398SHannes Reinecke 	 */
19425a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19435a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19445a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19455a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19465a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19475a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19485a09e398SHannes Reinecke 
19495a09e398SHannes Reinecke 	/*
19505a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19515a09e398SHannes Reinecke 	 */
19525a09e398SHannes Reinecke 	n = 4;
1953b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19545a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19555a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19565a09e398SHannes Reinecke 	} else {
19575a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1958773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19595a09e398SHannes Reinecke 	}
1960773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1961773642d9SDouglas Gilbert 	n += 2;
19625a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19645a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19655a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19665a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1968773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1969773642d9SDouglas Gilbert 	n += 2;
19705a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19715a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1972773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1973773642d9SDouglas Gilbert 	n += 2;
19745a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19755a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19765a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19775a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19785a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19795a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1980773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1981773642d9SDouglas Gilbert 	n += 2;
19825a09e398SHannes Reinecke 
19835a09e398SHannes Reinecke 	rlen = n - 4;
1984773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19855a09e398SHannes Reinecke 
19865a09e398SHannes Reinecke 	/*
19875a09e398SHannes Reinecke 	 * Return the smallest value of either
19885a09e398SHannes Reinecke 	 * - The allocated length
19895a09e398SHannes Reinecke 	 * - The constructed command length
19905a09e398SHannes Reinecke 	 * - The maximum array size
19915a09e398SHannes Reinecke 	 */
1992f347c268SYe Bin 	rlen = min(alen, n);
19935a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1994f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19955a09e398SHannes Reinecke 	kfree(arr);
19965a09e398SHannes Reinecke 	return ret;
19975a09e398SHannes Reinecke }
19985a09e398SHannes Reinecke 
1999fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
2000fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
200138d5c833SDouglas Gilbert {
200238d5c833SDouglas Gilbert 	bool rctd;
200338d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
200438d5c833SDouglas Gilbert 	u16 req_sa, u;
200538d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
200638d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
200738d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
200838d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
200938d5c833SDouglas Gilbert 	u8 *arr;
201038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
201138d5c833SDouglas Gilbert 
201238d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
201338d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
201438d5c833SDouglas Gilbert 	req_opcode = cmd[3];
201538d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
201638d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
20176d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
201838d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
201938d5c833SDouglas Gilbert 		return check_condition_result;
202038d5c833SDouglas Gilbert 	}
202138d5c833SDouglas Gilbert 	if (alloc_len > 8192)
202238d5c833SDouglas Gilbert 		a_len = 8192;
202338d5c833SDouglas Gilbert 	else
202438d5c833SDouglas Gilbert 		a_len = alloc_len;
202599531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
202638d5c833SDouglas Gilbert 	if (NULL == arr) {
202738d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
202838d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
202938d5c833SDouglas Gilbert 		return check_condition_result;
203038d5c833SDouglas Gilbert 	}
203138d5c833SDouglas Gilbert 	switch (reporting_opts) {
203238d5c833SDouglas Gilbert 	case 0:	/* all commands */
203338d5c833SDouglas Gilbert 		/* count number of commands */
203438d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
203538d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
203638d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
203738d5c833SDouglas Gilbert 				continue;
203838d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
203938d5c833SDouglas Gilbert 		}
204038d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
204138d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
204238d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
204338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
204438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
204538d5c833SDouglas Gilbert 				continue;
204638d5c833SDouglas Gilbert 			na = oip->num_attached;
204738d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
204838d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
204938d5c833SDouglas Gilbert 			if (rctd)
205038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
205138d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
205238d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
205338d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
205438d5c833SDouglas Gilbert 			if (rctd)
205538d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
205638d5c833SDouglas Gilbert 			r_oip = oip;
205738d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
205838d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
205938d5c833SDouglas Gilbert 					continue;
206038d5c833SDouglas Gilbert 				offset += bump;
206138d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
206238d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
206338d5c833SDouglas Gilbert 				if (rctd)
206438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
206538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
206638d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
206738d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
206838d5c833SDouglas Gilbert 						   arr + offset + 6);
206938d5c833SDouglas Gilbert 				if (rctd)
207038d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
207138d5c833SDouglas Gilbert 							   arr + offset + 8);
207238d5c833SDouglas Gilbert 			}
207338d5c833SDouglas Gilbert 			oip = r_oip;
207438d5c833SDouglas Gilbert 			offset += bump;
207538d5c833SDouglas Gilbert 		}
207638d5c833SDouglas Gilbert 		break;
207738d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
207838d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
207938d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
208038d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
208138d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
208238d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
208338d5c833SDouglas Gilbert 			supp = 1;
208438d5c833SDouglas Gilbert 			offset = 4;
208538d5c833SDouglas Gilbert 		} else {
208638d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
208738d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
208838d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
208938d5c833SDouglas Gilbert 							     2, 2);
209038d5c833SDouglas Gilbert 					kfree(arr);
209138d5c833SDouglas Gilbert 					return check_condition_result;
209238d5c833SDouglas Gilbert 				}
209338d5c833SDouglas Gilbert 				req_sa = 0;
209438d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
209538d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
209638d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
209738d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
209838d5c833SDouglas Gilbert 				return check_condition_result;
209938d5c833SDouglas Gilbert 			}
210038d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
210138d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
210238d5c833SDouglas Gilbert 				supp = 3;
210338d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
210438d5c833SDouglas Gilbert 				na = oip->num_attached;
210538d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
210638d5c833SDouglas Gilbert 				     ++k, ++oip) {
210738d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
210838d5c833SDouglas Gilbert 						break;
210938d5c833SDouglas Gilbert 				}
211038d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
211138d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
211238d5c833SDouglas Gilbert 				na = oip->num_attached;
211338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
211438d5c833SDouglas Gilbert 				     ++k, ++oip) {
211538d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
211638d5c833SDouglas Gilbert 						break;
211738d5c833SDouglas Gilbert 				}
211838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
211938d5c833SDouglas Gilbert 			} else
212038d5c833SDouglas Gilbert 				supp = 3;
212138d5c833SDouglas Gilbert 			if (3 == supp) {
212238d5c833SDouglas Gilbert 				u = oip->len_mask[0];
212338d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
212438d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
212538d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
212638d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
212738d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
212838d5c833SDouglas Gilbert 				offset = 4 + u;
212938d5c833SDouglas Gilbert 			} else
213038d5c833SDouglas Gilbert 				offset = 4;
213138d5c833SDouglas Gilbert 		}
213238d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
213338d5c833SDouglas Gilbert 		if (rctd) {
213438d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
213538d5c833SDouglas Gilbert 			offset += 12;
213638d5c833SDouglas Gilbert 		}
213738d5c833SDouglas Gilbert 		break;
213838d5c833SDouglas Gilbert 	default:
213938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
214038d5c833SDouglas Gilbert 		kfree(arr);
214138d5c833SDouglas Gilbert 		return check_condition_result;
214238d5c833SDouglas Gilbert 	}
214338d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
214438d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
214538d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
214638d5c833SDouglas Gilbert 	kfree(arr);
214738d5c833SDouglas Gilbert 	return errsts;
214838d5c833SDouglas Gilbert }
214938d5c833SDouglas Gilbert 
2150fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2151fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
215238d5c833SDouglas Gilbert {
215338d5c833SDouglas Gilbert 	bool repd;
215438d5c833SDouglas Gilbert 	u32 alloc_len, len;
215538d5c833SDouglas Gilbert 	u8 arr[16];
215638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
215738d5c833SDouglas Gilbert 
215838d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
215938d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
216038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
216138d5c833SDouglas Gilbert 	if (alloc_len < 4) {
216238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
216338d5c833SDouglas Gilbert 		return check_condition_result;
216438d5c833SDouglas Gilbert 	}
216538d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
216638d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
216738d5c833SDouglas Gilbert 	if (repd) {
216838d5c833SDouglas Gilbert 		arr[3] = 0xc;
216938d5c833SDouglas Gilbert 		len = 16;
217038d5c833SDouglas Gilbert 	} else
217138d5c833SDouglas Gilbert 		len = 4;
217238d5c833SDouglas Gilbert 
217338d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
217438d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
217538d5c833SDouglas Gilbert }
217638d5c833SDouglas Gilbert 
21771da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21781da177e4SLinus Torvalds 
21791da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21801da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21811da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21821da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21831da177e4SLinus Torvalds 
21841da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21851da177e4SLinus Torvalds 	if (1 == pcontrol)
21861da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21871da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21881da177e4SLinus Torvalds }
21891da177e4SLinus Torvalds 
21901da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21911da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21921da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21931da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21941da177e4SLinus Torvalds 
21951da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21961da177e4SLinus Torvalds 	if (1 == pcontrol)
21971da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21981da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21991da177e4SLinus Torvalds }
22001da177e4SLinus Torvalds 
22011da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
22021da177e4SLinus Torvalds {       /* Format device page for mode_sense */
22031da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
22041da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
22051da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2208773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2209773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2210773642d9SDouglas Gilbert 	if (sdebug_removable)
22111da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
22121da177e4SLinus Torvalds 	if (1 == pcontrol)
22131da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
22141da177e4SLinus Torvalds 	return sizeof(format_pg);
22151da177e4SLinus Torvalds }
22161da177e4SLinus Torvalds 
2217fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2218fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2219fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2220fd32119bSDouglas Gilbert 
22211da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22221da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2223cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2224cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2225cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22261da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22271da177e4SLinus Torvalds 
2228773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2229cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22301da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22311da177e4SLinus Torvalds 	if (1 == pcontrol)
2232cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2233cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2234cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22351da177e4SLinus Torvalds 	return sizeof(caching_pg);
22361da177e4SLinus Torvalds }
22371da177e4SLinus Torvalds 
2238fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2239fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2240fd32119bSDouglas Gilbert 
22411da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22421da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2243c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2244c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2245c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22461da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22471da177e4SLinus Torvalds 
2248773642d9SDouglas Gilbert 	if (sdebug_dsense)
22491da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2250c65b1445SDouglas Gilbert 	else
2251c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2252c6a44287SMartin K. Petersen 
2253773642d9SDouglas Gilbert 	if (sdebug_ato)
2254c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2255c6a44287SMartin K. Petersen 
22561da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22571da177e4SLinus Torvalds 	if (1 == pcontrol)
2258c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2259c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2260c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22611da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22621da177e4SLinus Torvalds }
22631da177e4SLinus Torvalds 
2264c65b1445SDouglas Gilbert 
22651da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22661da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2267c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22681da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2269c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2270c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2271c65b1445SDouglas Gilbert 
22721da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22731da177e4SLinus Torvalds 	if (1 == pcontrol)
2274c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2275c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2276c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22771da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22781da177e4SLinus Torvalds }
22791da177e4SLinus Torvalds 
2280c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2281c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2282c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2283c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2284c65b1445SDouglas Gilbert 
2285c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2286c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2287c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2288c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2289c65b1445SDouglas Gilbert }
2290c65b1445SDouglas Gilbert 
2291c65b1445SDouglas Gilbert 
2292c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2293c65b1445SDouglas Gilbert 			      int target_dev_id)
2294c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2295c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2296c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2297773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2298773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2299c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2300c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2301c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2302c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2303773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2304773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2305c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2306c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2307c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2308c65b1445SDouglas Gilbert 		};
2309c65b1445SDouglas Gilbert 	int port_a, port_b;
2310c65b1445SDouglas Gilbert 
23111b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
23121b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
23131b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
23141b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2315c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2316c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2317c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2318773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2319773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2320c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2321c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2322c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2323c65b1445SDouglas Gilbert }
2324c65b1445SDouglas Gilbert 
2325c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2326c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2327c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2328c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2329c65b1445SDouglas Gilbert 		};
2330c65b1445SDouglas Gilbert 
2331c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2332c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2333c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2334c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2335c65b1445SDouglas Gilbert }
2336c65b1445SDouglas Gilbert 
23371da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23381da177e4SLinus Torvalds 
2339fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2340fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23411da177e4SLinus Torvalds {
234223183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23431da177e4SLinus Torvalds 	unsigned char dev_spec;
234436e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
234536e07d7eSGeorge Kennedy 	int target_dev_id;
2346c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23471da177e4SLinus Torvalds 	unsigned char *ap;
23481da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
234901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2350d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23511da177e4SLinus Torvalds 
2352760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23531da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23541da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23551da177e4SLinus Torvalds 	subpcode = cmd[3];
23561da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2357760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2358760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
235964e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2360d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
236123183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
236223183910SDouglas Gilbert 	else
236323183910SDouglas Gilbert 		bd_len = 0;
2364773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23651da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23661da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2367cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23681da177e4SLinus Torvalds 		return check_condition_result;
23691da177e4SLinus Torvalds 	}
2370c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2371c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2372d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2373d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2374b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23759447b6ceSMartin K. Petersen 		if (sdebug_wp)
23769447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23779447b6ceSMartin K. Petersen 	} else
237823183910SDouglas Gilbert 		dev_spec = 0x0;
23791da177e4SLinus Torvalds 	if (msense_6) {
23801da177e4SLinus Torvalds 		arr[2] = dev_spec;
238123183910SDouglas Gilbert 		arr[3] = bd_len;
23821da177e4SLinus Torvalds 		offset = 4;
23831da177e4SLinus Torvalds 	} else {
23841da177e4SLinus Torvalds 		arr[3] = dev_spec;
238523183910SDouglas Gilbert 		if (16 == bd_len)
238623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
238723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23881da177e4SLinus Torvalds 		offset = 8;
23891da177e4SLinus Torvalds 	}
23901da177e4SLinus Torvalds 	ap = arr + offset;
239128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
239228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
239328898873SFUJITA Tomonori 
239423183910SDouglas Gilbert 	if (8 == bd_len) {
2395773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2396773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2397773642d9SDouglas Gilbert 		else
2398773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2399773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
240023183910SDouglas Gilbert 		offset += bd_len;
240123183910SDouglas Gilbert 		ap = arr + offset;
240223183910SDouglas Gilbert 	} else if (16 == bd_len) {
2403773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2404773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
240523183910SDouglas Gilbert 		offset += bd_len;
240623183910SDouglas Gilbert 		ap = arr + offset;
240723183910SDouglas Gilbert 	}
24081da177e4SLinus Torvalds 
2409c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2410c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
241122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24121da177e4SLinus Torvalds 		return check_condition_result;
24131da177e4SLinus Torvalds 	}
2414760f3b03SDouglas Gilbert 	bad_pcode = false;
2415760f3b03SDouglas Gilbert 
24161da177e4SLinus Torvalds 	switch (pcode) {
24171da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
24181da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
24191da177e4SLinus Torvalds 		offset += len;
24201da177e4SLinus Torvalds 		break;
24211da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
24221da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24231da177e4SLinus Torvalds 		offset += len;
24241da177e4SLinus Torvalds 		break;
24251da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2426760f3b03SDouglas Gilbert 		if (is_disk) {
24271da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24281da177e4SLinus Torvalds 			offset += len;
2429760f3b03SDouglas Gilbert 		} else
2430760f3b03SDouglas Gilbert 			bad_pcode = true;
24311da177e4SLinus Torvalds 		break;
24321da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2433d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24341da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24351da177e4SLinus Torvalds 			offset += len;
2436760f3b03SDouglas Gilbert 		} else
2437760f3b03SDouglas Gilbert 			bad_pcode = true;
24381da177e4SLinus Torvalds 		break;
24391da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24401da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24411da177e4SLinus Torvalds 		offset += len;
24421da177e4SLinus Torvalds 		break;
2443c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2444c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
244522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2446c65b1445SDouglas Gilbert 			return check_condition_result;
2447c65b1445SDouglas Gilbert 		}
2448c65b1445SDouglas Gilbert 		len = 0;
2449c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2450c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2451c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2452c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2453c65b1445SDouglas Gilbert 						  target_dev_id);
2454c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2455c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2456c65b1445SDouglas Gilbert 		offset += len;
2457c65b1445SDouglas Gilbert 		break;
24581da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24591da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24601da177e4SLinus Torvalds 		offset += len;
24611da177e4SLinus Torvalds 		break;
24621da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2463c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24641da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24651da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2466760f3b03SDouglas Gilbert 			if (is_disk) {
2467760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2468760f3b03SDouglas Gilbert 						      target);
2469760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2470760f3b03SDouglas Gilbert 						       target);
2471d36da305SDouglas Gilbert 			} else if (is_zbc) {
2472d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2473d36da305SDouglas Gilbert 						       target);
2474760f3b03SDouglas Gilbert 			}
24751da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2476c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2477c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2478c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2479c65b1445SDouglas Gilbert 						  target, target_dev_id);
2480c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2481c65b1445SDouglas Gilbert 			}
24821da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2483760f3b03SDouglas Gilbert 			offset += len;
2484c65b1445SDouglas Gilbert 		} else {
248522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2486c65b1445SDouglas Gilbert 			return check_condition_result;
2487c65b1445SDouglas Gilbert 		}
24881da177e4SLinus Torvalds 		break;
24891da177e4SLinus Torvalds 	default:
2490760f3b03SDouglas Gilbert 		bad_pcode = true;
2491760f3b03SDouglas Gilbert 		break;
2492760f3b03SDouglas Gilbert 	}
2493760f3b03SDouglas Gilbert 	if (bad_pcode) {
249422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24951da177e4SLinus Torvalds 		return check_condition_result;
24961da177e4SLinus Torvalds 	}
24971da177e4SLinus Torvalds 	if (msense_6)
24981da177e4SLinus Torvalds 		arr[0] = offset - 1;
2499773642d9SDouglas Gilbert 	else
2500773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
250136e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
25021da177e4SLinus Torvalds }
25031da177e4SLinus Torvalds 
2504c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2505c65b1445SDouglas Gilbert 
2506fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2507fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2508c65b1445SDouglas Gilbert {
2509c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2510c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2511c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
251201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2513c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2514c65b1445SDouglas Gilbert 
2515c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2516c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2517c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2518773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2519c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
252022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2521c65b1445SDouglas Gilbert 		return check_condition_result;
2522c65b1445SDouglas Gilbert 	}
2523c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2524c65b1445SDouglas Gilbert 	if (-1 == res)
2525773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2526773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2527cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2528cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2529cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2530773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2531773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2532e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2533e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
253422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2535c65b1445SDouglas Gilbert 		return check_condition_result;
2536c65b1445SDouglas Gilbert 	}
2537c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2538c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2539c65b1445SDouglas Gilbert 	if (ps) {
254022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2541c65b1445SDouglas Gilbert 		return check_condition_result;
2542c65b1445SDouglas Gilbert 	}
2543c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2544773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2545c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2546c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2547cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2548c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2549c65b1445SDouglas Gilbert 		return check_condition_result;
2550c65b1445SDouglas Gilbert 	}
2551c65b1445SDouglas Gilbert 	switch (mpage) {
2552cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2553cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2554cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2555cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2556cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2557cbf67842SDouglas Gilbert 		}
2558cbf67842SDouglas Gilbert 		break;
2559c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2560c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2561c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2562c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25639447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25649447b6ceSMartin K. Petersen 				sdebug_wp = true;
25659447b6ceSMartin K. Petersen 			else
25669447b6ceSMartin K. Petersen 				sdebug_wp = false;
2567773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2568cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2569c65b1445SDouglas Gilbert 		}
2570c65b1445SDouglas Gilbert 		break;
2571c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2572c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2573c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2574c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2575cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2576c65b1445SDouglas Gilbert 		}
2577c65b1445SDouglas Gilbert 		break;
2578c65b1445SDouglas Gilbert 	default:
2579c65b1445SDouglas Gilbert 		break;
2580c65b1445SDouglas Gilbert 	}
258122017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2582c65b1445SDouglas Gilbert 	return check_condition_result;
2583cbf67842SDouglas Gilbert set_mode_changed_ua:
2584cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2585cbf67842SDouglas Gilbert 	return 0;
2586c65b1445SDouglas Gilbert }
2587c65b1445SDouglas Gilbert 
2588c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2589c65b1445SDouglas Gilbert {
2590c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2591c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2592c65b1445SDouglas Gilbert 		};
2593c65b1445SDouglas Gilbert 
2594c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2595c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2596c65b1445SDouglas Gilbert }
2597c65b1445SDouglas Gilbert 
2598c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2599c65b1445SDouglas Gilbert {
2600c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2601c65b1445SDouglas Gilbert 		};
2602c65b1445SDouglas Gilbert 
2603c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2604c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2605c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2606c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2607c65b1445SDouglas Gilbert 	}
2608c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2609c65b1445SDouglas Gilbert }
2610c65b1445SDouglas Gilbert 
26110790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr)
26120790797aSDouglas Gilbert {
26130790797aSDouglas Gilbert 	unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
26140790797aSDouglas Gilbert 					 0x0, 40, 72, 0xff, 45, 18, 0, 0,
26150790797aSDouglas Gilbert 					 0x1, 0x0, 0x23, 0x8,
26160790797aSDouglas Gilbert 					 0x0, 55, 72, 35, 55, 45, 0, 0,
26170790797aSDouglas Gilbert 		};
26180790797aSDouglas Gilbert 
26190790797aSDouglas Gilbert 	memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
26200790797aSDouglas Gilbert 	return sizeof(env_rep_l_spg);
26210790797aSDouglas Gilbert }
26220790797aSDouglas Gilbert 
2623c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2624c65b1445SDouglas Gilbert 
2625c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2626c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2627c65b1445SDouglas Gilbert {
262836e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
262936e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2630c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
263101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2632c65b1445SDouglas Gilbert 
2633c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2634c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2635c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2636c65b1445SDouglas Gilbert 	if (ppc || sp) {
263722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2638c65b1445SDouglas Gilbert 		return check_condition_result;
2639c65b1445SDouglas Gilbert 	}
2640c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
264123183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2642773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2643c65b1445SDouglas Gilbert 	arr[0] = pcode;
264423183910SDouglas Gilbert 	if (0 == subpcode) {
2645c65b1445SDouglas Gilbert 		switch (pcode) {
2646c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2647c65b1445SDouglas Gilbert 			n = 4;
2648c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2649c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2650c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2651c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2652c65b1445SDouglas Gilbert 			break;
2653c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2654c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2655c65b1445SDouglas Gilbert 			break;
2656c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2657c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2658c65b1445SDouglas Gilbert 			break;
2659c65b1445SDouglas Gilbert 		default:
266022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2661c65b1445SDouglas Gilbert 			return check_condition_result;
2662c65b1445SDouglas Gilbert 		}
266323183910SDouglas Gilbert 	} else if (0xff == subpcode) {
266423183910SDouglas Gilbert 		arr[0] |= 0x40;
266523183910SDouglas Gilbert 		arr[1] = subpcode;
266623183910SDouglas Gilbert 		switch (pcode) {
266723183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
266823183910SDouglas Gilbert 			n = 4;
266923183910SDouglas Gilbert 			arr[n++] = 0x0;
267023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
267123183910SDouglas Gilbert 			arr[n++] = 0x0;
267223183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
267323183910SDouglas Gilbert 			arr[n++] = 0xd;
267423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26750790797aSDouglas Gilbert 			arr[n++] = 0xd;
26760790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26770790797aSDouglas Gilbert 			arr[n++] = 0xd;
26780790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0xd subpages */
267923183910SDouglas Gilbert 			arr[n++] = 0x2f;
268023183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
26810790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26820790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0x2f subpages */
268323183910SDouglas Gilbert 			arr[3] = n - 4;
268423183910SDouglas Gilbert 			break;
268523183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
268623183910SDouglas Gilbert 			n = 4;
268723183910SDouglas Gilbert 			arr[n++] = 0xd;
268823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26890790797aSDouglas Gilbert 			arr[n++] = 0xd;
26900790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26910790797aSDouglas Gilbert 			arr[n++] = 0xd;
26920790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
269323183910SDouglas Gilbert 			arr[3] = n - 4;
269423183910SDouglas Gilbert 			break;
269523183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
269623183910SDouglas Gilbert 			n = 4;
269723183910SDouglas Gilbert 			arr[n++] = 0x2f;
269823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
26990790797aSDouglas Gilbert 			arr[n++] = 0x2f;
27000790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
270123183910SDouglas Gilbert 			arr[3] = n - 4;
270223183910SDouglas Gilbert 			break;
270323183910SDouglas Gilbert 		default:
270422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
270523183910SDouglas Gilbert 			return check_condition_result;
270623183910SDouglas Gilbert 		}
27070790797aSDouglas Gilbert 	} else if (subpcode > 0) {
27080790797aSDouglas Gilbert 		arr[0] |= 0x40;
27090790797aSDouglas Gilbert 		arr[1] = subpcode;
27100790797aSDouglas Gilbert 		if (pcode == 0xd && subpcode == 1)
27110790797aSDouglas Gilbert 			arr[3] = resp_env_rep_l_spg(arr + 4);
27120790797aSDouglas Gilbert 		else {
27130790797aSDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
27140790797aSDouglas Gilbert 			return check_condition_result;
27150790797aSDouglas Gilbert 		}
271623183910SDouglas Gilbert 	} else {
271722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
271823183910SDouglas Gilbert 		return check_condition_result;
271923183910SDouglas Gilbert 	}
272036e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2721c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
272236e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2723c65b1445SDouglas Gilbert }
2724c65b1445SDouglas Gilbert 
2725f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2726f0d1cf93SDouglas Gilbert {
2727f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2728f0d1cf93SDouglas Gilbert }
2729f0d1cf93SDouglas Gilbert 
2730f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2731f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2732f0d1cf93SDouglas Gilbert {
27334a5fc1c6SDamien Le Moal 	u32 zno = lba >> devip->zsize_shift;
27344a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp;
27354a5fc1c6SDamien Le Moal 
27364a5fc1c6SDamien Le Moal 	if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones)
27374a5fc1c6SDamien Le Moal 		return &devip->zstate[zno];
27384a5fc1c6SDamien Le Moal 
27394a5fc1c6SDamien Le Moal 	/*
27404a5fc1c6SDamien Le Moal 	 * If the zone capacity is less than the zone size, adjust for gap
27414a5fc1c6SDamien Le Moal 	 * zones.
27424a5fc1c6SDamien Le Moal 	 */
27434a5fc1c6SDamien Le Moal 	zno = 2 * zno - devip->nr_conv_zones;
27444a5fc1c6SDamien Le Moal 	WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones);
27454a5fc1c6SDamien Le Moal 	zsp = &devip->zstate[zno];
27464a5fc1c6SDamien Le Moal 	if (lba >= zsp->z_start + zsp->z_size)
27474a5fc1c6SDamien Le Moal 		zsp++;
27484a5fc1c6SDamien Le Moal 	WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size);
27494a5fc1c6SDamien Le Moal 	return zsp;
2750f0d1cf93SDouglas Gilbert }
2751f0d1cf93SDouglas Gilbert 
2752f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2753f0d1cf93SDouglas Gilbert {
275435dbe2b9SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_CNV;
2755f0d1cf93SDouglas Gilbert }
2756f0d1cf93SDouglas Gilbert 
27574a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp)
27584a5fc1c6SDamien Le Moal {
27594a5fc1c6SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_GAP;
27604a5fc1c6SDamien Le Moal }
27614a5fc1c6SDamien Le Moal 
27624a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp)
27634a5fc1c6SDamien Le Moal {
27644a5fc1c6SDamien Le Moal 	return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp);
27654a5fc1c6SDamien Le Moal }
27664a5fc1c6SDamien Le Moal 
2767f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2768f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2769f0d1cf93SDouglas Gilbert {
2770f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2771f0d1cf93SDouglas Gilbert 
27724a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2773f0d1cf93SDouglas Gilbert 		return;
2774f0d1cf93SDouglas Gilbert 
2775f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2776f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2777f0d1cf93SDouglas Gilbert 		return;
2778f0d1cf93SDouglas Gilbert 
2779f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2780f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2781f0d1cf93SDouglas Gilbert 	else
2782f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2783f0d1cf93SDouglas Gilbert 
2784f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2785f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2786f0d1cf93SDouglas Gilbert 	} else {
2787f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2788f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2789f0d1cf93SDouglas Gilbert 	}
2790f0d1cf93SDouglas Gilbert }
2791f0d1cf93SDouglas Gilbert 
2792f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2793f0d1cf93SDouglas Gilbert {
2794f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2795f0d1cf93SDouglas Gilbert 	unsigned int i;
2796f0d1cf93SDouglas Gilbert 
2797f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2798f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2799f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2800f0d1cf93SDouglas Gilbert 			return;
2801f0d1cf93SDouglas Gilbert 		}
2802f0d1cf93SDouglas Gilbert 	}
2803f0d1cf93SDouglas Gilbert }
2804f0d1cf93SDouglas Gilbert 
2805f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2806f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2807f0d1cf93SDouglas Gilbert {
2808f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2809f0d1cf93SDouglas Gilbert 
28104a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2811f0d1cf93SDouglas Gilbert 		return;
2812f0d1cf93SDouglas Gilbert 
2813f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2814f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2815f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2816f0d1cf93SDouglas Gilbert 		return;
2817f0d1cf93SDouglas Gilbert 
2818f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2819f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2820f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2821f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2822f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2823f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2824f0d1cf93SDouglas Gilbert 
2825f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2826f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2827f0d1cf93SDouglas Gilbert 	if (explicit) {
2828f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2829f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2830f0d1cf93SDouglas Gilbert 	} else {
2831f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2832f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2833f0d1cf93SDouglas Gilbert 	}
2834f0d1cf93SDouglas Gilbert }
2835f0d1cf93SDouglas Gilbert 
2836566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip,
2837566d3c57SDamien Le Moal 				     struct sdeb_zone_state *zsp)
2838566d3c57SDamien Le Moal {
2839566d3c57SDamien Le Moal 	switch (zsp->z_cond) {
2840566d3c57SDamien Le Moal 	case ZC2_IMPLICIT_OPEN:
2841566d3c57SDamien Le Moal 		devip->nr_imp_open--;
2842566d3c57SDamien Le Moal 		break;
2843566d3c57SDamien Le Moal 	case ZC3_EXPLICIT_OPEN:
2844566d3c57SDamien Le Moal 		devip->nr_exp_open--;
2845566d3c57SDamien Le Moal 		break;
2846566d3c57SDamien Le Moal 	default:
2847566d3c57SDamien Le Moal 		WARN_ONCE(true, "Invalid zone %llu condition %x\n",
2848566d3c57SDamien Le Moal 			  zsp->z_start, zsp->z_cond);
2849566d3c57SDamien Le Moal 		break;
2850566d3c57SDamien Le Moal 	}
2851566d3c57SDamien Le Moal 	zsp->z_cond = ZC5_FULL;
2852566d3c57SDamien Le Moal }
2853566d3c57SDamien Le Moal 
2854f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2855f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2856f0d1cf93SDouglas Gilbert {
2857f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
285864e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2859f0d1cf93SDouglas Gilbert 
28604a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2861f0d1cf93SDouglas Gilbert 		return;
2862f0d1cf93SDouglas Gilbert 
286335dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2864f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
286564e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2866566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
286764e14eceSDamien Le Moal 		return;
286864e14eceSDamien Le Moal 	}
286964e14eceSDamien Le Moal 
287064e14eceSDamien Le Moal 	while (num) {
287164e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
287264e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
287364e14eceSDamien Le Moal 
287464e14eceSDamien Le Moal 		end = lba + num;
287564e14eceSDamien Le Moal 		if (end >= zend) {
287664e14eceSDamien Le Moal 			n = zend - lba;
287764e14eceSDamien Le Moal 			zsp->z_wp = zend;
287864e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
287964e14eceSDamien Le Moal 			n = num;
288064e14eceSDamien Le Moal 			zsp->z_wp = end;
288164e14eceSDamien Le Moal 		} else {
288264e14eceSDamien Le Moal 			n = num;
288364e14eceSDamien Le Moal 		}
288464e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2885566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
288664e14eceSDamien Le Moal 
288764e14eceSDamien Le Moal 		num -= n;
288864e14eceSDamien Le Moal 		lba += n;
288964e14eceSDamien Le Moal 		if (num) {
289064e14eceSDamien Le Moal 			zsp++;
289164e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
289264e14eceSDamien Le Moal 		}
289364e14eceSDamien Le Moal 	}
2894f0d1cf93SDouglas Gilbert }
2895f0d1cf93SDouglas Gilbert 
2896f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
28979447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
28981da177e4SLinus Torvalds {
2899f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2900f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2901f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2902f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2903f0d1cf93SDouglas Gilbert 
2904f0d1cf93SDouglas Gilbert 	if (!write) {
290564e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
290664e14eceSDamien Le Moal 			return 0;
290764e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
29084a5fc1c6SDamien Le Moal 		if (zsp->z_type != zsp_end->z_type) {
2909f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2910f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2911f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2912f0d1cf93SDouglas Gilbert 			return check_condition_result;
2913f0d1cf93SDouglas Gilbert 		}
2914f0d1cf93SDouglas Gilbert 		return 0;
2915f0d1cf93SDouglas Gilbert 	}
2916f0d1cf93SDouglas Gilbert 
29174a5fc1c6SDamien Le Moal 	/* Writing into a gap zone is not allowed */
29184a5fc1c6SDamien Le Moal 	if (zbc_zone_is_gap(zsp)) {
29194a5fc1c6SDamien Le Moal 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE,
29204a5fc1c6SDamien Le Moal 				ATTEMPT_ACCESS_GAP);
29214a5fc1c6SDamien Le Moal 		return check_condition_result;
29224a5fc1c6SDamien Le Moal 	}
29234a5fc1c6SDamien Le Moal 
2924f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2925f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2926f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2927f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2928f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2929f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2930f0d1cf93SDouglas Gilbert 			return check_condition_result;
2931f0d1cf93SDouglas Gilbert 		}
2932f0d1cf93SDouglas Gilbert 		return 0;
2933f0d1cf93SDouglas Gilbert 	}
2934f0d1cf93SDouglas Gilbert 
293535dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2936f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2937f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2938f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2939f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2940f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2941f0d1cf93SDouglas Gilbert 			return check_condition_result;
2942f0d1cf93SDouglas Gilbert 		}
2943f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2944f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2945f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2946f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2947f0d1cf93SDouglas Gilbert 			return check_condition_result;
2948f0d1cf93SDouglas Gilbert 		}
2949f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2950f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2951f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2952f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2953f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2954f0d1cf93SDouglas Gilbert 			return check_condition_result;
2955f0d1cf93SDouglas Gilbert 		}
295664e14eceSDamien Le Moal 	}
2957f0d1cf93SDouglas Gilbert 
2958f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2959f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2960f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2961f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2962f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2963f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2964f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2965f0d1cf93SDouglas Gilbert 			return check_condition_result;
2966f0d1cf93SDouglas Gilbert 		}
2967f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2968f0d1cf93SDouglas Gilbert 	}
2969f0d1cf93SDouglas Gilbert 
2970f0d1cf93SDouglas Gilbert 	return 0;
2971f0d1cf93SDouglas Gilbert }
2972f0d1cf93SDouglas Gilbert 
2973f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2974f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2975f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2976f0d1cf93SDouglas Gilbert {
2977f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2978f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2979f0d1cf93SDouglas Gilbert 
2980c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
298122017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
29821da177e4SLinus Torvalds 		return check_condition_result;
29831da177e4SLinus Torvalds 	}
2984c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2985c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
298622017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2987cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2988c65b1445SDouglas Gilbert 		return check_condition_result;
2989c65b1445SDouglas Gilbert 	}
29909447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
29919447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29929447b6ceSMartin K. Petersen 		return check_condition_result;
29939447b6ceSMartin K. Petersen 	}
2994f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2995f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2996f0d1cf93SDouglas Gilbert 
299719789100SFUJITA Tomonori 	return 0;
299819789100SFUJITA Tomonori }
299919789100SFUJITA Tomonori 
3000b6ff8ca7SDouglas Gilbert /*
3001b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
3002b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
3003b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
3004b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
3005b6ff8ca7SDouglas Gilbert  */
3006b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
3007b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
300887c715dcSDouglas Gilbert {
3009b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
3010b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
3011b6ff8ca7SDouglas Gilbert 		return NULL;
3012b6ff8ca7SDouglas Gilbert 	}
3013b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
301487c715dcSDouglas Gilbert }
301587c715dcSDouglas Gilbert 
3016a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
301787c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
301887c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
301919789100SFUJITA Tomonori {
302019789100SFUJITA Tomonori 	int ret;
3021c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
3022a4517511SAkinobu Mita 	enum dma_data_direction dir;
302387c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
302487c715dcSDouglas Gilbert 	u8 *fsp;
302519789100SFUJITA Tomonori 
3026c2248fc9SDouglas Gilbert 	if (do_write) {
3027a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
30284f2c8bf6SDouglas Gilbert 		write_since_sync = true;
3029a4517511SAkinobu Mita 	} else {
3030a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
3031a4517511SAkinobu Mita 	}
3032a4517511SAkinobu Mita 
303387c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
3034a4517511SAkinobu Mita 		return 0;
303587c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
3036a4517511SAkinobu Mita 		return -1;
303787c715dcSDouglas Gilbert 	fsp = sip->storep;
303819789100SFUJITA Tomonori 
303919789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
304019789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
304119789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
304219789100SFUJITA Tomonori 
3043386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
304487c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
30450a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
3046773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
3047a4517511SAkinobu Mita 		return ret;
3048a4517511SAkinobu Mita 
3049a4517511SAkinobu Mita 	if (rest) {
3050386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
305187c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
30520a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
30530a7e69c7SDouglas Gilbert 			    do_write);
3054a4517511SAkinobu Mita 	}
305519789100SFUJITA Tomonori 
305619789100SFUJITA Tomonori 	return ret;
305719789100SFUJITA Tomonori }
305819789100SFUJITA Tomonori 
305987c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
306087c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
306187c715dcSDouglas Gilbert {
306287c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
306387c715dcSDouglas Gilbert 
306487c715dcSDouglas Gilbert 	if (!sdb->length)
306587c715dcSDouglas Gilbert 		return 0;
306687c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
306787c715dcSDouglas Gilbert 		return -1;
306887c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
306987c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
307087c715dcSDouglas Gilbert }
307187c715dcSDouglas Gilbert 
307287c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
307387c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
307438d5c833SDouglas Gilbert  * return false. */
307587c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
3076c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
307738d5c833SDouglas Gilbert {
307838d5c833SDouglas Gilbert 	bool res;
307938d5c833SDouglas Gilbert 	u64 block, rest = 0;
308038d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
3081773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
308287c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
308338d5c833SDouglas Gilbert 
308438d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
308538d5c833SDouglas Gilbert 	if (block + num > store_blks)
308638d5c833SDouglas Gilbert 		rest = block + num - store_blks;
308738d5c833SDouglas Gilbert 
308887c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
308938d5c833SDouglas Gilbert 	if (!res)
309038d5c833SDouglas Gilbert 		return res;
309138d5c833SDouglas Gilbert 	if (rest)
309287c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
309338d5c833SDouglas Gilbert 			     rest * lb_size);
309438d5c833SDouglas Gilbert 	if (!res)
309538d5c833SDouglas Gilbert 		return res;
3096c3e2fe92SDouglas Gilbert 	if (compare_only)
3097c3e2fe92SDouglas Gilbert 		return true;
309838d5c833SDouglas Gilbert 	arr += num * lb_size;
309987c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
310038d5c833SDouglas Gilbert 	if (rest)
310187c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
310238d5c833SDouglas Gilbert 	return res;
310338d5c833SDouglas Gilbert }
310438d5c833SDouglas Gilbert 
310551d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3106beb40ea4SAkinobu Mita {
310751d648afSAkinobu Mita 	__be16 csum;
3108beb40ea4SAkinobu Mita 
3109773642d9SDouglas Gilbert 	if (sdebug_guard)
311051d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
311151d648afSAkinobu Mita 	else
3112beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
311351d648afSAkinobu Mita 
3114beb40ea4SAkinobu Mita 	return csum;
3115beb40ea4SAkinobu Mita }
3116beb40ea4SAkinobu Mita 
31176ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3118beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3119beb40ea4SAkinobu Mita {
3120773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3121beb40ea4SAkinobu Mita 
3122beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3123c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3124beb40ea4SAkinobu Mita 			(unsigned long)sector,
3125beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3126beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3127beb40ea4SAkinobu Mita 		return 0x01;
3128beb40ea4SAkinobu Mita 	}
31298475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3130beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3131c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3132c1287970STomas Winkler 			(unsigned long)sector);
3133beb40ea4SAkinobu Mita 		return 0x03;
3134beb40ea4SAkinobu Mita 	}
31358475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3136beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3137c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3138c1287970STomas Winkler 			(unsigned long)sector);
3139beb40ea4SAkinobu Mita 		return 0x03;
3140beb40ea4SAkinobu Mita 	}
3141beb40ea4SAkinobu Mita 	return 0;
3142beb40ea4SAkinobu Mita }
3143beb40ea4SAkinobu Mita 
314487c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
314565f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3146c6a44287SMartin K. Petersen {
3147be4e11beSAkinobu Mita 	size_t resid;
3148c6a44287SMartin K. Petersen 	void *paddr;
314987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3150b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
315187c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
315214faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3153be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3154c6a44287SMartin K. Petersen 
3155e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3156e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3157c6a44287SMartin K. Petersen 
315887c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
315987c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3160be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3161be4e11beSAkinobu Mita 
3162be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
316387c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
316487c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3165be4e11beSAkinobu Mita 		size_t rest = 0;
316614faa944SAkinobu Mita 
316714faa944SAkinobu Mita 		if (dif_store_end < start + len)
316814faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3169c6a44287SMartin K. Petersen 
3170be4e11beSAkinobu Mita 		paddr = miter.addr;
317114faa944SAkinobu Mita 
317265f72f2aSAkinobu Mita 		if (read)
317365f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
317465f72f2aSAkinobu Mita 		else
317565f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
317665f72f2aSAkinobu Mita 
317765f72f2aSAkinobu Mita 		if (rest) {
317865f72f2aSAkinobu Mita 			if (read)
317914faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
318065f72f2aSAkinobu Mita 			else
318165f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
318265f72f2aSAkinobu Mita 		}
3183c6a44287SMartin K. Petersen 
3184e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3185c6a44287SMartin K. Petersen 		resid -= len;
3186c6a44287SMartin K. Petersen 	}
3187be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3188bb8c063cSAkinobu Mita }
3189c6a44287SMartin K. Petersen 
319087c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3191bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3192bb8c063cSAkinobu Mita {
3193f7be6772SMartin K. Petersen 	int ret = 0;
3194bb8c063cSAkinobu Mita 	unsigned int i;
3195bb8c063cSAkinobu Mita 	sector_t sector;
319687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3197b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
319887c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3199bb8c063cSAkinobu Mita 
3200c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3201bb8c063cSAkinobu Mita 		sector = start_sec + i;
320287c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3203bb8c063cSAkinobu Mita 
320451d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3205bb8c063cSAkinobu Mita 			continue;
3206bb8c063cSAkinobu Mita 
3207f7be6772SMartin K. Petersen 		/*
3208f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3209f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3210f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3211f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3212f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3213f7be6772SMartin K. Petersen 		 */
3214f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3215f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3216f7be6772SMartin K. Petersen 					 sector, ei_lba);
3217bb8c063cSAkinobu Mita 			if (ret) {
3218bb8c063cSAkinobu Mita 				dif_errors++;
3219f7be6772SMartin K. Petersen 				break;
3220f7be6772SMartin K. Petersen 			}
3221bb8c063cSAkinobu Mita 		}
3222bb8c063cSAkinobu Mita 	}
3223bb8c063cSAkinobu Mita 
322487c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3225c6a44287SMartin K. Petersen 	dix_reads++;
3226c6a44287SMartin K. Petersen 
3227f7be6772SMartin K. Petersen 	return ret;
3228c6a44287SMartin K. Petersen }
3229c6a44287SMartin K. Petersen 
32307109f370SDouglas Gilbert static inline void
32317109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip)
32327109f370SDouglas Gilbert {
3233e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3234e9c47801SDamien Le Moal 		if (sip)
3235e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3236e9c47801SDamien Le Moal 		else
3237e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3238e9c47801SDamien Le Moal 	} else {
32397109f370SDouglas Gilbert 		if (sip)
32407109f370SDouglas Gilbert 			read_lock(&sip->macc_lck);
32417109f370SDouglas Gilbert 		else
32427109f370SDouglas Gilbert 			read_lock(&sdeb_fake_rw_lck);
32437109f370SDouglas Gilbert 	}
3244e9c47801SDamien Le Moal }
32457109f370SDouglas Gilbert 
32467109f370SDouglas Gilbert static inline void
32477109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip)
32487109f370SDouglas Gilbert {
3249e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3250e9c47801SDamien Le Moal 		if (sip)
3251e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3252e9c47801SDamien Le Moal 		else
3253e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3254e9c47801SDamien Le Moal 	} else {
32557109f370SDouglas Gilbert 		if (sip)
32567109f370SDouglas Gilbert 			read_unlock(&sip->macc_lck);
32577109f370SDouglas Gilbert 		else
32587109f370SDouglas Gilbert 			read_unlock(&sdeb_fake_rw_lck);
32597109f370SDouglas Gilbert 	}
3260e9c47801SDamien Le Moal }
32617109f370SDouglas Gilbert 
32627109f370SDouglas Gilbert static inline void
32637109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip)
32647109f370SDouglas Gilbert {
3265e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3266e9c47801SDamien Le Moal 		if (sip)
3267e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3268e9c47801SDamien Le Moal 		else
3269e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3270e9c47801SDamien Le Moal 	} else {
32717109f370SDouglas Gilbert 		if (sip)
32727109f370SDouglas Gilbert 			write_lock(&sip->macc_lck);
32737109f370SDouglas Gilbert 		else
32747109f370SDouglas Gilbert 			write_lock(&sdeb_fake_rw_lck);
32757109f370SDouglas Gilbert 	}
3276e9c47801SDamien Le Moal }
32777109f370SDouglas Gilbert 
32787109f370SDouglas Gilbert static inline void
32797109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip)
32807109f370SDouglas Gilbert {
3281e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3282e9c47801SDamien Le Moal 		if (sip)
3283e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3284e9c47801SDamien Le Moal 		else
3285e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3286e9c47801SDamien Le Moal 	} else {
32877109f370SDouglas Gilbert 		if (sip)
32887109f370SDouglas Gilbert 			write_unlock(&sip->macc_lck);
32897109f370SDouglas Gilbert 		else
32907109f370SDouglas Gilbert 			write_unlock(&sdeb_fake_rw_lck);
32917109f370SDouglas Gilbert 	}
3292e9c47801SDamien Le Moal }
32937109f370SDouglas Gilbert 
3294fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
329519789100SFUJITA Tomonori {
329687c715dcSDouglas Gilbert 	bool check_prot;
3297c2248fc9SDouglas Gilbert 	u32 num;
3298c2248fc9SDouglas Gilbert 	u32 ei_lba;
329919789100SFUJITA Tomonori 	int ret;
330087c715dcSDouglas Gilbert 	u64 lba;
3301b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
330287c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
330319789100SFUJITA Tomonori 
3304c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3305c2248fc9SDouglas Gilbert 	case READ_16:
3306c2248fc9SDouglas Gilbert 		ei_lba = 0;
3307c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3308c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3309c2248fc9SDouglas Gilbert 		check_prot = true;
3310c2248fc9SDouglas Gilbert 		break;
3311c2248fc9SDouglas Gilbert 	case READ_10:
3312c2248fc9SDouglas Gilbert 		ei_lba = 0;
3313c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3314c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3315c2248fc9SDouglas Gilbert 		check_prot = true;
3316c2248fc9SDouglas Gilbert 		break;
3317c2248fc9SDouglas Gilbert 	case READ_6:
3318c2248fc9SDouglas Gilbert 		ei_lba = 0;
3319c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3320c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3321c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3322c2248fc9SDouglas Gilbert 		check_prot = true;
3323c2248fc9SDouglas Gilbert 		break;
3324c2248fc9SDouglas Gilbert 	case READ_12:
3325c2248fc9SDouglas Gilbert 		ei_lba = 0;
3326c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3327c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3328c2248fc9SDouglas Gilbert 		check_prot = true;
3329c2248fc9SDouglas Gilbert 		break;
3330c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3331c2248fc9SDouglas Gilbert 		ei_lba = 0;
3332c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3333c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3334c2248fc9SDouglas Gilbert 		check_prot = false;
3335c2248fc9SDouglas Gilbert 		break;
3336c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3337c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3338c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3339c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3340c2248fc9SDouglas Gilbert 		check_prot = false;
3341c2248fc9SDouglas Gilbert 		break;
3342c2248fc9SDouglas Gilbert 	}
3343f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
33448475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3345c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3346c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3347c2248fc9SDouglas Gilbert 			return check_condition_result;
3348c2248fc9SDouglas Gilbert 		}
33498475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
33508475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3351c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3352c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3353c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3354c2248fc9SDouglas Gilbert 	}
33553a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
33563a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3357c2248fc9SDouglas Gilbert 		num /= 2;
33583a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3359c2248fc9SDouglas Gilbert 	}
3360c2248fc9SDouglas Gilbert 
33619447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
33629447b6ceSMartin K. Petersen 	if (ret)
33639447b6ceSMartin K. Petersen 		return ret;
3364f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3365d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3366d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3367c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3368c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3369c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3370c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3371c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
337232f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
337332f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3374c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3375c65b1445SDouglas Gilbert 		}
3376c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
33771da177e4SLinus Torvalds 		return check_condition_result;
33781da177e4SLinus Torvalds 	}
3379c6a44287SMartin K. Petersen 
33807109f370SDouglas Gilbert 	sdeb_read_lock(sip);
33816c78cc06SAkinobu Mita 
3382c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3383f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3384f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3385f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3386f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33877109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3388f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3389f7be6772SMartin K. Petersen 				return check_condition_result;
3390f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
33917109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3392f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3393c6a44287SMartin K. Petersen 				return illegal_condition_result;
3394c6a44287SMartin K. Petersen 			}
3395f7be6772SMartin K. Petersen 			break;
3396f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3397f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33987109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3399f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3400f7be6772SMartin K. Petersen 				return check_condition_result;
3401f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
34027109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3403f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3404f7be6772SMartin K. Petersen 				return illegal_condition_result;
3405f7be6772SMartin K. Petersen 			}
3406f7be6772SMartin K. Petersen 			break;
3407f7be6772SMartin K. Petersen 		}
3408c6a44287SMartin K. Petersen 	}
3409c6a44287SMartin K. Petersen 
341087c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
34117109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
3412f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3413a4517511SAkinobu Mita 		return DID_ERROR << 16;
3414a4517511SAkinobu Mita 
341542d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3416a4517511SAkinobu Mita 
34173a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
34183a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
34193a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
34203a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
34213a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3422c2248fc9SDouglas Gilbert 			return check_condition_result;
34233a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3424c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3425c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
34263a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3427c2248fc9SDouglas Gilbert 			return illegal_condition_result;
34283a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3429c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
34303a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3431c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3432c2248fc9SDouglas Gilbert 		}
3433c2248fc9SDouglas Gilbert 	}
3434a4517511SAkinobu Mita 	return 0;
34351da177e4SLinus Torvalds }
34361da177e4SLinus Torvalds 
3437c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3438395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3439c6a44287SMartin K. Petersen {
3440be4e11beSAkinobu Mita 	int ret;
34416ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3442be4e11beSAkinobu Mita 	void *daddr;
344365f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3444c6a44287SMartin K. Petersen 	int ppage_offset;
3445be4e11beSAkinobu Mita 	int dpage_offset;
3446be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3447be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3448c6a44287SMartin K. Petersen 
3449c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3450c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3451c6a44287SMartin K. Petersen 
3452be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3453be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3454be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3455be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3456be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3457c6a44287SMartin K. Petersen 
3458be4e11beSAkinobu Mita 	/* For each protection page */
3459be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3460be4e11beSAkinobu Mita 		dpage_offset = 0;
3461be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3462be4e11beSAkinobu Mita 			ret = 0x01;
3463be4e11beSAkinobu Mita 			goto out;
3464c6a44287SMartin K. Petersen 		}
3465c6a44287SMartin K. Petersen 
3466be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
34676ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3468be4e11beSAkinobu Mita 			/* If we're at the end of the current
3469be4e11beSAkinobu Mita 			 * data page advance to the next one
3470be4e11beSAkinobu Mita 			 */
3471be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3472be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3473be4e11beSAkinobu Mita 					ret = 0x01;
3474be4e11beSAkinobu Mita 					goto out;
3475be4e11beSAkinobu Mita 				}
3476be4e11beSAkinobu Mita 				dpage_offset = 0;
3477be4e11beSAkinobu Mita 			}
3478c6a44287SMartin K. Petersen 
3479be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3480be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3481be4e11beSAkinobu Mita 
3482f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3483be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3484c78be80dSMartin K. Petersen 				if (ret)
3485395cef03SMartin K. Petersen 					goto out;
3486395cef03SMartin K. Petersen 			}
3487395cef03SMartin K. Petersen 
3488c6a44287SMartin K. Petersen 			sector++;
3489395cef03SMartin K. Petersen 			ei_lba++;
3490773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3491c6a44287SMartin K. Petersen 		}
3492be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3493be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3494c6a44287SMartin K. Petersen 	}
3495be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3496c6a44287SMartin K. Petersen 
349765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3498c6a44287SMartin K. Petersen 	dix_writes++;
3499c6a44287SMartin K. Petersen 
3500c6a44287SMartin K. Petersen 	return 0;
3501c6a44287SMartin K. Petersen 
3502c6a44287SMartin K. Petersen out:
3503c6a44287SMartin K. Petersen 	dif_errors++;
3504be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3505be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3506c6a44287SMartin K. Petersen 	return ret;
3507c6a44287SMartin K. Petersen }
3508c6a44287SMartin K. Petersen 
3509b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3510b90ebc3dSAkinobu Mita {
3511773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3512773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3513773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3514b90ebc3dSAkinobu Mita 	return lba;
3515b90ebc3dSAkinobu Mita }
3516b90ebc3dSAkinobu Mita 
3517b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3518b90ebc3dSAkinobu Mita {
3519773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3520a027b5b9SAkinobu Mita 
3521773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3522773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3523a027b5b9SAkinobu Mita 	return lba;
3524a027b5b9SAkinobu Mita }
3525a027b5b9SAkinobu Mita 
352687c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
352787c715dcSDouglas Gilbert 			      unsigned int *num)
352844d92694SMartin K. Petersen {
3529b90ebc3dSAkinobu Mita 	sector_t end;
3530b90ebc3dSAkinobu Mita 	unsigned int mapped;
3531b90ebc3dSAkinobu Mita 	unsigned long index;
3532b90ebc3dSAkinobu Mita 	unsigned long next;
353344d92694SMartin K. Petersen 
3534b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
353587c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
353644d92694SMartin K. Petersen 
353744d92694SMartin K. Petersen 	if (mapped)
353887c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
353944d92694SMartin K. Petersen 	else
354087c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
354144d92694SMartin K. Petersen 
3542b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
354344d92694SMartin K. Petersen 	*num = end - lba;
354444d92694SMartin K. Petersen 	return mapped;
354544d92694SMartin K. Petersen }
354644d92694SMartin K. Petersen 
354787c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
354887c715dcSDouglas Gilbert 		       unsigned int len)
354944d92694SMartin K. Petersen {
355044d92694SMartin K. Petersen 	sector_t end = lba + len;
355144d92694SMartin K. Petersen 
355244d92694SMartin K. Petersen 	while (lba < end) {
3553b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
355444d92694SMartin K. Petersen 
3555b90ebc3dSAkinobu Mita 		if (index < map_size)
355687c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
355744d92694SMartin K. Petersen 
3558b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
355944d92694SMartin K. Petersen 	}
356044d92694SMartin K. Petersen }
356144d92694SMartin K. Petersen 
356287c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
356387c715dcSDouglas Gilbert 			 unsigned int len)
356444d92694SMartin K. Petersen {
356544d92694SMartin K. Petersen 	sector_t end = lba + len;
356687c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
356744d92694SMartin K. Petersen 
356844d92694SMartin K. Petersen 	while (lba < end) {
3569b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
357044d92694SMartin K. Petersen 
3571b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3572773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3573b90ebc3dSAkinobu Mita 		    index < map_size) {
357487c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3575760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
357687c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3577760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3578773642d9SDouglas Gilbert 				       sdebug_sector_size *
3579773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3580be1dd78dSEric Sandeen 			}
358187c715dcSDouglas Gilbert 			if (sip->dif_storep) {
358287c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
358387c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3584773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3585e9926b43SAkinobu Mita 			}
3586b90ebc3dSAkinobu Mita 		}
3587b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
358844d92694SMartin K. Petersen 	}
358944d92694SMartin K. Petersen }
359044d92694SMartin K. Petersen 
3591fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
35921da177e4SLinus Torvalds {
359387c715dcSDouglas Gilbert 	bool check_prot;
3594c2248fc9SDouglas Gilbert 	u32 num;
3595c2248fc9SDouglas Gilbert 	u32 ei_lba;
359619789100SFUJITA Tomonori 	int ret;
359787c715dcSDouglas Gilbert 	u64 lba;
3598b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
359987c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
36001da177e4SLinus Torvalds 
3601c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3602c2248fc9SDouglas Gilbert 	case WRITE_16:
3603c2248fc9SDouglas Gilbert 		ei_lba = 0;
3604c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3605c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3606c2248fc9SDouglas Gilbert 		check_prot = true;
3607c2248fc9SDouglas Gilbert 		break;
3608c2248fc9SDouglas Gilbert 	case WRITE_10:
3609c2248fc9SDouglas Gilbert 		ei_lba = 0;
3610c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3611c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3612c2248fc9SDouglas Gilbert 		check_prot = true;
3613c2248fc9SDouglas Gilbert 		break;
3614c2248fc9SDouglas Gilbert 	case WRITE_6:
3615c2248fc9SDouglas Gilbert 		ei_lba = 0;
3616c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3617c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3618c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3619c2248fc9SDouglas Gilbert 		check_prot = true;
3620c2248fc9SDouglas Gilbert 		break;
3621c2248fc9SDouglas Gilbert 	case WRITE_12:
3622c2248fc9SDouglas Gilbert 		ei_lba = 0;
3623c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3624c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3625c2248fc9SDouglas Gilbert 		check_prot = true;
3626c2248fc9SDouglas Gilbert 		break;
3627c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3628c2248fc9SDouglas Gilbert 		ei_lba = 0;
3629c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3630c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3631c2248fc9SDouglas Gilbert 		check_prot = false;
3632c2248fc9SDouglas Gilbert 		break;
3633c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3634c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3635c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3636c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3637c2248fc9SDouglas Gilbert 		check_prot = false;
3638c2248fc9SDouglas Gilbert 		break;
3639c2248fc9SDouglas Gilbert 	}
3640f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
36418475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3642c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3643c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3644c2248fc9SDouglas Gilbert 			return check_condition_result;
3645c2248fc9SDouglas Gilbert 		}
36468475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
36478475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3648c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3649c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3650c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3651c2248fc9SDouglas Gilbert 	}
3652f0d1cf93SDouglas Gilbert 
36537109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3654f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3655f0d1cf93SDouglas Gilbert 	if (ret) {
36567109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3657f0d1cf93SDouglas Gilbert 		return ret;
3658f0d1cf93SDouglas Gilbert 	}
36596c78cc06SAkinobu Mita 
3660c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3661f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3662f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3663f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3664f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
36657109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3666f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3667c6a44287SMartin K. Petersen 				return illegal_condition_result;
3668f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36697109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3670f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3671f7be6772SMartin K. Petersen 				return check_condition_result;
3672f7be6772SMartin K. Petersen 			}
3673f7be6772SMartin K. Petersen 			break;
3674f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3675f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
36767109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3677f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3678f7be6772SMartin K. Petersen 				return illegal_condition_result;
3679f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36807109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3681f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3682f7be6772SMartin K. Petersen 				return check_condition_result;
3683f7be6772SMartin K. Petersen 			}
3684f7be6772SMartin K. Petersen 			break;
3685c6a44287SMartin K. Petersen 		}
3686c6a44287SMartin K. Petersen 	}
3687c6a44287SMartin K. Petersen 
368887c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3689f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
369087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3691f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3692f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3693f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
36947109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3695f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3696773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3697c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3698c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3699c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3700cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3701773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
370244d92694SMartin K. Petersen 
37033a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
37043a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
37053a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
37063a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
37073a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3708c2248fc9SDouglas Gilbert 			return check_condition_result;
37093a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3710c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3711c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37123a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3713c2248fc9SDouglas Gilbert 			return illegal_condition_result;
37143a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3715c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37163a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3717c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3718c2248fc9SDouglas Gilbert 		}
3719c2248fc9SDouglas Gilbert 	}
37201da177e4SLinus Torvalds 	return 0;
37211da177e4SLinus Torvalds }
37221da177e4SLinus Torvalds 
3723481b5e5cSDouglas Gilbert /*
3724481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3725481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3726481b5e5cSDouglas Gilbert  */
3727481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3728481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3729481b5e5cSDouglas Gilbert {
3730481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3731481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3732481b5e5cSDouglas Gilbert 	u8 *up;
3733b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3734481b5e5cSDouglas Gilbert 	u8 wrprotect;
3735481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3736481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3737481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3738481b5e5cSDouglas Gilbert 	u32 ei_lba;
3739481b5e5cSDouglas Gilbert 	u64 lba;
3740481b5e5cSDouglas Gilbert 	int ret, res;
3741481b5e5cSDouglas Gilbert 	bool is_16;
3742481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3743481b5e5cSDouglas Gilbert 
3744481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3745481b5e5cSDouglas Gilbert 		is_16 = false;
3746481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3747481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3748481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3749481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3750481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3751481b5e5cSDouglas Gilbert 		is_16 = true;
3752481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3753481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3754481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3755481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3756481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3757481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3758481b5e5cSDouglas Gilbert 			    wrprotect) {
3759481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3760481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3761481b5e5cSDouglas Gilbert 			}
3762481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3763481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3764481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3765481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3766481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3767481b5e5cSDouglas Gilbert 		}
3768481b5e5cSDouglas Gilbert 	}
3769481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3770481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3771481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3772481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3773481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3774481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3775481b5e5cSDouglas Gilbert 				my_name, __func__);
3776481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3777481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3778481b5e5cSDouglas Gilbert 	}
3779481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3780481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3781481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3782481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3783481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3784481b5e5cSDouglas Gilbert 				my_name, __func__);
3785481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3786481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3787481b5e5cSDouglas Gilbert 	}
3788481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3789481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3790481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3791481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3792481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3793481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3794481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3795481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3796481b5e5cSDouglas Gilbert 	if (res == -1) {
3797481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3798481b5e5cSDouglas Gilbert 		goto err_out;
3799481b5e5cSDouglas Gilbert 	}
3800481b5e5cSDouglas Gilbert 
38017109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3802481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3803481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3804481b5e5cSDouglas Gilbert 	cum_lb = 0;
3805481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3806481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3807481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3808481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3809481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3810481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3811481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3812481b5e5cSDouglas Gilbert 		if (num == 0)
3813481b5e5cSDouglas Gilbert 			continue;
38149447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3815481b5e5cSDouglas Gilbert 		if (ret)
3816481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3817481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3818481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3819481b5e5cSDouglas Gilbert 
3820481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3821481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3822481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3823481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3824481b5e5cSDouglas Gilbert 				    my_name, __func__);
3825481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3826481b5e5cSDouglas Gilbert 					0);
3827481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3828481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3829481b5e5cSDouglas Gilbert 		}
3830481b5e5cSDouglas Gilbert 
3831481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3832481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3833481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3834481b5e5cSDouglas Gilbert 							 ei_lba);
3835481b5e5cSDouglas Gilbert 
3836481b5e5cSDouglas Gilbert 			if (prot_ret) {
3837481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3838481b5e5cSDouglas Gilbert 						prot_ret);
3839481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3840481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3841481b5e5cSDouglas Gilbert 			}
3842481b5e5cSDouglas Gilbert 		}
3843481b5e5cSDouglas Gilbert 
384487c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3845f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3846f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3847f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3848481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
384987c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3850481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3851481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3852481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3853481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3854481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3855481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3856481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3857481b5e5cSDouglas Gilbert 
38583a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
38593a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
38603a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
38613a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
38623a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
38633a90a63dSDouglas Gilbert 				ret = check_condition_result;
3864481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38653a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3866481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
38673a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
38683a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3869481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3870481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38713a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
38723a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
38733a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3874481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3875481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3876481b5e5cSDouglas Gilbert 			}
3877481b5e5cSDouglas Gilbert 		}
3878481b5e5cSDouglas Gilbert 		sg_off += num_by;
3879481b5e5cSDouglas Gilbert 		cum_lb += num;
3880481b5e5cSDouglas Gilbert 	}
3881481b5e5cSDouglas Gilbert 	ret = 0;
3882481b5e5cSDouglas Gilbert err_out_unlock:
38837109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3884481b5e5cSDouglas Gilbert err_out:
3885481b5e5cSDouglas Gilbert 	kfree(lrdp);
3886481b5e5cSDouglas Gilbert 	return ret;
3887481b5e5cSDouglas Gilbert }
3888481b5e5cSDouglas Gilbert 
3889fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3890fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
389144d92694SMartin K. Petersen {
3892f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3893f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
389444d92694SMartin K. Petersen 	unsigned long long i;
389540d07b52SDouglas Gilbert 	u64 block, lbaa;
389687c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
389787c715dcSDouglas Gilbert 	int ret;
389887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3899b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
390040d07b52SDouglas Gilbert 	u8 *fs1p;
390187c715dcSDouglas Gilbert 	u8 *fsp;
390244d92694SMartin K. Petersen 
39037109f370SDouglas Gilbert 	sdeb_write_lock(sip);
390444d92694SMartin K. Petersen 
3905f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3906f0d1cf93SDouglas Gilbert 	if (ret) {
39077109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3908f0d1cf93SDouglas Gilbert 		return ret;
3909f0d1cf93SDouglas Gilbert 	}
3910f0d1cf93SDouglas Gilbert 
39119ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
391287c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
391344d92694SMartin K. Petersen 		goto out;
391444d92694SMartin K. Petersen 	}
391540d07b52SDouglas Gilbert 	lbaa = lba;
391640d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3917c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
391887c715dcSDouglas Gilbert 	fsp = sip->storep;
391987c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3920c2248fc9SDouglas Gilbert 	if (ndob) {
392140d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3922c2248fc9SDouglas Gilbert 		ret = 0;
3923c2248fc9SDouglas Gilbert 	} else
392440d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
392544d92694SMartin K. Petersen 
392644d92694SMartin K. Petersen 	if (-1 == ret) {
39277109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3928773642d9SDouglas Gilbert 		return DID_ERROR << 16;
392940d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3930c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3931e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
393240d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
393344d92694SMartin K. Petersen 
393444d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
393540d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
393640d07b52SDouglas Gilbert 		lbaa = lba + i;
393740d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
393887c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
393940d07b52SDouglas Gilbert 	}
39409ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
394187c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3942f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3943f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3944f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
394544d92694SMartin K. Petersen out:
39467109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
394744d92694SMartin K. Petersen 
394844d92694SMartin K. Petersen 	return 0;
394944d92694SMartin K. Petersen }
395044d92694SMartin K. Petersen 
3951fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3952fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3953c2248fc9SDouglas Gilbert {
3954c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3955c2248fc9SDouglas Gilbert 	u32 lba;
3956c2248fc9SDouglas Gilbert 	u16 num;
3957c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3958c2248fc9SDouglas Gilbert 	bool unmap = false;
3959c2248fc9SDouglas Gilbert 
3960c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3961773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3962c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3963c2248fc9SDouglas Gilbert 			return check_condition_result;
3964c2248fc9SDouglas Gilbert 		} else
3965c2248fc9SDouglas Gilbert 			unmap = true;
3966c2248fc9SDouglas Gilbert 	}
3967c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3968c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3969773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3970c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3971c2248fc9SDouglas Gilbert 		return check_condition_result;
3972c2248fc9SDouglas Gilbert 	}
3973c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3974c2248fc9SDouglas Gilbert }
3975c2248fc9SDouglas Gilbert 
3976fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3977fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3978c2248fc9SDouglas Gilbert {
3979c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3980c2248fc9SDouglas Gilbert 	u64 lba;
3981c2248fc9SDouglas Gilbert 	u32 num;
3982c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3983c2248fc9SDouglas Gilbert 	bool unmap = false;
3984c2248fc9SDouglas Gilbert 	bool ndob = false;
3985c2248fc9SDouglas Gilbert 
3986c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3987773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3988c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3989c2248fc9SDouglas Gilbert 			return check_condition_result;
3990c2248fc9SDouglas Gilbert 		} else
3991c2248fc9SDouglas Gilbert 			unmap = true;
3992c2248fc9SDouglas Gilbert 	}
3993c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3994c2248fc9SDouglas Gilbert 		ndob = true;
3995c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3996c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3997773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3998c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3999c2248fc9SDouglas Gilbert 		return check_condition_result;
4000c2248fc9SDouglas Gilbert 	}
4001c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
4002c2248fc9SDouglas Gilbert }
4003c2248fc9SDouglas Gilbert 
4004acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
4005acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
4006acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
4007fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
4008fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
4009acafd0b9SEwan D. Milne {
4010acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
4011acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
4012acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
4013acafd0b9SEwan D. Milne 	u8 mode;
4014acafd0b9SEwan D. Milne 
4015acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
4016acafd0b9SEwan D. Milne 	switch (mode) {
4017acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
4018acafd0b9SEwan D. Milne 		/* set UAs on this device only */
4019acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4020acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
4021acafd0b9SEwan D. Milne 		break;
4022acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
4023acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
4024acafd0b9SEwan D. Milne 		break;
4025acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
4026acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
4027acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4028acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4029acafd0b9SEwan D. Milne 				    dev_list)
4030acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
4031acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
4032acafd0b9SEwan D. Milne 				if (devip != dp)
4033acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
4034acafd0b9SEwan D. Milne 						dp->uas_bm);
4035acafd0b9SEwan D. Milne 			}
4036acafd0b9SEwan D. Milne 		break;
4037acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
4038acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
4039acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4040acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4041acafd0b9SEwan D. Milne 				    dev_list)
4042acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
4043acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
4044acafd0b9SEwan D. Milne 					dp->uas_bm);
4045acafd0b9SEwan D. Milne 		break;
4046acafd0b9SEwan D. Milne 	default:
4047acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
4048acafd0b9SEwan D. Milne 		break;
4049acafd0b9SEwan D. Milne 	}
4050acafd0b9SEwan D. Milne 	return 0;
4051acafd0b9SEwan D. Milne }
4052acafd0b9SEwan D. Milne 
4053fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
4054fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
405538d5c833SDouglas Gilbert {
405638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
405738d5c833SDouglas Gilbert 	u8 *arr;
4058b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
405938d5c833SDouglas Gilbert 	u64 lba;
406038d5c833SDouglas Gilbert 	u32 dnum;
4061773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
406238d5c833SDouglas Gilbert 	u8 num;
406338d5c833SDouglas Gilbert 	int ret;
4064d467d31fSDouglas Gilbert 	int retval = 0;
406538d5c833SDouglas Gilbert 
4066d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
406738d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
406838d5c833SDouglas Gilbert 	if (0 == num)
406938d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
40708475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
407138d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
407238d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
407338d5c833SDouglas Gilbert 		return check_condition_result;
407438d5c833SDouglas Gilbert 	}
40758475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
40768475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
407738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
407838d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
407938d5c833SDouglas Gilbert 			    "to DIF device\n");
40809447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
40819447b6ceSMartin K. Petersen 	if (ret)
40829447b6ceSMartin K. Petersen 		return ret;
4083d467d31fSDouglas Gilbert 	dnum = 2 * num;
40846396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
4085d467d31fSDouglas Gilbert 	if (NULL == arr) {
4086d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4087d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
4088d467d31fSDouglas Gilbert 		return check_condition_result;
4089d467d31fSDouglas Gilbert 	}
409038d5c833SDouglas Gilbert 
40917109f370SDouglas Gilbert 	sdeb_write_lock(sip);
409238d5c833SDouglas Gilbert 
409387c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
409438d5c833SDouglas Gilbert 	if (ret == -1) {
4095d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
4096d467d31fSDouglas Gilbert 		goto cleanup;
4097773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
409838d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
409938d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
410038d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
4101c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
410238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4103d467d31fSDouglas Gilbert 		retval = check_condition_result;
4104d467d31fSDouglas Gilbert 		goto cleanup;
410538d5c833SDouglas Gilbert 	}
410638d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
410787c715dcSDouglas Gilbert 		map_region(sip, lba, num);
4108d467d31fSDouglas Gilbert cleanup:
41097109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4110d467d31fSDouglas Gilbert 	kfree(arr);
4111d467d31fSDouglas Gilbert 	return retval;
411238d5c833SDouglas Gilbert }
411338d5c833SDouglas Gilbert 
411444d92694SMartin K. Petersen struct unmap_block_desc {
411544d92694SMartin K. Petersen 	__be64	lba;
411644d92694SMartin K. Petersen 	__be32	blocks;
411744d92694SMartin K. Petersen 	__be32	__reserved;
411844d92694SMartin K. Petersen };
411944d92694SMartin K. Petersen 
4120fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
412144d92694SMartin K. Petersen {
412244d92694SMartin K. Petersen 	unsigned char *buf;
412344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
4124b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
412544d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
412644d92694SMartin K. Petersen 	int ret;
412744d92694SMartin K. Petersen 
4128c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
4129c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
4130c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
4131c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
413244d92694SMartin K. Petersen 
413344d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
4134773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
4135c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
413644d92694SMartin K. Petersen 		return check_condition_result;
4137c2248fc9SDouglas Gilbert 	}
413844d92694SMartin K. Petersen 
4139b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
4140c2248fc9SDouglas Gilbert 	if (!buf) {
4141c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4142c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
4143c2248fc9SDouglas Gilbert 		return check_condition_result;
4144c2248fc9SDouglas Gilbert 	}
4145c2248fc9SDouglas Gilbert 
4146c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
414744d92694SMartin K. Petersen 
414844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
414944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
415044d92694SMartin K. Petersen 
415144d92694SMartin K. Petersen 	desc = (void *)&buf[8];
415244d92694SMartin K. Petersen 
41537109f370SDouglas Gilbert 	sdeb_write_lock(sip);
41546c78cc06SAkinobu Mita 
415544d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
415644d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
415744d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
415844d92694SMartin K. Petersen 
41599447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
416044d92694SMartin K. Petersen 		if (ret)
416144d92694SMartin K. Petersen 			goto out;
416244d92694SMartin K. Petersen 
416387c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
416444d92694SMartin K. Petersen 	}
416544d92694SMartin K. Petersen 
416644d92694SMartin K. Petersen 	ret = 0;
416744d92694SMartin K. Petersen 
416844d92694SMartin K. Petersen out:
41697109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
417044d92694SMartin K. Petersen 	kfree(buf);
417144d92694SMartin K. Petersen 
417244d92694SMartin K. Petersen 	return ret;
417344d92694SMartin K. Petersen }
417444d92694SMartin K. Petersen 
417544d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
417644d92694SMartin K. Petersen 
4177fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4178fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
417944d92694SMartin K. Petersen {
4180c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4181c2248fc9SDouglas Gilbert 	u64 lba;
4182c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
418344d92694SMartin K. Petersen 	int ret;
418487c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
418544d92694SMartin K. Petersen 
4186c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4187c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
418844d92694SMartin K. Petersen 
418944d92694SMartin K. Petersen 	if (alloc_len < 24)
419044d92694SMartin K. Petersen 		return 0;
419144d92694SMartin K. Petersen 
41929447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
419344d92694SMartin K. Petersen 	if (ret)
419444d92694SMartin K. Petersen 		return ret;
419544d92694SMartin K. Petersen 
4196b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4197b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4198b6ff8ca7SDouglas Gilbert 
419987c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4200b6ff8ca7SDouglas Gilbert 	} else {
4201c2248fc9SDouglas Gilbert 		mapped = 1;
4202c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4203c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4204c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4205c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4206c2248fc9SDouglas Gilbert 		else
4207c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4208c2248fc9SDouglas Gilbert 	}
420944d92694SMartin K. Petersen 
421044d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4211c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4212c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4213c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4214c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
421544d92694SMartin K. Petersen 
4216c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
421744d92694SMartin K. Petersen }
421844d92694SMartin K. Petersen 
421980c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
422080c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
422180c49563SDouglas Gilbert {
42224f2c8bf6SDouglas Gilbert 	int res = 0;
422380c49563SDouglas Gilbert 	u64 lba;
422480c49563SDouglas Gilbert 	u32 num_blocks;
422580c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
422680c49563SDouglas Gilbert 
422780c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
422880c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
422980c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
423080c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
423180c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
423280c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
423380c49563SDouglas Gilbert 	}
423480c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
423580c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
423680c49563SDouglas Gilbert 		return check_condition_result;
423780c49563SDouglas Gilbert 	}
4238fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
42394f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
42404f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
42414f2c8bf6SDouglas Gilbert 		write_since_sync = false;
42424f2c8bf6SDouglas Gilbert 	return res;
424380c49563SDouglas Gilbert }
424480c49563SDouglas Gilbert 
4245ed9f3e25SDouglas Gilbert /*
4246ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4247ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4248ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4249ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4250ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4251ed9f3e25SDouglas Gilbert  */
4252ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4253ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4254ed9f3e25SDouglas Gilbert {
4255ed9f3e25SDouglas Gilbert 	int res = 0;
4256ed9f3e25SDouglas Gilbert 	u64 lba;
4257ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4258ed9f3e25SDouglas Gilbert 	u32 nblks;
4259ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4260b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4261b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4262ed9f3e25SDouglas Gilbert 
4263ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4264ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4265ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4266ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4267ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4268ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4269ed9f3e25SDouglas Gilbert 	}
4270ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4271ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4272ed9f3e25SDouglas Gilbert 		return check_condition_result;
4273ed9f3e25SDouglas Gilbert 	}
4274ed9f3e25SDouglas Gilbert 	if (!fsp)
4275ed9f3e25SDouglas Gilbert 		goto fini;
4276ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4277ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4278ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4279ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4280ed9f3e25SDouglas Gilbert 
4281ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
42827109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4283ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4284ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4285ed9f3e25SDouglas Gilbert 	if (rest)
4286ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
42877109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4288ed9f3e25SDouglas Gilbert fini:
4289ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4290ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4291ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4292ed9f3e25SDouglas Gilbert }
4293ed9f3e25SDouglas Gilbert 
4294fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4295fb0cc8d1SDouglas Gilbert 
42968d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
42978d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
42988d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
42998d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
43008d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
43018d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
43028d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
43038d039e22SDouglas Gilbert  */
43041da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
43051da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
43061da177e4SLinus Torvalds {
430701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
43088d039e22SDouglas Gilbert 	unsigned int alloc_len;
43098d039e22SDouglas Gilbert 	unsigned char select_report;
43108d039e22SDouglas Gilbert 	u64 lun;
43118d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4312fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
43138d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
43148d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
43158d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
43168d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4317fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4318fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4319fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
43201da177e4SLinus Torvalds 
432119c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
43228d039e22SDouglas Gilbert 
43238d039e22SDouglas Gilbert 	select_report = cmd[2];
43248d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
43258d039e22SDouglas Gilbert 
43268d039e22SDouglas Gilbert 	if (alloc_len < 4) {
43278d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
43288d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
43291da177e4SLinus Torvalds 		return check_condition_result;
43301da177e4SLinus Torvalds 	}
43318d039e22SDouglas Gilbert 
43328d039e22SDouglas Gilbert 	switch (select_report) {
43338d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4334773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43358d039e22SDouglas Gilbert 		wlun_cnt = 0;
43368d039e22SDouglas Gilbert 		break;
43378d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4338c65b1445SDouglas Gilbert 		lun_cnt = 0;
43398d039e22SDouglas Gilbert 		wlun_cnt = 1;
43408d039e22SDouglas Gilbert 		break;
43418d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
43428d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43438d039e22SDouglas Gilbert 		wlun_cnt = 1;
43448d039e22SDouglas Gilbert 		break;
43458d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
43468d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
43478d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
43488d039e22SDouglas Gilbert 	default:
43498d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
43508d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
43518d039e22SDouglas Gilbert 		return check_condition_result;
43528d039e22SDouglas Gilbert 	}
43538d039e22SDouglas Gilbert 
43548d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4355c65b1445SDouglas Gilbert 		--lun_cnt;
43568d039e22SDouglas Gilbert 
43578d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4358fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4359fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
43608d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
43618d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
43628d039e22SDouglas Gilbert 
4363fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
43648d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4365fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4366fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4367fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4368fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4369fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4370fb0cc8d1SDouglas Gilbert 			++lun_p;
4371fb0cc8d1SDouglas Gilbert 			j = 1;
4372fb0cc8d1SDouglas Gilbert 		}
4373fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4374fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4375fb0cc8d1SDouglas Gilbert 				break;
4376fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4377ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4378ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4379fb0cc8d1SDouglas Gilbert 		}
4380fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4381fb0cc8d1SDouglas Gilbert 			break;
4382fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4383fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4384fb0cc8d1SDouglas Gilbert 		if (res)
4385fb0cc8d1SDouglas Gilbert 			return res;
4386fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4387fb0cc8d1SDouglas Gilbert 	}
4388fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4389fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4390fb0cc8d1SDouglas Gilbert 		++j;
4391fb0cc8d1SDouglas Gilbert 	}
4392fb0cc8d1SDouglas Gilbert 	if (j > 0)
4393fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
43948d039e22SDouglas Gilbert 	return res;
43951da177e4SLinus Torvalds }
43961da177e4SLinus Torvalds 
4397c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4398c3e2fe92SDouglas Gilbert {
4399c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4400c3e2fe92SDouglas Gilbert 	u8 bytchk;
4401c3e2fe92SDouglas Gilbert 	int ret, j;
4402c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4403c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4404c3e2fe92SDouglas Gilbert 	u64 lba;
4405c3e2fe92SDouglas Gilbert 	u8 *arr;
4406c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4407b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4408c3e2fe92SDouglas Gilbert 
4409c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4410c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4411c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4412c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4413c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4414c3e2fe92SDouglas Gilbert 		return check_condition_result;
4415c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4416c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4417c3e2fe92SDouglas Gilbert 	}
4418c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4419c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4420c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4421c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4422c3e2fe92SDouglas Gilbert 		break;
4423c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4424c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4425c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4426c3e2fe92SDouglas Gilbert 		break;
4427c3e2fe92SDouglas Gilbert 	default:
4428c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4429c3e2fe92SDouglas Gilbert 		return check_condition_result;
4430c3e2fe92SDouglas Gilbert 	}
44313344b58bSGeorge Kennedy 	if (vnum == 0)
44323344b58bSGeorge Kennedy 		return 0;	/* not an error */
4433c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4434c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4435c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4436c3e2fe92SDouglas Gilbert 	if (ret)
4437c3e2fe92SDouglas Gilbert 		return ret;
4438c3e2fe92SDouglas Gilbert 
4439c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4440c3e2fe92SDouglas Gilbert 	if (!arr) {
4441c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4442c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4443c3e2fe92SDouglas Gilbert 		return check_condition_result;
4444c3e2fe92SDouglas Gilbert 	}
4445c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
44467109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4447c3e2fe92SDouglas Gilbert 
4448c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4449c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4450c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4451c3e2fe92SDouglas Gilbert 		goto cleanup;
4452c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4453c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4454c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4455c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4456c3e2fe92SDouglas Gilbert 	}
4457c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4458c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4459c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4460c3e2fe92SDouglas Gilbert 	}
4461c3e2fe92SDouglas Gilbert 	ret = 0;
4462c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4463c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4464c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4465c3e2fe92SDouglas Gilbert 		goto cleanup;
4466c3e2fe92SDouglas Gilbert 	}
4467c3e2fe92SDouglas Gilbert cleanup:
44687109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4469c3e2fe92SDouglas Gilbert 	kfree(arr);
4470c3e2fe92SDouglas Gilbert 	return ret;
4471c3e2fe92SDouglas Gilbert }
4472c3e2fe92SDouglas Gilbert 
4473f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4474f0d1cf93SDouglas Gilbert 
4475897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */
4476f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4477f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4478f0d1cf93SDouglas Gilbert {
44794a5fc1c6SDamien Le Moal 	unsigned int rep_max_zones, nrz = 0;
4480f0d1cf93SDouglas Gilbert 	int ret = 0;
4481f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4482f0d1cf93SDouglas Gilbert 	bool partial;
4483f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4484f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4485f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
44864a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp = NULL;
4487b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4488f0d1cf93SDouglas Gilbert 
4489f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4490f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4491f0d1cf93SDouglas Gilbert 		return check_condition_result;
4492f0d1cf93SDouglas Gilbert 	}
4493f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4494f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
44953344b58bSGeorge Kennedy 	if (alloc_len == 0)
44963344b58bSGeorge Kennedy 		return 0;	/* not an error */
4497f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4498f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4499f0d1cf93SDouglas Gilbert 
4500f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4501f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4502f0d1cf93SDouglas Gilbert 		return check_condition_result;
4503f0d1cf93SDouglas Gilbert 	}
4504f0d1cf93SDouglas Gilbert 
45054a5fc1c6SDamien Le Moal 	rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
4506f0d1cf93SDouglas Gilbert 
45077db0e0c8SShin'ichiro Kawasaki 	arr = kzalloc(alloc_len, GFP_ATOMIC);
4508f0d1cf93SDouglas Gilbert 	if (!arr) {
4509f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4510f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4511f0d1cf93SDouglas Gilbert 		return check_condition_result;
4512f0d1cf93SDouglas Gilbert 	}
4513f0d1cf93SDouglas Gilbert 
45147109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4515f0d1cf93SDouglas Gilbert 
4516f0d1cf93SDouglas Gilbert 	desc = arr + 64;
45174a5fc1c6SDamien Le Moal 	for (lba = zs_lba; lba < sdebug_capacity;
45184a5fc1c6SDamien Le Moal 	     lba = zsp->z_start + zsp->z_size) {
45194a5fc1c6SDamien Le Moal 		if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba))
4520f0d1cf93SDouglas Gilbert 			break;
4521f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4522f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4523f0d1cf93SDouglas Gilbert 		case 0x00:
4524f0d1cf93SDouglas Gilbert 			/* All zones */
4525f0d1cf93SDouglas Gilbert 			break;
4526f0d1cf93SDouglas Gilbert 		case 0x01:
4527f0d1cf93SDouglas Gilbert 			/* Empty zones */
4528f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4529f0d1cf93SDouglas Gilbert 				continue;
4530f0d1cf93SDouglas Gilbert 			break;
4531f0d1cf93SDouglas Gilbert 		case 0x02:
4532f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4533f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4534f0d1cf93SDouglas Gilbert 				continue;
4535f0d1cf93SDouglas Gilbert 			break;
4536f0d1cf93SDouglas Gilbert 		case 0x03:
4537f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4538f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4539f0d1cf93SDouglas Gilbert 				continue;
4540f0d1cf93SDouglas Gilbert 			break;
4541f0d1cf93SDouglas Gilbert 		case 0x04:
4542f0d1cf93SDouglas Gilbert 			/* Closed zones */
4543f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4544f0d1cf93SDouglas Gilbert 				continue;
4545f0d1cf93SDouglas Gilbert 			break;
4546f0d1cf93SDouglas Gilbert 		case 0x05:
4547f0d1cf93SDouglas Gilbert 			/* Full zones */
4548f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4549f0d1cf93SDouglas Gilbert 				continue;
4550f0d1cf93SDouglas Gilbert 			break;
4551f0d1cf93SDouglas Gilbert 		case 0x06:
4552f0d1cf93SDouglas Gilbert 		case 0x07:
4553f0d1cf93SDouglas Gilbert 		case 0x10:
4554f0d1cf93SDouglas Gilbert 			/*
455564e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
455664e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4557f0d1cf93SDouglas Gilbert 			 */
4558f0d1cf93SDouglas Gilbert 			continue;
455964e14eceSDamien Le Moal 		case 0x11:
456064e14eceSDamien Le Moal 			/* non-seq-resource set */
456164e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
456264e14eceSDamien Le Moal 				continue;
456364e14eceSDamien Le Moal 			break;
45644a5fc1c6SDamien Le Moal 		case 0x3e:
45654a5fc1c6SDamien Le Moal 			/* All zones except gap zones. */
45664a5fc1c6SDamien Le Moal 			if (zbc_zone_is_gap(zsp))
45674a5fc1c6SDamien Le Moal 				continue;
45684a5fc1c6SDamien Le Moal 			break;
4569f0d1cf93SDouglas Gilbert 		case 0x3f:
4570f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
45714a5fc1c6SDamien Le Moal 			if (zbc_zone_is_seq(zsp))
4572f0d1cf93SDouglas Gilbert 				continue;
4573f0d1cf93SDouglas Gilbert 			break;
4574f0d1cf93SDouglas Gilbert 		default:
4575f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4576f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4577f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4578f0d1cf93SDouglas Gilbert 			goto fini;
4579f0d1cf93SDouglas Gilbert 		}
4580f0d1cf93SDouglas Gilbert 
4581f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4582f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
458364e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4584f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
458564e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
458664e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4587f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4588f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4589f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4590f0d1cf93SDouglas Gilbert 			desc += 64;
4591f0d1cf93SDouglas Gilbert 		}
4592f0d1cf93SDouglas Gilbert 
4593f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4594f0d1cf93SDouglas Gilbert 			break;
4595f0d1cf93SDouglas Gilbert 
4596f0d1cf93SDouglas Gilbert 		nrz++;
4597f0d1cf93SDouglas Gilbert 	}
4598f0d1cf93SDouglas Gilbert 
4599f0d1cf93SDouglas Gilbert 	/* Report header */
46004a5fc1c6SDamien Le Moal 	/* Zone list length. */
4601f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
46024a5fc1c6SDamien Le Moal 	/* Maximum LBA */
4603f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
46044a5fc1c6SDamien Le Moal 	/* Zone starting LBA granularity. */
46054a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
46064a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, arr + 16);
4607f0d1cf93SDouglas Gilbert 
4608f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
460936e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4610f0d1cf93SDouglas Gilbert 
4611f0d1cf93SDouglas Gilbert fini:
46127109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4613f0d1cf93SDouglas Gilbert 	kfree(arr);
4614f0d1cf93SDouglas Gilbert 	return ret;
4615f0d1cf93SDouglas Gilbert }
4616f0d1cf93SDouglas Gilbert 
4617f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4618f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4619f0d1cf93SDouglas Gilbert {
4620f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4621f0d1cf93SDouglas Gilbert 	unsigned int i;
4622f0d1cf93SDouglas Gilbert 
4623f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4624f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4625f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4626f0d1cf93SDouglas Gilbert 	}
4627f0d1cf93SDouglas Gilbert }
4628f0d1cf93SDouglas Gilbert 
4629f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4630f0d1cf93SDouglas Gilbert {
4631f0d1cf93SDouglas Gilbert 	int res = 0;
4632f0d1cf93SDouglas Gilbert 	u64 z_id;
4633f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4634f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4635f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4636f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4637b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4638f0d1cf93SDouglas Gilbert 
4639f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4640f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4641f0d1cf93SDouglas Gilbert 		return check_condition_result;
4642f0d1cf93SDouglas Gilbert 	}
4643f0d1cf93SDouglas Gilbert 
46447109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4645f0d1cf93SDouglas Gilbert 
4646f0d1cf93SDouglas Gilbert 	if (all) {
4647f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4648f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4649f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4650f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4651f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4652f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4653f0d1cf93SDouglas Gilbert 			goto fini;
4654f0d1cf93SDouglas Gilbert 		}
4655f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4656f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4657f0d1cf93SDouglas Gilbert 		goto fini;
4658f0d1cf93SDouglas Gilbert 	}
4659f0d1cf93SDouglas Gilbert 
4660f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4661f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4662f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4663f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4664f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4665f0d1cf93SDouglas Gilbert 		goto fini;
4666f0d1cf93SDouglas Gilbert 	}
4667f0d1cf93SDouglas Gilbert 
4668f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4669f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4670f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4671f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4672f0d1cf93SDouglas Gilbert 		goto fini;
4673f0d1cf93SDouglas Gilbert 	}
4674f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4675f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4676f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4677f0d1cf93SDouglas Gilbert 		goto fini;
4678f0d1cf93SDouglas Gilbert 	}
4679f0d1cf93SDouglas Gilbert 
4680f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4681f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4682f0d1cf93SDouglas Gilbert 		goto fini;
4683f0d1cf93SDouglas Gilbert 
4684f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4685f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4686f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4687f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4688f0d1cf93SDouglas Gilbert 		goto fini;
4689f0d1cf93SDouglas Gilbert 	}
4690f0d1cf93SDouglas Gilbert 
4691f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4692f0d1cf93SDouglas Gilbert fini:
46937109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4694f0d1cf93SDouglas Gilbert 	return res;
4695f0d1cf93SDouglas Gilbert }
4696f0d1cf93SDouglas Gilbert 
4697f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4698f0d1cf93SDouglas Gilbert {
4699f0d1cf93SDouglas Gilbert 	unsigned int i;
4700f0d1cf93SDouglas Gilbert 
4701f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4702f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4703f0d1cf93SDouglas Gilbert }
4704f0d1cf93SDouglas Gilbert 
4705f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4706f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4707f0d1cf93SDouglas Gilbert {
4708f0d1cf93SDouglas Gilbert 	int res = 0;
4709f0d1cf93SDouglas Gilbert 	u64 z_id;
4710f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4711f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4712f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4713b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4714f0d1cf93SDouglas Gilbert 
4715f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4716f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4717f0d1cf93SDouglas Gilbert 		return check_condition_result;
4718f0d1cf93SDouglas Gilbert 	}
4719f0d1cf93SDouglas Gilbert 
47207109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4721f0d1cf93SDouglas Gilbert 
4722f0d1cf93SDouglas Gilbert 	if (all) {
4723f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4724f0d1cf93SDouglas Gilbert 		goto fini;
4725f0d1cf93SDouglas Gilbert 	}
4726f0d1cf93SDouglas Gilbert 
4727f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4728f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4729f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4730f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4731f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4732f0d1cf93SDouglas Gilbert 		goto fini;
4733f0d1cf93SDouglas Gilbert 	}
4734f0d1cf93SDouglas Gilbert 
4735f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4736f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4737f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4738f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4739f0d1cf93SDouglas Gilbert 		goto fini;
4740f0d1cf93SDouglas Gilbert 	}
4741f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4742f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4743f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4744f0d1cf93SDouglas Gilbert 		goto fini;
4745f0d1cf93SDouglas Gilbert 	}
4746f0d1cf93SDouglas Gilbert 
4747f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4748f0d1cf93SDouglas Gilbert fini:
47497109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4750f0d1cf93SDouglas Gilbert 	return res;
4751f0d1cf93SDouglas Gilbert }
4752f0d1cf93SDouglas Gilbert 
4753f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4754f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4755f0d1cf93SDouglas Gilbert {
4756f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4757f0d1cf93SDouglas Gilbert 
4758f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4759f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4760f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4761f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4762f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4763f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4764f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4765f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4766f0d1cf93SDouglas Gilbert 	}
4767f0d1cf93SDouglas Gilbert }
4768f0d1cf93SDouglas Gilbert 
4769f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4770f0d1cf93SDouglas Gilbert {
4771f0d1cf93SDouglas Gilbert 	unsigned int i;
4772f0d1cf93SDouglas Gilbert 
4773f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4774f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4775f0d1cf93SDouglas Gilbert }
4776f0d1cf93SDouglas Gilbert 
4777f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4778f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4779f0d1cf93SDouglas Gilbert {
4780f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4781f0d1cf93SDouglas Gilbert 	int res = 0;
4782f0d1cf93SDouglas Gilbert 	u64 z_id;
4783f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4784f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4785b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4786f0d1cf93SDouglas Gilbert 
4787f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4788f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4789f0d1cf93SDouglas Gilbert 		return check_condition_result;
4790f0d1cf93SDouglas Gilbert 	}
4791f0d1cf93SDouglas Gilbert 
47927109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4793f0d1cf93SDouglas Gilbert 
4794f0d1cf93SDouglas Gilbert 	if (all) {
4795f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4796f0d1cf93SDouglas Gilbert 		goto fini;
4797f0d1cf93SDouglas Gilbert 	}
4798f0d1cf93SDouglas Gilbert 
4799f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4800f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4801f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4802f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4803f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4804f0d1cf93SDouglas Gilbert 		goto fini;
4805f0d1cf93SDouglas Gilbert 	}
4806f0d1cf93SDouglas Gilbert 
4807f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4808f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4809f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4810f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4811f0d1cf93SDouglas Gilbert 		goto fini;
4812f0d1cf93SDouglas Gilbert 	}
4813f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4814f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4815f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4816f0d1cf93SDouglas Gilbert 		goto fini;
4817f0d1cf93SDouglas Gilbert 	}
4818f0d1cf93SDouglas Gilbert 
4819f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4820f0d1cf93SDouglas Gilbert fini:
48217109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4822f0d1cf93SDouglas Gilbert 	return res;
4823f0d1cf93SDouglas Gilbert }
4824f0d1cf93SDouglas Gilbert 
4825f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4826f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4827f0d1cf93SDouglas Gilbert {
4828f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
48292d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4830f0d1cf93SDouglas Gilbert 
48314a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
4832f0d1cf93SDouglas Gilbert 		return;
4833f0d1cf93SDouglas Gilbert 
4834f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4835f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4836f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4837f0d1cf93SDouglas Gilbert 
4838f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4839f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4840f0d1cf93SDouglas Gilbert 
48412d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
48422d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
48432d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
48442d62253eSShin'ichiro Kawasaki 
484564e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4846f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4847f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4848f0d1cf93SDouglas Gilbert }
4849f0d1cf93SDouglas Gilbert 
4850f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4851f0d1cf93SDouglas Gilbert {
4852f0d1cf93SDouglas Gilbert 	unsigned int i;
4853f0d1cf93SDouglas Gilbert 
4854f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4855f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4856f0d1cf93SDouglas Gilbert }
4857f0d1cf93SDouglas Gilbert 
4858f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4859f0d1cf93SDouglas Gilbert {
4860f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4861f0d1cf93SDouglas Gilbert 	int res = 0;
4862f0d1cf93SDouglas Gilbert 	u64 z_id;
4863f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4864f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4865b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4866f0d1cf93SDouglas Gilbert 
4867f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4868f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4869f0d1cf93SDouglas Gilbert 		return check_condition_result;
4870f0d1cf93SDouglas Gilbert 	}
4871f0d1cf93SDouglas Gilbert 
48727109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4873f0d1cf93SDouglas Gilbert 
4874f0d1cf93SDouglas Gilbert 	if (all) {
4875f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4876f0d1cf93SDouglas Gilbert 		goto fini;
4877f0d1cf93SDouglas Gilbert 	}
4878f0d1cf93SDouglas Gilbert 
4879f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4880f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4881f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4882f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4883f0d1cf93SDouglas Gilbert 		goto fini;
4884f0d1cf93SDouglas Gilbert 	}
4885f0d1cf93SDouglas Gilbert 
4886f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4887f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4888f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4889f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4890f0d1cf93SDouglas Gilbert 		goto fini;
4891f0d1cf93SDouglas Gilbert 	}
4892f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4893f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4894f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4895f0d1cf93SDouglas Gilbert 		goto fini;
4896f0d1cf93SDouglas Gilbert 	}
4897f0d1cf93SDouglas Gilbert 
4898f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4899f0d1cf93SDouglas Gilbert fini:
49007109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4901f0d1cf93SDouglas Gilbert 	return res;
4902f0d1cf93SDouglas Gilbert }
4903f0d1cf93SDouglas Gilbert 
4904c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4905c4837394SDouglas Gilbert {
4906c10fa55fSJohn Garry 	u16 hwq;
4907a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4908c10fa55fSJohn Garry 
4909c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4910c4837394SDouglas Gilbert 
4911458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4912458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4913458df78bSBart Van Assche 		hwq = 0;
4914f7c4cdc7SJohn Garry 
4915458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4916c4837394SDouglas Gilbert }
4917c4837394SDouglas Gilbert 
4918c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4919c10fa55fSJohn Garry {
4920a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4921c10fa55fSJohn Garry }
4922c10fa55fSJohn Garry 
4923c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4924fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
49251da177e4SLinus Torvalds {
49267382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4927c4837394SDouglas Gilbert 	int qc_idx;
4928cbf67842SDouglas Gilbert 	int retiring = 0;
49291da177e4SLinus Torvalds 	unsigned long iflags;
4930c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4931cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4932cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4933cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
49341da177e4SLinus Torvalds 
49357382f9d8SDouglas Gilbert 	if (unlikely(aborted))
49367382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4937c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4938c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4939c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4940cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4941c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4942c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4943c4837394SDouglas Gilbert 	}
4944c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4945c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
49461da177e4SLinus Torvalds 		return;
49471da177e4SLinus Torvalds 	}
4948c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4949d9d23a5aSDouglas Gilbert 	WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
4950c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4951cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4952b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4953c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4954c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4955c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
49561da177e4SLinus Torvalds 		return;
49571da177e4SLinus Torvalds 	}
4958cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4959f46eb0e9SDouglas Gilbert 	if (likely(devip))
4960cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4961cbf67842SDouglas Gilbert 	else
4962c1287970STomas Winkler 		pr_err("devip=NULL\n");
4963f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4964cbf67842SDouglas Gilbert 		retiring = 1;
4965cbf67842SDouglas Gilbert 
4966cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4967c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4968c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4969c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4970cbf67842SDouglas Gilbert 		return;
49711da177e4SLinus Torvalds 	}
49721da177e4SLinus Torvalds 
4973cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4974cbf67842SDouglas Gilbert 		int k, retval;
4975cbf67842SDouglas Gilbert 
4976cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4977c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4978c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4979c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4980cbf67842SDouglas Gilbert 			return;
4981cbf67842SDouglas Gilbert 		}
4982c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4983773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4984cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4985cbf67842SDouglas Gilbert 		else
4986cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4987cbf67842SDouglas Gilbert 	}
4988c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
49897382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
49907382f9d8SDouglas Gilbert 		if (sdebug_verbose)
49917382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
49927382f9d8SDouglas Gilbert 		return;
49937382f9d8SDouglas Gilbert 	}
49946c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
4995cbf67842SDouglas Gilbert }
4996cbf67842SDouglas Gilbert 
4997cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4998fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4999cbf67842SDouglas Gilbert {
5000a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
5001a10bc12aSDouglas Gilbert 						  hrt);
5002a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5003cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
5004cbf67842SDouglas Gilbert }
50051da177e4SLinus Torvalds 
5006a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
5007fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
5008a10bc12aSDouglas Gilbert {
5009a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
5010a10bc12aSDouglas Gilbert 						  ew.work);
5011a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5012a10bc12aSDouglas Gilbert }
5013a10bc12aSDouglas Gilbert 
501409ba24c1SDouglas Gilbert static bool got_shared_uuid;
5015bf476433SChristoph Hellwig static uuid_t shared_uuid;
501609ba24c1SDouglas Gilbert 
5017f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
5018f0d1cf93SDouglas Gilbert {
5019f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
5020f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
50214a5fc1c6SDamien Le Moal 	sector_t conv_capacity;
5022f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
5023f0d1cf93SDouglas Gilbert 	unsigned int i;
5024f0d1cf93SDouglas Gilbert 
5025f0d1cf93SDouglas Gilbert 	/*
502698e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
502798e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
5028f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
5029f0d1cf93SDouglas Gilbert 	 * created for the device.
5030f0d1cf93SDouglas Gilbert 	 */
503198e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
5032f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
5033f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5034f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
5035f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
5036f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
5037f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
5038f0d1cf93SDouglas Gilbert 			return -EINVAL;
5039f0d1cf93SDouglas Gilbert 		}
5040f0d1cf93SDouglas Gilbert 	} else {
5041108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
5042108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
5043108e36f0SDamien Le Moal 			return -EINVAL;
5044108e36f0SDamien Le Moal 		}
504598e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
5046f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5047f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
5048f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
5049f0d1cf93SDouglas Gilbert 			return -EINVAL;
5050f0d1cf93SDouglas Gilbert 		}
5051f0d1cf93SDouglas Gilbert 	}
5052f0d1cf93SDouglas Gilbert 
5053f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
5054f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
5055f0d1cf93SDouglas Gilbert 
50564a5fc1c6SDamien Le Moal 	if (sdeb_zbc_zone_cap_mb == 0) {
50574a5fc1c6SDamien Le Moal 		devip->zcap = devip->zsize;
50584a5fc1c6SDamien Le Moal 	} else {
50594a5fc1c6SDamien Le Moal 		devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >>
50604a5fc1c6SDamien Le Moal 			      ilog2(sdebug_sector_size);
50614a5fc1c6SDamien Le Moal 		if (devip->zcap > devip->zsize) {
50624a5fc1c6SDamien Le Moal 			pr_err("Zone capacity too large\n");
50634a5fc1c6SDamien Le Moal 			return -EINVAL;
50644a5fc1c6SDamien Le Moal 		}
50654a5fc1c6SDamien Le Moal 	}
50664a5fc1c6SDamien Le Moal 
50674a5fc1c6SDamien Le Moal 	conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift;
50684a5fc1c6SDamien Le Moal 	if (conv_capacity >= capacity) {
5069aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
5070aa8fecf9SDamien Le Moal 		return -EINVAL;
5071aa8fecf9SDamien Le Moal 	}
5072aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
50734a5fc1c6SDamien Le Moal 	devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >>
50744a5fc1c6SDamien Le Moal 			      devip->zsize_shift;
50754a5fc1c6SDamien Le Moal 	devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones;
50764a5fc1c6SDamien Le Moal 
50774a5fc1c6SDamien Le Moal 	/* Add gap zones if zone capacity is smaller than the zone size */
50784a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
50794a5fc1c6SDamien Le Moal 		devip->nr_zones += devip->nr_seq_zones;
5080aa8fecf9SDamien Le Moal 
508164e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
508264e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
5083380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
5084f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
5085f0d1cf93SDouglas Gilbert 		else
5086380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
508764e14eceSDamien Le Moal 	}
5088f0d1cf93SDouglas Gilbert 
5089f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
5090f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
5091f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
5092f0d1cf93SDouglas Gilbert 		return -ENOMEM;
5093f0d1cf93SDouglas Gilbert 
5094f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
5095f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
5096f0d1cf93SDouglas Gilbert 
5097f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
5098f0d1cf93SDouglas Gilbert 
5099aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
510035dbe2b9SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_CNV;
5101f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
5102f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
51034a5fc1c6SDamien Le Moal 			zsp->z_size =
51044a5fc1c6SDamien Le Moal 				min_t(u64, devip->zsize, capacity - zstart);
51054a5fc1c6SDamien Le Moal 		} else if ((zstart & (devip->zsize - 1)) == 0) {
510664e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
510735dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWR;
510864e14eceSDamien Le Moal 			else
510935dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWP;
5110f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
5111f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
51124a5fc1c6SDamien Le Moal 			zsp->z_size =
51134a5fc1c6SDamien Le Moal 				min_t(u64, devip->zcap, capacity - zstart);
51144a5fc1c6SDamien Le Moal 		} else {
51154a5fc1c6SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_GAP;
51164a5fc1c6SDamien Le Moal 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
51174a5fc1c6SDamien Le Moal 			zsp->z_wp = (sector_t)-1;
51184a5fc1c6SDamien Le Moal 			zsp->z_size = min_t(u64, devip->zsize - devip->zcap,
51194a5fc1c6SDamien Le Moal 					    capacity - zstart);
5120f0d1cf93SDouglas Gilbert 		}
5121f0d1cf93SDouglas Gilbert 
51224a5fc1c6SDamien Le Moal 		WARN_ON_ONCE((int)zsp->z_size <= 0);
5123f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
5124f0d1cf93SDouglas Gilbert 	}
5125f0d1cf93SDouglas Gilbert 
5126f0d1cf93SDouglas Gilbert 	return 0;
5127f0d1cf93SDouglas Gilbert }
5128f0d1cf93SDouglas Gilbert 
5129fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
5130fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
51315cb2fc06SFUJITA Tomonori {
51325cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
51335cb2fc06SFUJITA Tomonori 
51345cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
51355cb2fc06SFUJITA Tomonori 	if (devip) {
513609ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
5137bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
513809ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
513909ba24c1SDouglas Gilbert 			if (got_shared_uuid)
514009ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
514109ba24c1SDouglas Gilbert 			else {
5142bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
514309ba24c1SDouglas Gilbert 				got_shared_uuid = true;
514409ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
514509ba24c1SDouglas Gilbert 			}
514609ba24c1SDouglas Gilbert 		}
51475cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
5148f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
514964e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
5150f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
5151f0d1cf93SDouglas Gilbert 				kfree(devip);
5152f0d1cf93SDouglas Gilbert 				return NULL;
5153f0d1cf93SDouglas Gilbert 			}
515464e14eceSDamien Le Moal 		} else {
515564e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
5156f0d1cf93SDouglas Gilbert 		}
5157f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
5158fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
5159fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
51605cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
51615cb2fc06SFUJITA Tomonori 	}
51625cb2fc06SFUJITA Tomonori 	return devip;
51635cb2fc06SFUJITA Tomonori }
51645cb2fc06SFUJITA Tomonori 
5165f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
51661da177e4SLinus Torvalds {
51671da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51681da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
5169f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
51701da177e4SLinus Torvalds 
5171d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
51721da177e4SLinus Torvalds 	if (!sdbg_host) {
5173c1287970STomas Winkler 		pr_err("Host info NULL\n");
51741da177e4SLinus Torvalds 		return NULL;
51751da177e4SLinus Torvalds 	}
5176ad0c7775SDouglas Gilbert 
51771da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
51781da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
51791da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
51801da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
51811da177e4SLinus Torvalds 			return devip;
51821da177e4SLinus Torvalds 		else {
51831da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
51841da177e4SLinus Torvalds 				open_devip = devip;
51851da177e4SLinus Torvalds 		}
51861da177e4SLinus Torvalds 	}
51875cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
51885cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
51895cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5190c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51911da177e4SLinus Torvalds 			return NULL;
51921da177e4SLinus Torvalds 		}
51931da177e4SLinus Torvalds 	}
5194a75869d1SFUJITA Tomonori 
51951da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
51961da177e4SLinus Torvalds 	open_devip->target = sdev->id;
51971da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
51981da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5199cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
5200500d0d24SDouglas Gilbert 	set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
5201c2248fc9SDouglas Gilbert 	open_devip->used = true;
52021da177e4SLinus Torvalds 	return open_devip;
52031da177e4SLinus Torvalds }
52041da177e4SLinus Torvalds 
52058dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
52061da177e4SLinus Torvalds {
5207773642d9SDouglas Gilbert 	if (sdebug_verbose)
5208c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
52098dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52108dea0d02SFUJITA Tomonori 	return 0;
52118dea0d02SFUJITA Tomonori }
52121da177e4SLinus Torvalds 
52138dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
52148dea0d02SFUJITA Tomonori {
5215f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5216f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5217a34c4e98SFUJITA Tomonori 
5218773642d9SDouglas Gilbert 	if (sdebug_verbose)
5219c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
52208dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5221b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5222b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5223b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5224f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5225b01f6f83SDouglas Gilbert 		if (devip == NULL)
52268dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5227f46eb0e9SDouglas Gilbert 	}
5228c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5229773642d9SDouglas Gilbert 	if (sdebug_no_uld)
523078d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
52319b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
52328dea0d02SFUJITA Tomonori 	return 0;
52338dea0d02SFUJITA Tomonori }
52348dea0d02SFUJITA Tomonori 
52358dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
52368dea0d02SFUJITA Tomonori {
52378dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
52388dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
52398dea0d02SFUJITA Tomonori 
5240773642d9SDouglas Gilbert 	if (sdebug_verbose)
5241c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
52428dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52438dea0d02SFUJITA Tomonori 	if (devip) {
524425985edcSLucas De Marchi 		/* make this slot available for re-use */
5245c2248fc9SDouglas Gilbert 		devip->used = false;
52468dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
52478dea0d02SFUJITA Tomonori 	}
52488dea0d02SFUJITA Tomonori }
52498dea0d02SFUJITA Tomonori 
525010bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
525110bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5252c4837394SDouglas Gilbert {
5253c4837394SDouglas Gilbert 	if (!sd_dp)
5254c4837394SDouglas Gilbert 		return;
525510bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5256c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
525710bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5258c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5259c4837394SDouglas Gilbert }
5260c4837394SDouglas Gilbert 
5261a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5262a10bc12aSDouglas Gilbert    returns false */
5263a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
52648dea0d02SFUJITA Tomonori {
52658dea0d02SFUJITA Tomonori 	unsigned long iflags;
5266c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
526710bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5268c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
52698dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5270cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5271a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
52728dea0d02SFUJITA Tomonori 
5273c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5274c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5275773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5276cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5277cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5278cbf67842SDouglas Gilbert 			qmax = r_qmax;
5279cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5280c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5281c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5282a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5283a10bc12aSDouglas Gilbert 					continue;
5284c4837394SDouglas Gilbert 				/* found */
5285db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5286db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5287db525fceSDouglas Gilbert 				if (devip)
5288db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5289db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5290a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
529110bde980SDouglas Gilbert 				if (sd_dp) {
5292d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5293d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
529410bde980SDouglas Gilbert 				} else
529510bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5296c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
529710bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5298c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5299a10bc12aSDouglas Gilbert 				return true;
53008dea0d02SFUJITA Tomonori 			}
5301cbf67842SDouglas Gilbert 		}
5302c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5303c4837394SDouglas Gilbert 	}
5304a10bc12aSDouglas Gilbert 	return false;
53058dea0d02SFUJITA Tomonori }
53068dea0d02SFUJITA Tomonori 
5307a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
5308f19fe8f3SBart Van Assche static void stop_all_queued(void)
53098dea0d02SFUJITA Tomonori {
53108dea0d02SFUJITA Tomonori 	unsigned long iflags;
5311c4837394SDouglas Gilbert 	int j, k;
531210bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5313c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
53148dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5315cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5316a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53178dea0d02SFUJITA Tomonori 
5318c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5319c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5320c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5321c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5322c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5323f19fe8f3SBart Van Assche 				if (sqcp->a_cmnd == NULL)
5324a10bc12aSDouglas Gilbert 					continue;
5325db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5326db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5327db525fceSDouglas Gilbert 				if (devip)
5328db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5329db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5330a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
533110bde980SDouglas Gilbert 				if (sd_dp) {
5332d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5333d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
533410bde980SDouglas Gilbert 				} else
533510bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5336c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
533710bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5338c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5339c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
53408dea0d02SFUJITA Tomonori 			}
53418dea0d02SFUJITA Tomonori 		}
5342c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5343c4837394SDouglas Gilbert 	}
5344cbf67842SDouglas Gilbert }
5345cbf67842SDouglas Gilbert 
5346cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5347cbf67842SDouglas Gilbert static void free_all_queued(void)
5348cbf67842SDouglas Gilbert {
5349c4837394SDouglas Gilbert 	int j, k;
5350c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5351cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5352cbf67842SDouglas Gilbert 
5353c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5354c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5355c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5356a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5357a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5358cbf67842SDouglas Gilbert 		}
53591da177e4SLinus Torvalds 	}
5360c4837394SDouglas Gilbert }
53611da177e4SLinus Torvalds 
53621da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
53631da177e4SLinus Torvalds {
5364a10bc12aSDouglas Gilbert 	bool ok;
5365a10bc12aSDouglas Gilbert 
53661da177e4SLinus Torvalds 	++num_aborts;
5367cbf67842SDouglas Gilbert 	if (SCpnt) {
5368a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5369a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5370a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5371a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5372a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5373cbf67842SDouglas Gilbert 	}
53741da177e4SLinus Torvalds 	return SUCCESS;
53751da177e4SLinus Torvalds }
53761da177e4SLinus Torvalds 
53771da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
53781da177e4SLinus Torvalds {
53791da177e4SLinus Torvalds 	++num_dev_resets;
5380cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5381cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5382f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5383f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5384cbf67842SDouglas Gilbert 
5385773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5386cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
53871da177e4SLinus Torvalds 		if (devip)
5388cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
53891da177e4SLinus Torvalds 	}
53901da177e4SLinus Torvalds 	return SUCCESS;
53911da177e4SLinus Torvalds }
53921da177e4SLinus Torvalds 
5393cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5394cbf67842SDouglas Gilbert {
5395cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5396cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5397cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5398cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5399cbf67842SDouglas Gilbert 	int k = 0;
5400cbf67842SDouglas Gilbert 
5401cbf67842SDouglas Gilbert 	++num_target_resets;
5402cbf67842SDouglas Gilbert 	if (!SCpnt)
5403cbf67842SDouglas Gilbert 		goto lie;
5404cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5405cbf67842SDouglas Gilbert 	if (!sdp)
5406cbf67842SDouglas Gilbert 		goto lie;
5407773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5408cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5409cbf67842SDouglas Gilbert 	hp = sdp->host;
5410cbf67842SDouglas Gilbert 	if (!hp)
5411cbf67842SDouglas Gilbert 		goto lie;
5412cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5413cbf67842SDouglas Gilbert 	if (sdbg_host) {
5414cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5415cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5416cbf67842SDouglas Gilbert 				    dev_list)
5417cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5418cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5419cbf67842SDouglas Gilbert 				++k;
5420cbf67842SDouglas Gilbert 			}
5421cbf67842SDouglas Gilbert 	}
5422773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5423cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5424cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5425cbf67842SDouglas Gilbert lie:
5426cbf67842SDouglas Gilbert 	return SUCCESS;
5427cbf67842SDouglas Gilbert }
5428cbf67842SDouglas Gilbert 
54291da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
54301da177e4SLinus Torvalds {
54311da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5432cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
54331da177e4SLinus Torvalds 	struct scsi_device *sdp;
54341da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5435cbf67842SDouglas Gilbert 	int k = 0;
54361da177e4SLinus Torvalds 
54371da177e4SLinus Torvalds 	++num_bus_resets;
5438cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5439cbf67842SDouglas Gilbert 		goto lie;
5440cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5441773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5442cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5443cbf67842SDouglas Gilbert 	hp = sdp->host;
5444cbf67842SDouglas Gilbert 	if (hp) {
5445d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
54461da177e4SLinus Torvalds 		if (sdbg_host) {
5447cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
54481da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5449cbf67842SDouglas Gilbert 					    dev_list) {
5450cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5451cbf67842SDouglas Gilbert 				++k;
54521da177e4SLinus Torvalds 			}
54531da177e4SLinus Torvalds 		}
5454cbf67842SDouglas Gilbert 	}
5455773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5456cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5457cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5458cbf67842SDouglas Gilbert lie:
54591da177e4SLinus Torvalds 	return SUCCESS;
54601da177e4SLinus Torvalds }
54611da177e4SLinus Torvalds 
54621da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
54631da177e4SLinus Torvalds {
54641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5465cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5466cbf67842SDouglas Gilbert 	int k = 0;
54671da177e4SLinus Torvalds 
54681da177e4SLinus Torvalds 	++num_host_resets;
5469773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5470cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
54711da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
54721da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5473cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5474cbf67842SDouglas Gilbert 				    dev_list) {
5475cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5476cbf67842SDouglas Gilbert 			++k;
5477cbf67842SDouglas Gilbert 		}
54781da177e4SLinus Torvalds 	}
54791da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
5480f19fe8f3SBart Van Assche 	stop_all_queued();
5481773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5482cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5483cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
54841da177e4SLinus Torvalds 	return SUCCESS;
54851da177e4SLinus Torvalds }
54861da177e4SLinus Torvalds 
548787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
54881da177e4SLinus Torvalds {
54891442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5490979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
54911da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
54921da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
54931da177e4SLinus Torvalds 
54941da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5495773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
54961da177e4SLinus Torvalds 		return;
5497773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5498773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5499c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
55001da177e4SLinus Torvalds 	}
55018c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
55021da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5503773642d9SDouglas Gilbert 			   / sdebug_num_parts;
55041da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
55051da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5506979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5507979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
55081da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
55091da177e4SLinus Torvalds 			    * heads_by_sects;
5510979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5511979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5512979e0dc3SJohn Pittman 	}
5513773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5514773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
55151da177e4SLinus Torvalds 
55161da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
55171da177e4SLinus Torvalds 	ramp[511] = 0xAA;
55181442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
55191da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
55201da177e4SLinus Torvalds 		start_sec = starts[k];
5521979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
55221da177e4SLinus Torvalds 		pp->boot_ind = 0;
55231da177e4SLinus Torvalds 
55241da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
55251da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
55261da177e4SLinus Torvalds 			   / sdebug_sectors_per;
55271da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
55281da177e4SLinus Torvalds 
55291da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
55301da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
55311da177e4SLinus Torvalds 			       / sdebug_sectors_per;
55321da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
55331da177e4SLinus Torvalds 
5534150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5535150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
55361da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
55371da177e4SLinus Torvalds 	}
55381da177e4SLinus Torvalds }
55391da177e4SLinus Torvalds 
5540f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block)
5541c4837394SDouglas Gilbert {
5542c4837394SDouglas Gilbert 	int j;
5543c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5544c4837394SDouglas Gilbert 
5545c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5546f19fe8f3SBart Van Assche 		atomic_set(&sqp->blocked, (int)block);
5547c4837394SDouglas Gilbert }
5548c4837394SDouglas Gilbert 
5549c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5550c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5551c4837394SDouglas Gilbert  */
5552c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5553c4837394SDouglas Gilbert {
5554c4837394SDouglas Gilbert 	int count, modulo;
5555c4837394SDouglas Gilbert 
5556c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5557c4837394SDouglas Gilbert 	if (modulo < 2)
5558c4837394SDouglas Gilbert 		return;
5559f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
5560c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5561c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5562f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
5563c4837394SDouglas Gilbert }
5564c4837394SDouglas Gilbert 
5565c4837394SDouglas Gilbert static void clear_queue_stats(void)
5566c4837394SDouglas Gilbert {
5567c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5568c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5569c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5570c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5571c4837394SDouglas Gilbert }
5572c4837394SDouglas Gilbert 
55733a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5574c4837394SDouglas Gilbert {
55753a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
55763a90a63dSDouglas Gilbert 		return false;
55773a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5578c4837394SDouglas Gilbert }
5579c4837394SDouglas Gilbert 
5580a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5581a2aede97SDouglas Gilbert 
5582c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5583c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5584c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5585c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5586c4837394SDouglas Gilbert  */
5587fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5588f66b8517SMartin Wilck 			 int scsi_result,
5589f19fe8f3SBart Van Assche 			 int (*pfp)(struct scsi_cmnd *,
5590f19fe8f3SBart Van Assche 				    struct sdebug_dev_info *),
5591f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
55921da177e4SLinus Torvalds {
5593a2aede97SDouglas Gilbert 	bool new_sd_dp;
55943a90a63dSDouglas Gilbert 	bool inject = false;
55956ce913feSChristoph Hellwig 	bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED;
55963a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5597a2aede97SDouglas Gilbert 	unsigned long iflags;
5598a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5599c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5600c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5601299b6c07STomas Winkler 	struct scsi_device *sdp;
5602a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
56031da177e4SLinus Torvalds 
5604b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5605b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5606f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5607f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
56081da177e4SLinus Torvalds 	}
5609299b6c07STomas Winkler 	sdp = cmnd->device;
5610299b6c07STomas Winkler 
5611f19fe8f3SBart Van Assche 	if (delta_jiff == 0)
5612cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56131da177e4SLinus Torvalds 
5614c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5615c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5616c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5617c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5618c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5619c4837394SDouglas Gilbert 	}
5620cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5621cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5622f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5623cd62b7daSDouglas Gilbert 		if (scsi_result) {
5624c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5625cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5626cd62b7daSDouglas Gilbert 		} else
5627cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5628c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5629773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5630f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5631cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5632cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5633773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5634cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
56353a90a63dSDouglas Gilbert 			inject = true;
5636cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
56371da177e4SLinus Torvalds 		}
5638cbf67842SDouglas Gilbert 	}
5639cbf67842SDouglas Gilbert 
5640c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5641f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5642c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5643cd62b7daSDouglas Gilbert 		if (scsi_result)
5644cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5645cd62b7daSDouglas Gilbert 		scsi_result = device_qfull_result;
5646773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
56477d5a129bSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
56487d5a129bSDouglas Gilbert 				    __func__, sdebug_max_queue);
5649cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56501da177e4SLinus Torvalds 	}
565174595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5652cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5653c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
56541da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5655c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5656a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5657c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5658c4b57d89SKashyap Desai 
565974595c04SDouglas Gilbert 	if (!sd_dp) {
566010bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
566174595c04SDouglas Gilbert 		if (!sd_dp) {
566274595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
566374595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
566410bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
566574595c04SDouglas Gilbert 		}
5666a2aede97SDouglas Gilbert 		new_sd_dp = true;
5667a2aede97SDouglas Gilbert 	} else {
5668a2aede97SDouglas Gilbert 		new_sd_dp = false;
566910bde980SDouglas Gilbert 	}
5670f66b8517SMartin Wilck 
5671c10fa55fSJohn Garry 	/* Set the hostwide tag */
5672c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5673c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5674c10fa55fSJohn Garry 
56756ce913feSChristoph Hellwig 	if (polled)
5676a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5677a2aede97SDouglas Gilbert 
5678a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
56793a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5680f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5681f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5682f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5683f66b8517SMartin Wilck 	}
5684f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5685f66b8517SMartin Wilck 		cmnd->result = scsi_result;
56863a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
56873a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
56883a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
56893a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56903a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
56913a90a63dSDouglas Gilbert 		}
56923a90a63dSDouglas Gilbert 	}
5693f66b8517SMartin Wilck 
5694f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5695f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5696f66b8517SMartin Wilck 			    __func__, cmnd->result);
5697f66b8517SMartin Wilck 
569810bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5699b333a819SDouglas Gilbert 		ktime_t kt;
5700cbf67842SDouglas Gilbert 
5701b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
57020c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
57030c4bc91dSDouglas Gilbert 
57040c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
57050c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
57060c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
57070c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
57080c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
57090c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
57100c4bc91dSDouglas Gilbert 				ns <<= 12;
57110c4bc91dSDouglas Gilbert 			}
57120c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
57130c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
57140c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
57150c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5716a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5717a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5718a2aede97SDouglas Gilbert 
5719a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5720223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5721a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5722a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5723a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5724223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5725a2aede97SDouglas Gilbert 					if (new_sd_dp)
5726a2aede97SDouglas Gilbert 						kfree(sd_dp);
5727a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
57286c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5729a2aede97SDouglas Gilbert 					return 0;
5730a2aede97SDouglas Gilbert 				}
5731a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5732a2aede97SDouglas Gilbert 				kt -= d;
5733a2aede97SDouglas Gilbert 			}
57340c4bc91dSDouglas Gilbert 		}
57356ce913feSChristoph Hellwig 		if (polled) {
57364a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
57374a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57384a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57394a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57404a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57414a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57424a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57434a0c6f43SDouglas Gilbert 			}
5744d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57454a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57464a0c6f43SDouglas Gilbert 		} else {
574710bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
574810bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5749a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5750a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5751c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5752a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5753c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5754c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5755cbf67842SDouglas Gilbert 			}
5756d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
5757a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5758c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
57594a0c6f43SDouglas Gilbert 		}
57604a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
57614a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5762c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
57634a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
57644a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
57654a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
57666ce913feSChristoph Hellwig 		if (polled) {
57674a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
57684a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57694a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57704a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57714a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57724a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57734a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57744a0c6f43SDouglas Gilbert 			}
5775d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57764a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57774a0c6f43SDouglas Gilbert 		} else {
577810bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
577910bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5780a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5781c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5782c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5783a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5784cbf67842SDouglas Gilbert 			}
5785d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
57864a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
57874a0c6f43SDouglas Gilbert 		}
5788c4837394SDouglas Gilbert 		if (sdebug_statistics)
5789c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
57904a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
5791a6e76e6fSBart Van Assche 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5792a6e76e6fSBart Van Assche 				    scsi_cmd_to_rq(cmnd)->tag);
5793a6e76e6fSBart Van Assche 			blk_abort_request(scsi_cmd_to_rq(cmnd));
57943a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
57954a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
57967382f9d8SDouglas Gilbert 		}
5797cbf67842SDouglas Gilbert 	}
57983a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
57993a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
58003a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
58011da177e4SLinus Torvalds 	return 0;
5802cd62b7daSDouglas Gilbert 
5803cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5804f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5805f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5806f19fe8f3SBart Van Assche 	if (cmnd->result == 0 && scsi_result != 0)
5807cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
58086c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5809cd62b7daSDouglas Gilbert 	return 0;
58101da177e4SLinus Torvalds }
5811cbf67842SDouglas Gilbert 
581223183910SDouglas Gilbert /* Note: The following macros create attribute files in the
581323183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
581423183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
581523183910SDouglas Gilbert    as it can when the corresponding attribute in the
581623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
581723183910SDouglas Gilbert  */
5818773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5819773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
58209b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5821773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5822c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5823773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5824773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5825773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5826773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5827773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5828773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5829773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5830773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5831c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5832e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5833e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5834e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5835e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
58365d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
58375d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
58385d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5839773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5840773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5841773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5842773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5843ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5844773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5845773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
58465d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
58475d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58485d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
58495d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5850773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5851773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
58527109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
5853773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5854773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5855773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5856773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
58575d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5858773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
585987c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
586087c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5861773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5862773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
58630c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5864773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5865773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5866773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5867c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5868773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5869c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5870c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5871fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5872773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5873773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5874773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5875773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
587609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
58775d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5878773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
587923183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58809447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5881773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
58825b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
58839267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
58844a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO);
5885380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5886aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
588798e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
58881da177e4SLinus Torvalds 
58891da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
58901da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
58911da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5892b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
58931da177e4SLinus Torvalds 
58945d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
58955b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
58969b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
58970759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5898cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5899c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
59005b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
59015b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5902c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5903beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
590423183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
59055b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5906185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5907c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5908c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5909e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
59109b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
59119b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
59125d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
59135d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
59145d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
59155b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
59165b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
59175b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
59185b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5919ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5920fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5921cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5922d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
59235d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5924cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5925c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
59267109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
592778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
59281da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5929c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
593032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
593186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
59325d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
59335d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
59345d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5935fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
59361da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
59370c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5938d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5939760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5940ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5941c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5942c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5943c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5944fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
59455b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
59465b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
59476014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
59486014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
594909ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
595009ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5951c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
59525b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
59539447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
59545b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
59559267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
59564a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)");
5957380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5958aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
595998e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
59601da177e4SLinus Torvalds 
5961760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5962760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
59631da177e4SLinus Torvalds 
59641da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
59651da177e4SLinus Torvalds {
5966c4837394SDouglas Gilbert 	int k;
5967c4837394SDouglas Gilbert 
5968760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5969760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5970760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5971c4837394SDouglas Gilbert 		return sdebug_info;
5972760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5973760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5974760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5975760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
59761da177e4SLinus Torvalds 	return sdebug_info;
59771da177e4SLinus Torvalds }
59781da177e4SLinus Torvalds 
5979cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5980fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5981fd32119bSDouglas Gilbert 				 int length)
59821da177e4SLinus Torvalds {
59831da177e4SLinus Torvalds 	char arr[16];
5984c8ed555aSAl Viro 	int opts;
59851da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
59861da177e4SLinus Torvalds 
59871da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
59881da177e4SLinus Torvalds 		return -EACCES;
59891da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
59901da177e4SLinus Torvalds 	arr[minLen] = '\0';
5991c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
59921da177e4SLinus Torvalds 		return -EINVAL;
5993773642d9SDouglas Gilbert 	sdebug_opts = opts;
5994773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5995773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5996773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5997c4837394SDouglas Gilbert 		tweak_cmnd_count();
59981da177e4SLinus Torvalds 	return length;
59991da177e4SLinus Torvalds }
6000c8ed555aSAl Viro 
6001cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
6002cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
6003cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
6004c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
6005c8ed555aSAl Viro {
6006c4837394SDouglas Gilbert 	int f, j, l;
6007c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
600887c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
6009cbf67842SDouglas Gilbert 
6010c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
6011c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
6012c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
6013c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
6014c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
6015c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
6016c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
6017c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
6018c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
6019c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
6020c4837394SDouglas Gilbert 		   num_aborts);
6021c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
6022c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
6023c4837394SDouglas Gilbert 		   num_host_resets);
6024c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
6025c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
6026458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
6027458df78bSBart Van Assche 		   sdebug_statistics);
60284a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
6029c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
6030c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
6031c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
60324a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
60334a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
6034cbf67842SDouglas Gilbert 
6035c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
6036c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
6037c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
6038c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
6039773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
6040c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
6041c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
6042c4837394SDouglas Gilbert 				   "first,last bits", f, l);
6043c4837394SDouglas Gilbert 		}
6044cbf67842SDouglas Gilbert 	}
604587c715dcSDouglas Gilbert 
604687c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
604787c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
604887c715dcSDouglas Gilbert 		bool niu;
604987c715dcSDouglas Gilbert 		int idx;
605087c715dcSDouglas Gilbert 		unsigned long l_idx;
605187c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
605287c715dcSDouglas Gilbert 
605387c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
605487c715dcSDouglas Gilbert 		j = 0;
605587c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
605687c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
605787c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
605887c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
605987c715dcSDouglas Gilbert 			++j;
606087c715dcSDouglas Gilbert 		}
606187c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
606287c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
606387c715dcSDouglas Gilbert 		j = 0;
606487c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
606587c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
606687c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
606787c715dcSDouglas Gilbert 			idx = (int)l_idx;
606887c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
606987c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
607087c715dcSDouglas Gilbert 			++j;
607187c715dcSDouglas Gilbert 		}
607287c715dcSDouglas Gilbert 	}
6073c8ed555aSAl Viro 	return 0;
60741da177e4SLinus Torvalds }
60751da177e4SLinus Torvalds 
607682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
60771da177e4SLinus Torvalds {
6078c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
60791da177e4SLinus Torvalds }
6080c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
6081c4837394SDouglas Gilbert  * of delay is jiffies.
6082c4837394SDouglas Gilbert  */
608382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
608482069379SAkinobu Mita 			   size_t count)
60851da177e4SLinus Torvalds {
6086c2206098SDouglas Gilbert 	int jdelay, res;
60871da177e4SLinus Torvalds 
6088b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
6089cbf67842SDouglas Gilbert 		res = count;
6090c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
6091c4837394SDouglas Gilbert 			int j, k;
6092c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6093cbf67842SDouglas Gilbert 
6094f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6095c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6096c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6097c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6098c4837394SDouglas Gilbert 						   sdebug_max_queue);
6099c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6100c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6101c4837394SDouglas Gilbert 					break;
6102c4837394SDouglas Gilbert 				}
6103c4837394SDouglas Gilbert 			}
6104c4837394SDouglas Gilbert 			if (res > 0) {
6105c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
6106773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
61071da177e4SLinus Torvalds 			}
6108f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
6109cbf67842SDouglas Gilbert 		}
6110cbf67842SDouglas Gilbert 		return res;
61111da177e4SLinus Torvalds 	}
61121da177e4SLinus Torvalds 	return -EINVAL;
61131da177e4SLinus Torvalds }
611482069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
61151da177e4SLinus Torvalds 
6116cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
6117cbf67842SDouglas Gilbert {
6118773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
6119cbf67842SDouglas Gilbert }
6120cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6121c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
6122cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6123cbf67842SDouglas Gilbert 			    size_t count)
6124cbf67842SDouglas Gilbert {
6125c4837394SDouglas Gilbert 	int ndelay, res;
6126cbf67842SDouglas Gilbert 
6127cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6128c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6129cbf67842SDouglas Gilbert 		res = count;
6130773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
6131c4837394SDouglas Gilbert 			int j, k;
6132c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6133c4837394SDouglas Gilbert 
6134f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6135c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6136c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6137c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6138c4837394SDouglas Gilbert 						   sdebug_max_queue);
6139c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6140c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6141c4837394SDouglas Gilbert 					break;
6142c4837394SDouglas Gilbert 				}
6143c4837394SDouglas Gilbert 			}
6144c4837394SDouglas Gilbert 			if (res > 0) {
6145773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6146c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6147c2206098SDouglas Gilbert 							: DEF_JDELAY;
6148cbf67842SDouglas Gilbert 			}
6149f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
6150cbf67842SDouglas Gilbert 		}
6151cbf67842SDouglas Gilbert 		return res;
6152cbf67842SDouglas Gilbert 	}
6153cbf67842SDouglas Gilbert 	return -EINVAL;
6154cbf67842SDouglas Gilbert }
6155cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6156cbf67842SDouglas Gilbert 
615782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
61581da177e4SLinus Torvalds {
6159773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
61601da177e4SLinus Torvalds }
61611da177e4SLinus Torvalds 
616282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
616382069379SAkinobu Mita 			  size_t count)
61641da177e4SLinus Torvalds {
61651da177e4SLinus Torvalds 	int opts;
61661da177e4SLinus Torvalds 	char work[20];
61671da177e4SLinus Torvalds 
61689a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61699a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61709a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
61711da177e4SLinus Torvalds 				goto opts_done;
61721da177e4SLinus Torvalds 		} else {
61739a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
61741da177e4SLinus Torvalds 				goto opts_done;
61751da177e4SLinus Torvalds 		}
61761da177e4SLinus Torvalds 	}
61771da177e4SLinus Torvalds 	return -EINVAL;
61781da177e4SLinus Torvalds opts_done:
6179773642d9SDouglas Gilbert 	sdebug_opts = opts;
6180773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6181773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6182c4837394SDouglas Gilbert 	tweak_cmnd_count();
61831da177e4SLinus Torvalds 	return count;
61841da177e4SLinus Torvalds }
618582069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
61861da177e4SLinus Torvalds 
618782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
61881da177e4SLinus Torvalds {
6189773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
61901da177e4SLinus Torvalds }
619182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
619282069379SAkinobu Mita 			   size_t count)
61931da177e4SLinus Torvalds {
61941da177e4SLinus Torvalds 	int n;
61951da177e4SLinus Torvalds 
6196f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6197f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6198f0d1cf93SDouglas Gilbert 		return -EINVAL;
6199f0d1cf93SDouglas Gilbert 
62001da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6201f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6202f0d1cf93SDouglas Gilbert 			return -EINVAL;
6203773642d9SDouglas Gilbert 		sdebug_ptype = n;
62041da177e4SLinus Torvalds 		return count;
62051da177e4SLinus Torvalds 	}
62061da177e4SLinus Torvalds 	return -EINVAL;
62071da177e4SLinus Torvalds }
620882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
62091da177e4SLinus Torvalds 
621082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
62111da177e4SLinus Torvalds {
6212773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
62131da177e4SLinus Torvalds }
621482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
621582069379SAkinobu Mita 			    size_t count)
62161da177e4SLinus Torvalds {
62171da177e4SLinus Torvalds 	int n;
62181da177e4SLinus Torvalds 
62191da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6220773642d9SDouglas Gilbert 		sdebug_dsense = n;
62211da177e4SLinus Torvalds 		return count;
62221da177e4SLinus Torvalds 	}
62231da177e4SLinus Torvalds 	return -EINVAL;
62241da177e4SLinus Torvalds }
622582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
62261da177e4SLinus Torvalds 
622782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
622823183910SDouglas Gilbert {
6229773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
623023183910SDouglas Gilbert }
623182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
623282069379SAkinobu Mita 			     size_t count)
623323183910SDouglas Gilbert {
623487c715dcSDouglas Gilbert 	int n, idx;
623523183910SDouglas Gilbert 
623623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
623787c715dcSDouglas Gilbert 		bool want_store = (n == 0);
623887c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
623987c715dcSDouglas Gilbert 
6240cbf67842SDouglas Gilbert 		n = (n > 0);
6241773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
624287c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
624387c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6244cbf67842SDouglas Gilbert 
624587c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
624687c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
624787c715dcSDouglas Gilbert 				idx = sdebug_add_store();
624887c715dcSDouglas Gilbert 				if (idx < 0)
624987c715dcSDouglas Gilbert 					return idx;
625087c715dcSDouglas Gilbert 			} else {
625187c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
625287c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
625387c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6254cbf67842SDouglas Gilbert 			}
625587c715dcSDouglas Gilbert 			/* make all hosts use same store */
625687c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
625787c715dcSDouglas Gilbert 					    host_list) {
625887c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
625987c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
626087c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
626187c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
626287c715dcSDouglas Gilbert 				}
626387c715dcSDouglas Gilbert 			}
626487c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
626587c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
626687c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6267cbf67842SDouglas Gilbert 		}
6268773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
626923183910SDouglas Gilbert 		return count;
627023183910SDouglas Gilbert 	}
627123183910SDouglas Gilbert 	return -EINVAL;
627223183910SDouglas Gilbert }
627382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
627423183910SDouglas Gilbert 
627582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6276c65b1445SDouglas Gilbert {
6277773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6278c65b1445SDouglas Gilbert }
627982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
628082069379SAkinobu Mita 			      size_t count)
6281c65b1445SDouglas Gilbert {
6282c65b1445SDouglas Gilbert 	int n;
6283c65b1445SDouglas Gilbert 
6284c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6285773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6286c65b1445SDouglas Gilbert 		return count;
6287c65b1445SDouglas Gilbert 	}
6288c65b1445SDouglas Gilbert 	return -EINVAL;
6289c65b1445SDouglas Gilbert }
629082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6291c65b1445SDouglas Gilbert 
629282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
62931da177e4SLinus Torvalds {
6294773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
62951da177e4SLinus Torvalds }
629682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
629782069379SAkinobu Mita 			      size_t count)
62981da177e4SLinus Torvalds {
62991da177e4SLinus Torvalds 	int n;
63001da177e4SLinus Torvalds 
63011da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6302773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
63031da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
63041da177e4SLinus Torvalds 		return count;
63051da177e4SLinus Torvalds 	}
63061da177e4SLinus Torvalds 	return -EINVAL;
63071da177e4SLinus Torvalds }
630882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
63091da177e4SLinus Torvalds 
631082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
63111da177e4SLinus Torvalds {
6312773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
63131da177e4SLinus Torvalds }
631482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
63151da177e4SLinus Torvalds 
631687c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
631787c715dcSDouglas Gilbert {
631887c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
631987c715dcSDouglas Gilbert }
632087c715dcSDouglas Gilbert 
632187c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
632287c715dcSDouglas Gilbert 				    size_t count)
632387c715dcSDouglas Gilbert {
632487c715dcSDouglas Gilbert 	bool v;
632587c715dcSDouglas Gilbert 
632687c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
632787c715dcSDouglas Gilbert 		return -EINVAL;
632887c715dcSDouglas Gilbert 
632987c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
633087c715dcSDouglas Gilbert 	return count;
633187c715dcSDouglas Gilbert }
633287c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
633387c715dcSDouglas Gilbert 
633482069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
63351da177e4SLinus Torvalds {
6336773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
63371da177e4SLinus Torvalds }
633882069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
63391da177e4SLinus Torvalds 
634082069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
63411da177e4SLinus Torvalds {
6342773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
63431da177e4SLinus Torvalds }
634482069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
634582069379SAkinobu Mita 			       size_t count)
63461da177e4SLinus Torvalds {
63471da177e4SLinus Torvalds 	int nth;
63483a90a63dSDouglas Gilbert 	char work[20];
63491da177e4SLinus Torvalds 
63503a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
63513a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
63523a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
63533a90a63dSDouglas Gilbert 				goto every_nth_done;
63543a90a63dSDouglas Gilbert 		} else {
63553a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
63563a90a63dSDouglas Gilbert 				goto every_nth_done;
63573a90a63dSDouglas Gilbert 		}
63583a90a63dSDouglas Gilbert 	}
63593a90a63dSDouglas Gilbert 	return -EINVAL;
63603a90a63dSDouglas Gilbert 
63613a90a63dSDouglas Gilbert every_nth_done:
6362773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6363c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6364c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6365c4837394SDouglas Gilbert 		sdebug_statistics = true;
6366c4837394SDouglas Gilbert 	}
6367c4837394SDouglas Gilbert 	tweak_cmnd_count();
63681da177e4SLinus Torvalds 	return count;
63691da177e4SLinus Torvalds }
637082069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
63711da177e4SLinus Torvalds 
6372ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6373ad0c7775SDouglas Gilbert {
6374ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6375ad0c7775SDouglas Gilbert }
6376ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6377ad0c7775SDouglas Gilbert 				size_t count)
6378ad0c7775SDouglas Gilbert {
6379ad0c7775SDouglas Gilbert 	int n;
6380ad0c7775SDouglas Gilbert 	bool changed;
6381ad0c7775SDouglas Gilbert 
6382ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6383ad0c7775SDouglas Gilbert 		return -EINVAL;
6384ad0c7775SDouglas Gilbert 	if (n >= 0) {
6385ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6386ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6387ad0c7775SDouglas Gilbert 			return -EINVAL;
6388ad0c7775SDouglas Gilbert 		}
6389ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6390ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6391ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6392ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6393ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6394ad0c7775SDouglas Gilbert 
6395ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6396ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6397ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6398ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6399ad0c7775SDouglas Gilbert 				}
6400ad0c7775SDouglas Gilbert 			}
6401ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6402ad0c7775SDouglas Gilbert 		}
6403ad0c7775SDouglas Gilbert 		return count;
6404ad0c7775SDouglas Gilbert 	}
6405ad0c7775SDouglas Gilbert 	return -EINVAL;
6406ad0c7775SDouglas Gilbert }
6407ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6408ad0c7775SDouglas Gilbert 
640982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
64101da177e4SLinus Torvalds {
6411773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
64121da177e4SLinus Torvalds }
641382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
641482069379SAkinobu Mita 			      size_t count)
64151da177e4SLinus Torvalds {
64161da177e4SLinus Torvalds 	int n;
641719c8ead7SEwan D. Milne 	bool changed;
64181da177e4SLinus Torvalds 
64191da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
64208d039e22SDouglas Gilbert 		if (n > 256) {
64218d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
64228d039e22SDouglas Gilbert 			return -EINVAL;
64238d039e22SDouglas Gilbert 		}
6424773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6425773642d9SDouglas Gilbert 		sdebug_max_luns = n;
64261da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6427773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
642819c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
642919c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
643019c8ead7SEwan D. Milne 
643119c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
643219c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
643319c8ead7SEwan D. Milne 					    host_list) {
643419c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
643519c8ead7SEwan D. Milne 						    dev_list) {
643619c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
643719c8ead7SEwan D. Milne 						dp->uas_bm);
643819c8ead7SEwan D. Milne 				}
643919c8ead7SEwan D. Milne 			}
644019c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
644119c8ead7SEwan D. Milne 		}
64421da177e4SLinus Torvalds 		return count;
64431da177e4SLinus Torvalds 	}
64441da177e4SLinus Torvalds 	return -EINVAL;
64451da177e4SLinus Torvalds }
644682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
64471da177e4SLinus Torvalds 
644882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
644978d4e5a0SDouglas Gilbert {
6450773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
645178d4e5a0SDouglas Gilbert }
6452cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6453cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
645482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
645582069379SAkinobu Mita 			       size_t count)
645678d4e5a0SDouglas Gilbert {
6457c4837394SDouglas Gilbert 	int j, n, k, a;
6458c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
645978d4e5a0SDouglas Gilbert 
646078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6461c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6462c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6463f19fe8f3SBart Van Assche 		block_unblock_all_queues(true);
6464c4837394SDouglas Gilbert 		k = 0;
6465c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6466c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6467c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6468c4837394SDouglas Gilbert 			if (a > k)
6469c4837394SDouglas Gilbert 				k = a;
6470c4837394SDouglas Gilbert 		}
6471773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6472c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6473cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6474cbf67842SDouglas Gilbert 		else if (k >= n)
6475cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6476cbf67842SDouglas Gilbert 		else
6477cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6478f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
647978d4e5a0SDouglas Gilbert 		return count;
648078d4e5a0SDouglas Gilbert 	}
648178d4e5a0SDouglas Gilbert 	return -EINVAL;
648278d4e5a0SDouglas Gilbert }
648382069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
648478d4e5a0SDouglas Gilbert 
6485c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6486c10fa55fSJohn Garry {
6487c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6488c10fa55fSJohn Garry }
6489c10fa55fSJohn Garry 
64907109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
64917109f370SDouglas Gilbert {
64927109f370SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
64937109f370SDouglas Gilbert }
64947109f370SDouglas Gilbert 
64957109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
64967109f370SDouglas Gilbert {
64977109f370SDouglas Gilbert 	bool v;
64987109f370SDouglas Gilbert 
64997109f370SDouglas Gilbert 	if (kstrtobool(buf, &v))
65007109f370SDouglas Gilbert 		return -EINVAL;
65017109f370SDouglas Gilbert 
65027109f370SDouglas Gilbert 	sdebug_no_rwlock = v;
65037109f370SDouglas Gilbert 	return count;
65047109f370SDouglas Gilbert }
65057109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock);
65067109f370SDouglas Gilbert 
6507c10fa55fSJohn Garry /*
6508c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6509c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6510c10fa55fSJohn Garry  */
6511c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6512c10fa55fSJohn Garry 
651382069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
651478d4e5a0SDouglas Gilbert {
6515773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
651678d4e5a0SDouglas Gilbert }
651782069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
651878d4e5a0SDouglas Gilbert 
651982069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
65201da177e4SLinus Torvalds {
6521773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
65221da177e4SLinus Torvalds }
652382069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
65241da177e4SLinus Torvalds 
652582069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6526c65b1445SDouglas Gilbert {
6527773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6528c65b1445SDouglas Gilbert }
652982069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
653082069379SAkinobu Mita 				size_t count)
6531c65b1445SDouglas Gilbert {
6532c65b1445SDouglas Gilbert 	int n;
65330d01c5dfSDouglas Gilbert 	bool changed;
6534c65b1445SDouglas Gilbert 
6535f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6536f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6537f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6538f0d1cf93SDouglas Gilbert 
6539c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6540773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6541773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
654228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
65430d01c5dfSDouglas Gilbert 		if (changed) {
65440d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
65450d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
654628898873SFUJITA Tomonori 
65474bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
65480d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
65490d01c5dfSDouglas Gilbert 					    host_list) {
65500d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
65510d01c5dfSDouglas Gilbert 						    dev_list) {
65520d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
65530d01c5dfSDouglas Gilbert 						dp->uas_bm);
65540d01c5dfSDouglas Gilbert 				}
65550d01c5dfSDouglas Gilbert 			}
65564bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
65570d01c5dfSDouglas Gilbert 		}
6558c65b1445SDouglas Gilbert 		return count;
6559c65b1445SDouglas Gilbert 	}
6560c65b1445SDouglas Gilbert 	return -EINVAL;
6561c65b1445SDouglas Gilbert }
656282069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6563c65b1445SDouglas Gilbert 
656482069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
65651da177e4SLinus Torvalds {
656687c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
6567f19fe8f3SBart Van Assche 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
65681da177e4SLinus Torvalds }
65691da177e4SLinus Torvalds 
657082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
657182069379SAkinobu Mita 			      size_t count)
65721da177e4SLinus Torvalds {
6573f19fe8f3SBart Van Assche 	bool found;
6574f19fe8f3SBart Van Assche 	unsigned long idx;
6575f19fe8f3SBart Van Assche 	struct sdeb_store_info *sip;
6576f19fe8f3SBart Van Assche 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
65771da177e4SLinus Torvalds 	int delta_hosts;
65781da177e4SLinus Torvalds 
6579f19fe8f3SBart Van Assche 	if (sscanf(buf, "%d", &delta_hosts) != 1)
65801da177e4SLinus Torvalds 		return -EINVAL;
65811da177e4SLinus Torvalds 	if (delta_hosts > 0) {
65821da177e4SLinus Torvalds 		do {
6583f19fe8f3SBart Van Assche 			found = false;
6584f19fe8f3SBart Van Assche 			if (want_phs) {
6585f19fe8f3SBart Van Assche 				xa_for_each_marked(per_store_ap, idx, sip,
6586f19fe8f3SBart Van Assche 						   SDEB_XA_NOT_IN_USE) {
6587f19fe8f3SBart Van Assche 					sdeb_most_recent_idx = (int)idx;
6588f19fe8f3SBart Van Assche 					found = true;
658987c715dcSDouglas Gilbert 					break;
659087c715dcSDouglas Gilbert 				}
6591f19fe8f3SBart Van Assche 				if (found)	/* re-use case */
6592f19fe8f3SBart Van Assche 					sdebug_add_host_helper((int)idx);
6593f19fe8f3SBart Van Assche 				else
6594f19fe8f3SBart Van Assche 					sdebug_do_add_host(true);
6595f19fe8f3SBart Van Assche 			} else {
6596f19fe8f3SBart Van Assche 				sdebug_do_add_host(false);
6597f19fe8f3SBart Van Assche 			}
6598f19fe8f3SBart Van Assche 		} while (--delta_hosts);
6599f19fe8f3SBart Van Assche 	} else if (delta_hosts < 0) {
6600f19fe8f3SBart Van Assche 		do {
660187c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
66021da177e4SLinus Torvalds 		} while (++delta_hosts);
66031da177e4SLinus Torvalds 	}
66041da177e4SLinus Torvalds 	return count;
66051da177e4SLinus Torvalds }
660682069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
66071da177e4SLinus Torvalds 
660882069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
660923183910SDouglas Gilbert {
6610773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
661123183910SDouglas Gilbert }
661282069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
661382069379SAkinobu Mita 				    size_t count)
661423183910SDouglas Gilbert {
661523183910SDouglas Gilbert 	int n;
661623183910SDouglas Gilbert 
661723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6618773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
661923183910SDouglas Gilbert 		return count;
662023183910SDouglas Gilbert 	}
662123183910SDouglas Gilbert 	return -EINVAL;
662223183910SDouglas Gilbert }
662382069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
662423183910SDouglas Gilbert 
6625c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6626c4837394SDouglas Gilbert {
6627c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6628c4837394SDouglas Gilbert }
6629c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6630c4837394SDouglas Gilbert 				size_t count)
6631c4837394SDouglas Gilbert {
6632c4837394SDouglas Gilbert 	int n;
6633c4837394SDouglas Gilbert 
6634c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6635c4837394SDouglas Gilbert 		if (n > 0)
6636c4837394SDouglas Gilbert 			sdebug_statistics = true;
6637c4837394SDouglas Gilbert 		else {
6638c4837394SDouglas Gilbert 			clear_queue_stats();
6639c4837394SDouglas Gilbert 			sdebug_statistics = false;
6640c4837394SDouglas Gilbert 		}
6641c4837394SDouglas Gilbert 		return count;
6642c4837394SDouglas Gilbert 	}
6643c4837394SDouglas Gilbert 	return -EINVAL;
6644c4837394SDouglas Gilbert }
6645c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6646c4837394SDouglas Gilbert 
664782069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6648597136abSMartin K. Petersen {
6649773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6650597136abSMartin K. Petersen }
665182069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6652597136abSMartin K. Petersen 
6653c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6654c4837394SDouglas Gilbert {
6655c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6656c4837394SDouglas Gilbert }
6657c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6658c4837394SDouglas Gilbert 
665982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6660c6a44287SMartin K. Petersen {
6661773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6662c6a44287SMartin K. Petersen }
666382069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6664c6a44287SMartin K. Petersen 
666582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6666c6a44287SMartin K. Petersen {
6667773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6668c6a44287SMartin K. Petersen }
666982069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6670c6a44287SMartin K. Petersen 
667182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6672c6a44287SMartin K. Petersen {
6673773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6674c6a44287SMartin K. Petersen }
667582069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6676c6a44287SMartin K. Petersen 
667782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6678c6a44287SMartin K. Petersen {
6679773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6680c6a44287SMartin K. Petersen }
668182069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6682c6a44287SMartin K. Petersen 
668382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
668444d92694SMartin K. Petersen {
668587c715dcSDouglas Gilbert 	ssize_t count = 0;
668644d92694SMartin K. Petersen 
66875b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
668844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
668944d92694SMartin K. Petersen 				 sdebug_store_sectors);
669044d92694SMartin K. Petersen 
669187c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
669287c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
669387c715dcSDouglas Gilbert 
669487c715dcSDouglas Gilbert 		if (sip)
6695c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
669687c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
669787c715dcSDouglas Gilbert 	}
669844d92694SMartin K. Petersen 	buf[count++] = '\n';
6699c7badc90STejun Heo 	buf[count] = '\0';
670044d92694SMartin K. Petersen 
670144d92694SMartin K. Petersen 	return count;
670244d92694SMartin K. Petersen }
670382069379SAkinobu Mita static DRIVER_ATTR_RO(map);
670444d92694SMartin K. Petersen 
67050c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
67060c4bc91dSDouglas Gilbert {
67070c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
67080c4bc91dSDouglas Gilbert }
67090c4bc91dSDouglas Gilbert 
67100c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
67110c4bc91dSDouglas Gilbert 			    size_t count)
67120c4bc91dSDouglas Gilbert {
67130c4bc91dSDouglas Gilbert 	bool v;
67140c4bc91dSDouglas Gilbert 
67150c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
67160c4bc91dSDouglas Gilbert 		return -EINVAL;
67170c4bc91dSDouglas Gilbert 
67180c4bc91dSDouglas Gilbert 	sdebug_random = v;
67190c4bc91dSDouglas Gilbert 	return count;
67200c4bc91dSDouglas Gilbert }
67210c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
67220c4bc91dSDouglas Gilbert 
672382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6724d986788bSMartin Pitt {
6725773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6726d986788bSMartin Pitt }
672782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
672882069379SAkinobu Mita 			       size_t count)
6729d986788bSMartin Pitt {
6730d986788bSMartin Pitt 	int n;
6731d986788bSMartin Pitt 
6732d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6733773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6734d986788bSMartin Pitt 		return count;
6735d986788bSMartin Pitt 	}
6736d986788bSMartin Pitt 	return -EINVAL;
6737d986788bSMartin Pitt }
673882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6739d986788bSMartin Pitt 
6740cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6741cbf67842SDouglas Gilbert {
6742773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6743cbf67842SDouglas Gilbert }
6744185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6745cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6746cbf67842SDouglas Gilbert 			       size_t count)
6747cbf67842SDouglas Gilbert {
6748185dd232SDouglas Gilbert 	int n;
6749cbf67842SDouglas Gilbert 
6750cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6751185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6752185dd232SDouglas Gilbert 		return count;
6753cbf67842SDouglas Gilbert 	}
6754cbf67842SDouglas Gilbert 	return -EINVAL;
6755cbf67842SDouglas Gilbert }
6756cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6757cbf67842SDouglas Gilbert 
6758c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6759c2248fc9SDouglas Gilbert {
6760773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6761c2248fc9SDouglas Gilbert }
6762c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6763c2248fc9SDouglas Gilbert 			    size_t count)
6764c2248fc9SDouglas Gilbert {
6765c2248fc9SDouglas Gilbert 	int n;
6766c2248fc9SDouglas Gilbert 
6767c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6768773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6769c2248fc9SDouglas Gilbert 		return count;
6770c2248fc9SDouglas Gilbert 	}
6771c2248fc9SDouglas Gilbert 	return -EINVAL;
6772c2248fc9SDouglas Gilbert }
6773c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6774c2248fc9SDouglas Gilbert 
677509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
677609ba24c1SDouglas Gilbert {
677709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
677809ba24c1SDouglas Gilbert }
677909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
678009ba24c1SDouglas Gilbert 
67819b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
67829b760fd8SDouglas Gilbert {
67839b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
67849b760fd8SDouglas Gilbert }
67859b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
67869b760fd8SDouglas Gilbert 			     size_t count)
67879b760fd8SDouglas Gilbert {
67889b760fd8SDouglas Gilbert 	int ret, n;
67899b760fd8SDouglas Gilbert 
67909b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
67919b760fd8SDouglas Gilbert 	if (ret)
67929b760fd8SDouglas Gilbert 		return ret;
67939b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
67949b760fd8SDouglas Gilbert 	all_config_cdb_len();
67959b760fd8SDouglas Gilbert 	return count;
67969b760fd8SDouglas Gilbert }
67979b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
67989b760fd8SDouglas Gilbert 
67999267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
68009267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
68019267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
68029267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
68039267e0ebSDouglas Gilbert };
68049267e0ebSDouglas Gilbert 
68059267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
68069267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
68079267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
68089267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
68099267e0ebSDouglas Gilbert };
68109267e0ebSDouglas Gilbert 
68119267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
68129267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
68139267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
68149267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
68159267e0ebSDouglas Gilbert };
68169267e0ebSDouglas Gilbert 
68179267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
68189267e0ebSDouglas Gilbert {
68199267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
68209267e0ebSDouglas Gilbert 
68219267e0ebSDouglas Gilbert 	if (res < 0) {
68229267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
68239267e0ebSDouglas Gilbert 		if (res < 0) {
68249267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
682547742bdeSDan Carpenter 			if (res < 0)
68269267e0ebSDouglas Gilbert 				return -EINVAL;
68279267e0ebSDouglas Gilbert 		}
68289267e0ebSDouglas Gilbert 	}
68299267e0ebSDouglas Gilbert 	return res;
68309267e0ebSDouglas Gilbert }
68319267e0ebSDouglas Gilbert 
68329267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
68339267e0ebSDouglas Gilbert {
68349267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
68359267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
68369267e0ebSDouglas Gilbert }
68379267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6838cbf67842SDouglas Gilbert 
6839fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6840fc13638aSDouglas Gilbert {
6841fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6842fc13638aSDouglas Gilbert }
6843fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6844fc13638aSDouglas Gilbert 
684582069379SAkinobu Mita /* Note: The following array creates attribute files in the
684623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
684723183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
684823183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
684987c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
685023183910SDouglas Gilbert  */
68516ecaff7fSRandy Dunlap 
685282069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
685382069379SAkinobu Mita 	&driver_attr_delay.attr,
685482069379SAkinobu Mita 	&driver_attr_opts.attr,
685582069379SAkinobu Mita 	&driver_attr_ptype.attr,
685682069379SAkinobu Mita 	&driver_attr_dsense.attr,
685782069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6858c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
685982069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
686082069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
686182069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
686282069379SAkinobu Mita 	&driver_attr_num_parts.attr,
686382069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6864ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
686582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
686682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
68677109f370SDouglas Gilbert 	&driver_attr_no_rwlock.attr,
686882069379SAkinobu Mita 	&driver_attr_no_uld.attr,
686982069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
687082069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
687182069379SAkinobu Mita 	&driver_attr_add_host.attr,
687287c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
687382069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
687482069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6875c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6876c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
687782069379SAkinobu Mita 	&driver_attr_dix.attr,
687882069379SAkinobu Mita 	&driver_attr_dif.attr,
687982069379SAkinobu Mita 	&driver_attr_guard.attr,
688082069379SAkinobu Mita 	&driver_attr_ato.attr,
688182069379SAkinobu Mita 	&driver_attr_map.attr,
68820c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
688382069379SAkinobu Mita 	&driver_attr_removable.attr,
6884cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6885cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6886c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
688709ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
68889b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6889fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
68909267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
689182069379SAkinobu Mita 	NULL,
689282069379SAkinobu Mita };
689382069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
68941da177e4SLinus Torvalds 
689511ddcecaSAkinobu Mita static struct device *pseudo_primary;
68968dea0d02SFUJITA Tomonori 
68971da177e4SLinus Torvalds static int __init scsi_debug_init(void)
68981da177e4SLinus Torvalds {
689987c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
69005f2578e5SFUJITA Tomonori 	unsigned long sz;
690187c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
690287c715dcSDouglas Gilbert 	int idx = -1;
69031da177e4SLinus Torvalds 
690487c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
690587c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6906cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6907cbf67842SDouglas Gilbert 
6908773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6909c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6910773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6911773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6912c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6913cbf67842SDouglas Gilbert 
6914773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6915597136abSMartin K. Petersen 	case  512:
6916597136abSMartin K. Petersen 	case 1024:
6917597136abSMartin K. Petersen 	case 2048:
6918597136abSMartin K. Petersen 	case 4096:
6919597136abSMartin K. Petersen 		break;
6920597136abSMartin K. Petersen 	default:
6921773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6922597136abSMartin K. Petersen 		return -EINVAL;
6923597136abSMartin K. Petersen 	}
6924597136abSMartin K. Petersen 
6925773642d9SDouglas Gilbert 	switch (sdebug_dif) {
69268475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6927f46eb0e9SDouglas Gilbert 		break;
69288475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
69298475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
69308475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6931f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6932c6a44287SMartin K. Petersen 		break;
6933c6a44287SMartin K. Petersen 
6934c6a44287SMartin K. Petersen 	default:
6935c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6936c6a44287SMartin K. Petersen 		return -EINVAL;
6937c6a44287SMartin K. Petersen 	}
6938c6a44287SMartin K. Petersen 
6939aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6940aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6941aa5334c4SMaurizio Lombardi 		return -EINVAL;
6942aa5334c4SMaurizio Lombardi 	}
6943aa5334c4SMaurizio Lombardi 
6944773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6945c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6946c6a44287SMartin K. Petersen 		return -EINVAL;
6947c6a44287SMartin K. Petersen 	}
6948c6a44287SMartin K. Petersen 
6949773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6950c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6951c6a44287SMartin K. Petersen 		return -EINVAL;
6952c6a44287SMartin K. Petersen 	}
6953c6a44287SMartin K. Petersen 
6954773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6955773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6956ea61fca5SMartin K. Petersen 		return -EINVAL;
6957ea61fca5SMartin K. Petersen 	}
6958ad0c7775SDouglas Gilbert 
6959ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6960ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6961ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6962ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6963ad0c7775SDouglas Gilbert 	}
6964ad0c7775SDouglas Gilbert 
69658d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6966ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6967ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
69688d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
69698d039e22SDouglas Gilbert 		}
6970ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6971ad0c7775SDouglas Gilbert 	}
6972ea61fca5SMartin K. Petersen 
6973773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6974773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6975ea61fca5SMartin K. Petersen 		return -EINVAL;
6976ea61fca5SMartin K. Petersen 	}
6977ea61fca5SMartin K. Petersen 
6978c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6979c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6980c4837394SDouglas Gilbert 		return -EINVAL;
6981c4837394SDouglas Gilbert 	}
6982c87bf24cSJohn Garry 
6983c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6984c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6985c87bf24cSJohn Garry 		return -EINVAL;
6986c87bf24cSJohn Garry 	}
6987c87bf24cSJohn Garry 
6988c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6989c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6990c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6991c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6992c10fa55fSJohn Garry 		return -EINVAL;
6993c10fa55fSJohn Garry 	}
6994c10fa55fSJohn Garry 
6995c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6996c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6997c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6998c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6999c10fa55fSJohn Garry 			sdebug_max_queue);
7000c10fa55fSJohn Garry 	}
7001c10fa55fSJohn Garry 
7002c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
7003c4837394SDouglas Gilbert 			       GFP_KERNEL);
7004c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
7005c4837394SDouglas Gilbert 		return -ENOMEM;
7006c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
7007c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
7008c4837394SDouglas Gilbert 
7009f0d1cf93SDouglas Gilbert 	/*
70109267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
70119267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
7012f0d1cf93SDouglas Gilbert 	 */
70139267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
70149267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
70159267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
70169267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
70179267e0ebSDouglas Gilbert 		if (k < 0) {
70189267e0ebSDouglas Gilbert 			ret = k;
70193b01d7eaSDinghao Liu 			goto free_q_arr;
70209267e0ebSDouglas Gilbert 		}
70219267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
70229267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
70239267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
702464e14eceSDamien Le Moal 		case BLK_ZONED_HA:
70259267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
70269267e0ebSDouglas Gilbert 			break;
70279267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
70289267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
70299267e0ebSDouglas Gilbert 			break;
70309267e0ebSDouglas Gilbert 		default:
70319267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
70323b01d7eaSDinghao Liu 			ret = -EINVAL;
70333b01d7eaSDinghao Liu 			goto free_q_arr;
70349267e0ebSDouglas Gilbert 		}
70359267e0ebSDouglas Gilbert 	}
70369267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
7037f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
70389267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70399267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
70409267e0ebSDouglas Gilbert 	}
7041f0d1cf93SDouglas Gilbert 
70429267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70439267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
7044773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
7045773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
7046773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
7047773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
704828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
70491da177e4SLinus Torvalds 
70501da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
70511da177e4SLinus Torvalds 	sdebug_heads = 8;
70521da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
7053773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
70541da177e4SLinus Torvalds 		sdebug_heads = 64;
7055773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
7056fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
70571da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70581da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70591da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
70601da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
70611da177e4SLinus Torvalds 		sdebug_heads = 255;
70621da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
70631da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70641da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70651da177e4SLinus Torvalds 	}
70665b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
7067773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
7068773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
70696014759cSMartin K. Petersen 
7070773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
7071773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
70726014759cSMartin K. Petersen 
7073773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
7074773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
70756014759cSMartin K. Petersen 
7076773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
7077773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
7078773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
7079c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
7080c4837394SDouglas Gilbert 			ret = -EINVAL;
708187c715dcSDouglas Gilbert 			goto free_q_arr;
708244d92694SMartin K. Petersen 		}
708344d92694SMartin K. Petersen 	}
708487c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
708587c715dcSDouglas Gilbert 	if (want_store) {
708687c715dcSDouglas Gilbert 		idx = sdebug_add_store();
708787c715dcSDouglas Gilbert 		if (idx < 0) {
708887c715dcSDouglas Gilbert 			ret = idx;
708987c715dcSDouglas Gilbert 			goto free_q_arr;
709087c715dcSDouglas Gilbert 		}
709144d92694SMartin K. Petersen 	}
709244d92694SMartin K. Petersen 
70939b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
70949b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
7095c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
70969b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
70976ecaff7fSRandy Dunlap 		goto free_vm;
70986ecaff7fSRandy Dunlap 	}
70996ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
71006ecaff7fSRandy Dunlap 	if (ret < 0) {
7101c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
71026ecaff7fSRandy Dunlap 		goto dev_unreg;
71036ecaff7fSRandy Dunlap 	}
71046ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
71056ecaff7fSRandy Dunlap 	if (ret < 0) {
7106c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
71076ecaff7fSRandy Dunlap 		goto bus_unreg;
71086ecaff7fSRandy Dunlap 	}
71091da177e4SLinus Torvalds 
711087c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
7111773642d9SDouglas Gilbert 	sdebug_add_host = 0;
71121da177e4SLinus Torvalds 
711387c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
711487c715dcSDouglas Gilbert 		if (want_store && k == 0) {
711587c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
711687c715dcSDouglas Gilbert 			if (ret < 0) {
711787c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
711887c715dcSDouglas Gilbert 				       k, -ret);
711987c715dcSDouglas Gilbert 				break;
712087c715dcSDouglas Gilbert 			}
712187c715dcSDouglas Gilbert 		} else {
712287c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
712387c715dcSDouglas Gilbert 						 sdebug_per_host_store);
712487c715dcSDouglas Gilbert 			if (ret < 0) {
712587c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
71261da177e4SLinus Torvalds 				break;
71271da177e4SLinus Torvalds 			}
71281da177e4SLinus Torvalds 		}
712987c715dcSDouglas Gilbert 	}
7130773642d9SDouglas Gilbert 	if (sdebug_verbose)
7131f19fe8f3SBart Van Assche 		pr_info("built %d host(s)\n", sdebug_num_hosts);
7132c1287970STomas Winkler 
71331da177e4SLinus Torvalds 	return 0;
71346ecaff7fSRandy Dunlap 
71356ecaff7fSRandy Dunlap bus_unreg:
71366ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
71376ecaff7fSRandy Dunlap dev_unreg:
71389b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71396ecaff7fSRandy Dunlap free_vm:
714087c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
7141c4837394SDouglas Gilbert free_q_arr:
7142c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
71436ecaff7fSRandy Dunlap 	return ret;
71441da177e4SLinus Torvalds }
71451da177e4SLinus Torvalds 
71461da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
71471da177e4SLinus Torvalds {
7148f19fe8f3SBart Van Assche 	int k = sdebug_num_hosts;
71491da177e4SLinus Torvalds 
7150f19fe8f3SBart Van Assche 	stop_all_queued();
7151f19fe8f3SBart Van Assche 	for (; k; k--)
715287c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
715352ab9768SLuis Henriques 	free_all_queued();
71541da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
71551da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
71569b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71571da177e4SLinus Torvalds 
715887c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
715987c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
7160f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
71611da177e4SLinus Torvalds }
71621da177e4SLinus Torvalds 
71631da177e4SLinus Torvalds device_initcall(scsi_debug_init);
71641da177e4SLinus Torvalds module_exit(scsi_debug_exit);
71651da177e4SLinus Torvalds 
71661da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
71671da177e4SLinus Torvalds {
71681da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71691da177e4SLinus Torvalds 
71701da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
71711da177e4SLinus Torvalds 	kfree(sdbg_host);
71721da177e4SLinus Torvalds }
71731da177e4SLinus Torvalds 
717487c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
717587c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
71761da177e4SLinus Torvalds {
717787c715dcSDouglas Gilbert 	if (idx < 0)
717887c715dcSDouglas Gilbert 		return;
717987c715dcSDouglas Gilbert 	if (!sip) {
718087c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
718187c715dcSDouglas Gilbert 			return;
718287c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
718387c715dcSDouglas Gilbert 		if (!sip)
718487c715dcSDouglas Gilbert 			return;
718587c715dcSDouglas Gilbert 	}
718687c715dcSDouglas Gilbert 	vfree(sip->map_storep);
718787c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
718887c715dcSDouglas Gilbert 	vfree(sip->storep);
718987c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
719087c715dcSDouglas Gilbert 	kfree(sip);
719187c715dcSDouglas Gilbert }
719287c715dcSDouglas Gilbert 
719387c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
719487c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
719587c715dcSDouglas Gilbert {
719687c715dcSDouglas Gilbert 	unsigned long idx;
719787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
719887c715dcSDouglas Gilbert 
719987c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
720087c715dcSDouglas Gilbert 		if (apart_from_first)
720187c715dcSDouglas Gilbert 			apart_from_first = false;
720287c715dcSDouglas Gilbert 		else
720387c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
720487c715dcSDouglas Gilbert 	}
720587c715dcSDouglas Gilbert 	if (apart_from_first)
720687c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
720787c715dcSDouglas Gilbert }
720887c715dcSDouglas Gilbert 
720987c715dcSDouglas Gilbert /*
721087c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
721187c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
721287c715dcSDouglas Gilbert  */
721387c715dcSDouglas Gilbert static int sdebug_add_store(void)
721487c715dcSDouglas Gilbert {
721587c715dcSDouglas Gilbert 	int res;
721687c715dcSDouglas Gilbert 	u32 n_idx;
721787c715dcSDouglas Gilbert 	unsigned long iflags;
721887c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
721987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
722087c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
722187c715dcSDouglas Gilbert 
722287c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
722387c715dcSDouglas Gilbert 	if (!sip)
722487c715dcSDouglas Gilbert 		return -ENOMEM;
722587c715dcSDouglas Gilbert 
722687c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
722787c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
722887c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
722987c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
723087c715dcSDouglas Gilbert 		kfree(sip);
723187c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
723287c715dcSDouglas Gilbert 		return res;
723387c715dcSDouglas Gilbert 	}
723487c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
723587c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
723687c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
723787c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
723887c715dcSDouglas Gilbert 
723987c715dcSDouglas Gilbert 	res = -ENOMEM;
724087c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
724187c715dcSDouglas Gilbert 	if (!sip->storep) {
724287c715dcSDouglas Gilbert 		pr_err("user data oom\n");
724387c715dcSDouglas Gilbert 		goto err;
724487c715dcSDouglas Gilbert 	}
724587c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
724687c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
724787c715dcSDouglas Gilbert 
724887c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
724987c715dcSDouglas Gilbert 	if (sdebug_dix) {
725087c715dcSDouglas Gilbert 		int dif_size;
725187c715dcSDouglas Gilbert 
725287c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
725387c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
725487c715dcSDouglas Gilbert 
725587c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
725687c715dcSDouglas Gilbert 			sip->dif_storep);
725787c715dcSDouglas Gilbert 
725887c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
725987c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
726087c715dcSDouglas Gilbert 			goto err;
726187c715dcSDouglas Gilbert 		}
726287c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
726387c715dcSDouglas Gilbert 	}
726487c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
726587c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
726687c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
726787c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
726887c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
726987c715dcSDouglas Gilbert 
727087c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
727187c715dcSDouglas Gilbert 
727287c715dcSDouglas Gilbert 		if (!sip->map_storep) {
727387c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
727487c715dcSDouglas Gilbert 			goto err;
727587c715dcSDouglas Gilbert 		}
727687c715dcSDouglas Gilbert 
727787c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
727887c715dcSDouglas Gilbert 
727987c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
728087c715dcSDouglas Gilbert 		if (sdebug_num_parts)
728187c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
728287c715dcSDouglas Gilbert 	}
728387c715dcSDouglas Gilbert 
728487c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
728587c715dcSDouglas Gilbert 	return (int)n_idx;
728687c715dcSDouglas Gilbert err:
728787c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
728887c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
728987c715dcSDouglas Gilbert 	return res;
729087c715dcSDouglas Gilbert }
729187c715dcSDouglas Gilbert 
729287c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
729387c715dcSDouglas Gilbert {
729487c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
729587c715dcSDouglas Gilbert 	int error = -ENOMEM;
72961da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72978b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
72981da177e4SLinus Torvalds 
729924669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
730087c715dcSDouglas Gilbert 	if (!sdbg_host)
73011da177e4SLinus Torvalds 		return -ENOMEM;
730287c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
730387c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
730487c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
730587c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
73061da177e4SLinus Torvalds 
73071da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
73081da177e4SLinus Torvalds 
7309773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
73101da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
73115cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
731287c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
73131da177e4SLinus Torvalds 			goto clean;
73141da177e4SLinus Torvalds 	}
73151da177e4SLinus Torvalds 
73161da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73171da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
73181da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73191da177e4SLinus Torvalds 
73201da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
73219b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
73221da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
7323f19fe8f3SBart Van Assche 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
73241da177e4SLinus Torvalds 
73251da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
7326*e208a1d7SYuan Can 	if (error) {
7327*e208a1d7SYuan Can 		spin_lock(&sdebug_host_list_lock);
7328*e208a1d7SYuan Can 		list_del(&sdbg_host->host_list);
7329*e208a1d7SYuan Can 		spin_unlock(&sdebug_host_list_lock);
73301da177e4SLinus Torvalds 		goto clean;
7331*e208a1d7SYuan Can 	}
73321da177e4SLinus Torvalds 
7333f19fe8f3SBart Van Assche 	++sdebug_num_hosts;
733487c715dcSDouglas Gilbert 	return 0;
73351da177e4SLinus Torvalds 
73361da177e4SLinus Torvalds clean:
73378b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73388b40228fSFUJITA Tomonori 				 dev_list) {
73391da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7340f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73411da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73421da177e4SLinus Torvalds 	}
73431da177e4SLinus Torvalds 	kfree(sdbg_host);
734487c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
73451da177e4SLinus Torvalds 	return error;
73461da177e4SLinus Torvalds }
73471da177e4SLinus Torvalds 
734887c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
73491da177e4SLinus Torvalds {
735087c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
735187c715dcSDouglas Gilbert 
735287c715dcSDouglas Gilbert 	if (mk_new_store) {
735387c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
735487c715dcSDouglas Gilbert 		if (ph_idx < 0)
735587c715dcSDouglas Gilbert 			return ph_idx;
735687c715dcSDouglas Gilbert 	}
735787c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
735887c715dcSDouglas Gilbert }
735987c715dcSDouglas Gilbert 
736087c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
736187c715dcSDouglas Gilbert {
736287c715dcSDouglas Gilbert 	int idx = -1;
73631da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
736487c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
73651da177e4SLinus Torvalds 
73661da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73671da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
73681da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
73691da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
737087c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
73711da177e4SLinus Torvalds 	}
737287c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
737387c715dcSDouglas Gilbert 		bool unique = true;
737487c715dcSDouglas Gilbert 
737587c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
737687c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
737787c715dcSDouglas Gilbert 				continue;
737887c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
737987c715dcSDouglas Gilbert 				unique = false;
738087c715dcSDouglas Gilbert 				break;
738187c715dcSDouglas Gilbert 			}
738287c715dcSDouglas Gilbert 		}
738387c715dcSDouglas Gilbert 		if (unique) {
738487c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
738587c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
738687c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
738787c715dcSDouglas Gilbert 		}
738887c715dcSDouglas Gilbert 	}
738987c715dcSDouglas Gilbert 	if (sdbg_host)
739087c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
73911da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73921da177e4SLinus Torvalds 
73931da177e4SLinus Torvalds 	if (!sdbg_host)
73941da177e4SLinus Torvalds 		return;
73951da177e4SLinus Torvalds 
73961da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
7397f19fe8f3SBart Van Assche 	--sdebug_num_hosts;
73981da177e4SLinus Torvalds }
73991da177e4SLinus Torvalds 
7400fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7401cbf67842SDouglas Gilbert {
7402cbf67842SDouglas Gilbert 	int num_in_q = 0;
7403cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7404cbf67842SDouglas Gilbert 
7405f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
7406cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7407cbf67842SDouglas Gilbert 	if (NULL == devip) {
7408f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
7409cbf67842SDouglas Gilbert 		return	-ENODEV;
7410cbf67842SDouglas Gilbert 	}
7411cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7412c40ecc12SChristoph Hellwig 
7413fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7414fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7415fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7416fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7417fc09acb7SDouglas Gilbert 	}
7418cbf67842SDouglas Gilbert 	if (qdepth < 1)
7419cbf67842SDouglas Gilbert 		qdepth = 1;
7420fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7421db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7422cbf67842SDouglas Gilbert 
7423773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7424c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7425c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7426cbf67842SDouglas Gilbert 	}
7427f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
7428cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7429cbf67842SDouglas Gilbert }
7430cbf67842SDouglas Gilbert 
7431c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7432817fd66bSDouglas Gilbert {
7433c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7434773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7435773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7436773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7437c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7438773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7439817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7440c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7441817fd66bSDouglas Gilbert 	}
7442c4837394SDouglas Gilbert 	return false;
7443817fd66bSDouglas Gilbert }
7444817fd66bSDouglas Gilbert 
7445fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7446fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7447fc13638aSDouglas Gilbert {
7448fc13638aSDouglas Gilbert 	int stopped_state;
7449fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7450fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7451fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7452fc13638aSDouglas Gilbert 
7453fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7454fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7455fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7456fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7457fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7458fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7459fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7460fc13638aSDouglas Gilbert 				return 0;
7461fc13638aSDouglas Gilbert 			}
7462fc13638aSDouglas Gilbert 		}
7463fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7464fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7465fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7466fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7467fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7468fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7469fc13638aSDouglas Gilbert 
7470fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7471fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7472fc13638aSDouglas Gilbert 			else
7473fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7474fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7475fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7476fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7477fc13638aSDouglas Gilbert 						   diff_ns);
7478fc13638aSDouglas Gilbert 			return check_condition_result;
7479fc13638aSDouglas Gilbert 		}
7480fc13638aSDouglas Gilbert 	}
7481fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7482fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7483fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7484fc13638aSDouglas Gilbert 			    my_name);
7485fc13638aSDouglas Gilbert 	return check_condition_result;
7486fc13638aSDouglas Gilbert }
7487fc13638aSDouglas Gilbert 
7488a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost)
7489c4b57d89SKashyap Desai {
7490c4b57d89SKashyap Desai 	int i, qoff;
7491c4b57d89SKashyap Desai 
7492c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7493a4e1d0b7SBart Van Assche 		return;
7494c4b57d89SKashyap Desai 
7495c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7496c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7497c4b57d89SKashyap Desai 
7498c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7499c4b57d89SKashyap Desai 
7500c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7501c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7502c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7503c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7504c4b57d89SKashyap Desai 
7505c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7506c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7507c4b57d89SKashyap Desai 			continue;
7508c4b57d89SKashyap Desai 		}
7509c4b57d89SKashyap Desai 
7510c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7511c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7512c4b57d89SKashyap Desai 
7513c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7514c4b57d89SKashyap Desai 	}
7515c4b57d89SKashyap Desai }
7516c4b57d89SKashyap Desai 
7517c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7518c4b57d89SKashyap Desai {
75194a0c6f43SDouglas Gilbert 	bool first;
75204a0c6f43SDouglas Gilbert 	bool retiring = false;
75214a0c6f43SDouglas Gilbert 	int num_entries = 0;
75224a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7523c4b57d89SKashyap Desai 	unsigned long iflags;
75244a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7525c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7526c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7527c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7528c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
75294a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7530c4b57d89SKashyap Desai 
7531c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
75324a0c6f43SDouglas Gilbert 
7533c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
75344a0c6f43SDouglas Gilbert 
75356a0d0ae3SDamien Le Moal 	qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
75366a0d0ae3SDamien Le Moal 	if (qc_idx >= sdebug_max_queue)
75376a0d0ae3SDamien Le Moal 		goto unlock;
75386a0d0ae3SDamien Le Moal 
75394a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
75404a0c6f43SDouglas Gilbert 		if (first) {
75414a0c6f43SDouglas Gilbert 			first = false;
7542b05d4e48SDouglas Gilbert 			if (!test_bit(qc_idx, sqp->in_use_bm))
7543b05d4e48SDouglas Gilbert 				continue;
75444a0c6f43SDouglas Gilbert 		} else {
75454a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
75464a0c6f43SDouglas Gilbert 		}
7547b05d4e48SDouglas Gilbert 		if (qc_idx >= sdebug_max_queue)
75484a0c6f43SDouglas Gilbert 			break;
7549c4b57d89SKashyap Desai 
7550c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
75514a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
75524a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
75534a0c6f43SDouglas Gilbert 			continue;
7554c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7555c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
75564a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7557c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
75584a0c6f43SDouglas Gilbert 			break;
7559c4b57d89SKashyap Desai 		}
7560d9d23a5aSDouglas Gilbert 		if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) {
75614a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
75624a0c6f43SDouglas Gilbert 				continue;
75634a0c6f43SDouglas Gilbert 
75646ce913feSChristoph Hellwig 		} else		/* ignoring non REQ_POLLED requests */
75654a0c6f43SDouglas Gilbert 			continue;
7566c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7567c4b57d89SKashyap Desai 		if (likely(devip))
7568c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7569c4b57d89SKashyap Desai 		else
7570c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7571c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
75724a0c6f43SDouglas Gilbert 			retiring = true;
7573c4b57d89SKashyap Desai 
7574c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7575c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
75764a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7577c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
75784a0c6f43SDouglas Gilbert 			break;
7579c4b57d89SKashyap Desai 		}
7580c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7581c4b57d89SKashyap Desai 			int k, retval;
7582c4b57d89SKashyap Desai 
7583c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7584c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7585c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
75864a0c6f43SDouglas Gilbert 				break;
7587c4b57d89SKashyap Desai 			}
7588c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7589c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7590c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7591c4b57d89SKashyap Desai 			else
7592c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7593c4b57d89SKashyap Desai 		}
7594d9d23a5aSDouglas Gilbert 		WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
7595c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75966c2c7d6aSBart Van Assche 		scsi_done(scp); /* callback to mid level */
7597c4b57d89SKashyap Desai 		num_entries++;
75983fd07aecSDamien Le Moal 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7599b05d4e48SDouglas Gilbert 		if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue)
76003fd07aecSDamien Le Moal 			break;
76014a0c6f43SDouglas Gilbert 	}
76023fd07aecSDamien Le Moal 
76036a0d0ae3SDamien Le Moal unlock:
7604c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
76053fd07aecSDamien Le Moal 
76064a0c6f43SDouglas Gilbert 	if (num_entries > 0)
76074a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7608c4b57d89SKashyap Desai 	return num_entries;
7609c4b57d89SKashyap Desai }
7610c4b57d89SKashyap Desai 
7611fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7612fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7613c2248fc9SDouglas Gilbert {
7614c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7615c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7616c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7617c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7618c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7619c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7620c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7621f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7622c2248fc9SDouglas Gilbert 	int k, na;
7623c2248fc9SDouglas Gilbert 	int errsts = 0;
7624ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7625c2248fc9SDouglas Gilbert 	u32 flags;
7626c2248fc9SDouglas Gilbert 	u16 sa;
7627c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7628c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
76293a90a63dSDouglas Gilbert 	bool inject_now;
7630c2248fc9SDouglas Gilbert 
7631c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
76323a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7633c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
76343a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
76353a90a63dSDouglas Gilbert 	} else {
76363a90a63dSDouglas Gilbert 		inject_now = false;
76373a90a63dSDouglas Gilbert 	}
7638f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7639f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7640c2248fc9SDouglas Gilbert 		char b[120];
7641c2248fc9SDouglas Gilbert 		int n, len, sb;
7642c2248fc9SDouglas Gilbert 
7643c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7644c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7645c2248fc9SDouglas Gilbert 		if (len > 32)
7646c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7647c2248fc9SDouglas Gilbert 		else {
7648c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7649c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7650c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7651c2248fc9SDouglas Gilbert 		}
7652458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7653a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7654c2248fc9SDouglas Gilbert 	}
76553a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
76567ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
765734d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7658ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7659f46eb0e9SDouglas Gilbert 		goto err_out;
7660c2248fc9SDouglas Gilbert 
7661c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7662c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7663c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7664f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7665f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7666c2248fc9SDouglas Gilbert 		if (NULL == devip)
7667f46eb0e9SDouglas Gilbert 			goto err_out;
7668c2248fc9SDouglas Gilbert 	}
76693a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
76703a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
76713a90a63dSDouglas Gilbert 
7672c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7673c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7674c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7675c2248fc9SDouglas Gilbert 		r_oip = oip;
7676c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7677c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7678c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7679c2248fc9SDouglas Gilbert 			else
7680c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7681c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7682c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7683c2248fc9SDouglas Gilbert 					break;
7684c2248fc9SDouglas Gilbert 			}
7685c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7686c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7687c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7688c2248fc9SDouglas Gilbert 					break;
7689c2248fc9SDouglas Gilbert 			}
7690c2248fc9SDouglas Gilbert 		}
7691c2248fc9SDouglas Gilbert 		if (k > na) {
7692c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7693c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7694c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7695c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7696c2248fc9SDouglas Gilbert 			else
7697c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7698c2248fc9SDouglas Gilbert 			goto check_cond;
7699c2248fc9SDouglas Gilbert 		}
7700c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7701c2248fc9SDouglas Gilbert 	flags = oip->flags;
7702f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7703c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7704c2248fc9SDouglas Gilbert 		goto check_cond;
7705c2248fc9SDouglas Gilbert 	}
7706f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7707773642d9SDouglas Gilbert 		if (sdebug_verbose)
7708773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7709773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7710c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7711c2248fc9SDouglas Gilbert 		goto check_cond;
7712c2248fc9SDouglas Gilbert 	}
7713f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7714c2248fc9SDouglas Gilbert 		u8 rem;
7715c2248fc9SDouglas Gilbert 		int j;
7716c2248fc9SDouglas Gilbert 
7717c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7718c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7719c2248fc9SDouglas Gilbert 			if (rem) {
7720c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7721c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7722c2248fc9SDouglas Gilbert 						break;
7723c2248fc9SDouglas Gilbert 				}
7724c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7725c2248fc9SDouglas Gilbert 				goto check_cond;
7726c2248fc9SDouglas Gilbert 			}
7727c2248fc9SDouglas Gilbert 		}
7728c2248fc9SDouglas Gilbert 	}
7729f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7730b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7731b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7732f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7733c2248fc9SDouglas Gilbert 		if (errsts)
7734c2248fc9SDouglas Gilbert 			goto check_cond;
7735c2248fc9SDouglas Gilbert 	}
7736fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7737fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7738fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7739fc13638aSDouglas Gilbert 		if (errsts)
7740c2248fc9SDouglas Gilbert 			goto fini;
7741c2248fc9SDouglas Gilbert 	}
7742773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7743c2248fc9SDouglas Gilbert 		goto fini;
7744f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7745c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7746c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7747c2248fc9SDouglas Gilbert 	}
7748f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7749f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7750f66b8517SMartin Wilck 	else
7751f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7752c2248fc9SDouglas Gilbert 
7753c2248fc9SDouglas Gilbert fini:
775467da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7755f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
775675aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
775775aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
775880c49563SDouglas Gilbert 		/*
775975aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
776075aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
776175aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
776275aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
776380c49563SDouglas Gilbert 		 */
776480c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
77654f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
776680c49563SDouglas Gilbert 
77674f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7768f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
776980c49563SDouglas Gilbert 	} else
7770f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
777110bde980SDouglas Gilbert 				     sdebug_ndelay);
7772c2248fc9SDouglas Gilbert check_cond:
7773f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7774f46eb0e9SDouglas Gilbert err_out:
7775f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7776c2248fc9SDouglas Gilbert }
7777c2248fc9SDouglas Gilbert 
77789e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7779c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7780c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
77819e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
77829e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
77839e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
77849e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
77859e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
77869e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
77879e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7788185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7789cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7790c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7791c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
77929e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
77939e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7794cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7795cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
77969e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7797c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
77989e603ca0SFUJITA Tomonori 	.this_id =		7,
779965e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7800cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
78016bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
780250c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
78039e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7804c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
78059e603ca0SFUJITA Tomonori };
78069e603ca0SFUJITA Tomonori 
78071da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
78081da177e4SLinus Torvalds {
78091da177e4SLinus Torvalds 	int error = 0;
78101da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
78111da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7812f46eb0e9SDouglas Gilbert 	int hprot;
78131da177e4SLinus Torvalds 
78141da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
78151da177e4SLinus Torvalds 
7816773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7817fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
78182a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
78194af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
78204af14d11SChristoph Hellwig 
78211da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
78221da177e4SLinus Torvalds 	if (NULL == hpnt) {
7823c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
78241da177e4SLinus Torvalds 		error = -ENODEV;
78251da177e4SLinus Torvalds 		return error;
78261da177e4SLinus Torvalds 	}
7827c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
78289b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7829c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7830c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7831c4837394SDouglas Gilbert 	}
7832c10fa55fSJohn Garry 	/*
7833c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7834f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7835c10fa55fSJohn Garry 	 */
7836c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7837f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7838f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
78391da177e4SLinus Torvalds 
7840c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7841c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7842c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7843c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7844c4b57d89SKashyap Desai 		poll_queues = 0;
7845c4b57d89SKashyap Desai 	}
7846c4b57d89SKashyap Desai 
7847c4b57d89SKashyap Desai 	/*
7848c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7849c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7850c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7851c4b57d89SKashyap Desai 	 */
7852c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7853fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7854c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7855fc09acb7SDouglas Gilbert 		else
7856fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7857fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7858c4b57d89SKashyap Desai 		poll_queues = 1;
7859c4b57d89SKashyap Desai 	}
7860c4b57d89SKashyap Desai 	if (poll_queues)
7861c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7862c4b57d89SKashyap Desai 
78631da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
78641da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7865773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7866773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
78671da177e4SLinus Torvalds 	else
7868773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7869773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7870f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
78711da177e4SLinus Torvalds 
7872f46eb0e9SDouglas Gilbert 	hprot = 0;
7873c6a44287SMartin K. Petersen 
7874773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7875c6a44287SMartin K. Petersen 
78768475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7877f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7878773642d9SDouglas Gilbert 		if (sdebug_dix)
7879f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7880c6a44287SMartin K. Petersen 		break;
7881c6a44287SMartin K. Petersen 
78828475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7883f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7884773642d9SDouglas Gilbert 		if (sdebug_dix)
7885f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7886c6a44287SMartin K. Petersen 		break;
7887c6a44287SMartin K. Petersen 
78888475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7889f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7890773642d9SDouglas Gilbert 		if (sdebug_dix)
7891f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7892c6a44287SMartin K. Petersen 		break;
7893c6a44287SMartin K. Petersen 
7894c6a44287SMartin K. Petersen 	default:
7895773642d9SDouglas Gilbert 		if (sdebug_dix)
7896f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7897c6a44287SMartin K. Petersen 		break;
7898c6a44287SMartin K. Petersen 	}
7899c6a44287SMartin K. Petersen 
7900f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7901c6a44287SMartin K. Petersen 
7902f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7903c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7904f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7905f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7906f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7907f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7908f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7909f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7910f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7911c6a44287SMartin K. Petersen 
7912773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7913c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7914c6a44287SMartin K. Petersen 	else
7915c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7916c6a44287SMartin K. Petersen 
7917773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7918773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7919c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7920c4837394SDouglas Gilbert 		sdebug_statistics = true;
79211da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
79221da177e4SLinus Torvalds 	if (error) {
7923c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
79241da177e4SLinus Torvalds 		error = -ENODEV;
79251da177e4SLinus Torvalds 		scsi_host_put(hpnt);
792687c715dcSDouglas Gilbert 	} else {
79271da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
792887c715dcSDouglas Gilbert 	}
79291da177e4SLinus Torvalds 
79301da177e4SLinus Torvalds 	return error;
79311da177e4SLinus Torvalds }
79321da177e4SLinus Torvalds 
7933fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
79341da177e4SLinus Torvalds {
79351da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
79368b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
79371da177e4SLinus Torvalds 
79381da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
79391da177e4SLinus Torvalds 
79401da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
79411da177e4SLinus Torvalds 
79428b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
79438b40228fSFUJITA Tomonori 				 dev_list) {
79441da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7945f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
79461da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
79471da177e4SLinus Torvalds 	}
79481da177e4SLinus Torvalds 
79491da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
79501da177e4SLinus Torvalds }
79511da177e4SLinus Torvalds 
79528dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
79538dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
79541da177e4SLinus Torvalds {
79558dea0d02SFUJITA Tomonori 	return 1;
79568dea0d02SFUJITA Tomonori }
79571da177e4SLinus Torvalds 
79588dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
79598dea0d02SFUJITA Tomonori 	.name = "pseudo",
79608dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
79618dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
79628dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
796382069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
79648dea0d02SFUJITA Tomonori };
7965