xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 07f2ca13)
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 
1902773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1903c6a44287SMartin K. Petersen 
1904760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1905773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1906c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1907c6a44287SMartin K. Petersen 	}
1908c6a44287SMartin K. Petersen 
1909c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
19104e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1911c65b1445SDouglas Gilbert }
1912c65b1445SDouglas Gilbert 
19135a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19145a09e398SHannes Reinecke 
19155a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19165a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19175a09e398SHannes Reinecke {
191801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19195a09e398SHannes Reinecke 	unsigned char *arr;
19205a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19215a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1922f347c268SYe Bin 	u32 alen, n, rlen;
1923f347c268SYe Bin 	int ret;
19245a09e398SHannes Reinecke 
1925773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19266f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19276f3cbf55SDouglas Gilbert 	if (! arr)
19286f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19295a09e398SHannes Reinecke 	/*
19305a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19315a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19325a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19335a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19345a09e398SHannes Reinecke 	 */
19355a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19365a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19375a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19385a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19395a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19405a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19415a09e398SHannes Reinecke 
19425a09e398SHannes Reinecke 	/*
19435a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19445a09e398SHannes Reinecke 	 */
19455a09e398SHannes Reinecke 	n = 4;
1946b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19475a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19485a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19495a09e398SHannes Reinecke 	} else {
19505a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1951773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19525a09e398SHannes Reinecke 	}
1953773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1954773642d9SDouglas Gilbert 	n += 2;
19555a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19565a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19575a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19585a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19595a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19605a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1961773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1962773642d9SDouglas Gilbert 	n += 2;
19635a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19645a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1965773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1966773642d9SDouglas Gilbert 	n += 2;
19675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19685a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19695a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19705a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19715a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19725a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1973773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1974773642d9SDouglas Gilbert 	n += 2;
19755a09e398SHannes Reinecke 
19765a09e398SHannes Reinecke 	rlen = n - 4;
1977773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19785a09e398SHannes Reinecke 
19795a09e398SHannes Reinecke 	/*
19805a09e398SHannes Reinecke 	 * Return the smallest value of either
19815a09e398SHannes Reinecke 	 * - The allocated length
19825a09e398SHannes Reinecke 	 * - The constructed command length
19835a09e398SHannes Reinecke 	 * - The maximum array size
19845a09e398SHannes Reinecke 	 */
1985f347c268SYe Bin 	rlen = min(alen, n);
19865a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1987f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19885a09e398SHannes Reinecke 	kfree(arr);
19895a09e398SHannes Reinecke 	return ret;
19905a09e398SHannes Reinecke }
19915a09e398SHannes Reinecke 
1992fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1993fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
199438d5c833SDouglas Gilbert {
199538d5c833SDouglas Gilbert 	bool rctd;
199638d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
199738d5c833SDouglas Gilbert 	u16 req_sa, u;
199838d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
199938d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
200038d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
200138d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
200238d5c833SDouglas Gilbert 	u8 *arr;
200338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
200438d5c833SDouglas Gilbert 
200538d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
200638d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
200738d5c833SDouglas Gilbert 	req_opcode = cmd[3];
200838d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
200938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
20106d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
201138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
201238d5c833SDouglas Gilbert 		return check_condition_result;
201338d5c833SDouglas Gilbert 	}
201438d5c833SDouglas Gilbert 	if (alloc_len > 8192)
201538d5c833SDouglas Gilbert 		a_len = 8192;
201638d5c833SDouglas Gilbert 	else
201738d5c833SDouglas Gilbert 		a_len = alloc_len;
201899531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
201938d5c833SDouglas Gilbert 	if (NULL == arr) {
202038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
202138d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
202238d5c833SDouglas Gilbert 		return check_condition_result;
202338d5c833SDouglas Gilbert 	}
202438d5c833SDouglas Gilbert 	switch (reporting_opts) {
202538d5c833SDouglas Gilbert 	case 0:	/* all commands */
202638d5c833SDouglas Gilbert 		/* count number of commands */
202738d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
202838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
202938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
203038d5c833SDouglas Gilbert 				continue;
203138d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
203238d5c833SDouglas Gilbert 		}
203338d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
203438d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
203538d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
203638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
203738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
203838d5c833SDouglas Gilbert 				continue;
203938d5c833SDouglas Gilbert 			na = oip->num_attached;
204038d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
204138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
204238d5c833SDouglas Gilbert 			if (rctd)
204338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
204438d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
204538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
204638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
204738d5c833SDouglas Gilbert 			if (rctd)
204838d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
204938d5c833SDouglas Gilbert 			r_oip = oip;
205038d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
205138d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
205238d5c833SDouglas Gilbert 					continue;
205338d5c833SDouglas Gilbert 				offset += bump;
205438d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
205538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
205638d5c833SDouglas Gilbert 				if (rctd)
205738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
205838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
205938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
206038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
206138d5c833SDouglas Gilbert 						   arr + offset + 6);
206238d5c833SDouglas Gilbert 				if (rctd)
206338d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
206438d5c833SDouglas Gilbert 							   arr + offset + 8);
206538d5c833SDouglas Gilbert 			}
206638d5c833SDouglas Gilbert 			oip = r_oip;
206738d5c833SDouglas Gilbert 			offset += bump;
206838d5c833SDouglas Gilbert 		}
206938d5c833SDouglas Gilbert 		break;
207038d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
207138d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
207238d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
207338d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
207438d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
207538d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
207638d5c833SDouglas Gilbert 			supp = 1;
207738d5c833SDouglas Gilbert 			offset = 4;
207838d5c833SDouglas Gilbert 		} else {
207938d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
208038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
208138d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
208238d5c833SDouglas Gilbert 							     2, 2);
208338d5c833SDouglas Gilbert 					kfree(arr);
208438d5c833SDouglas Gilbert 					return check_condition_result;
208538d5c833SDouglas Gilbert 				}
208638d5c833SDouglas Gilbert 				req_sa = 0;
208738d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
208838d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
208938d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
209038d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
209138d5c833SDouglas Gilbert 				return check_condition_result;
209238d5c833SDouglas Gilbert 			}
209338d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
209438d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
209538d5c833SDouglas Gilbert 				supp = 3;
209638d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
209738d5c833SDouglas Gilbert 				na = oip->num_attached;
209838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
209938d5c833SDouglas Gilbert 				     ++k, ++oip) {
210038d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
210138d5c833SDouglas Gilbert 						break;
210238d5c833SDouglas Gilbert 				}
210338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
210438d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
210538d5c833SDouglas Gilbert 				na = oip->num_attached;
210638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
210738d5c833SDouglas Gilbert 				     ++k, ++oip) {
210838d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
210938d5c833SDouglas Gilbert 						break;
211038d5c833SDouglas Gilbert 				}
211138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
211238d5c833SDouglas Gilbert 			} else
211338d5c833SDouglas Gilbert 				supp = 3;
211438d5c833SDouglas Gilbert 			if (3 == supp) {
211538d5c833SDouglas Gilbert 				u = oip->len_mask[0];
211638d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
211738d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
211838d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
211938d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
212038d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
212138d5c833SDouglas Gilbert 				offset = 4 + u;
212238d5c833SDouglas Gilbert 			} else
212338d5c833SDouglas Gilbert 				offset = 4;
212438d5c833SDouglas Gilbert 		}
212538d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
212638d5c833SDouglas Gilbert 		if (rctd) {
212738d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
212838d5c833SDouglas Gilbert 			offset += 12;
212938d5c833SDouglas Gilbert 		}
213038d5c833SDouglas Gilbert 		break;
213138d5c833SDouglas Gilbert 	default:
213238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
213338d5c833SDouglas Gilbert 		kfree(arr);
213438d5c833SDouglas Gilbert 		return check_condition_result;
213538d5c833SDouglas Gilbert 	}
213638d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
213738d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
213838d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
213938d5c833SDouglas Gilbert 	kfree(arr);
214038d5c833SDouglas Gilbert 	return errsts;
214138d5c833SDouglas Gilbert }
214238d5c833SDouglas Gilbert 
2143fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2144fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
214538d5c833SDouglas Gilbert {
214638d5c833SDouglas Gilbert 	bool repd;
214738d5c833SDouglas Gilbert 	u32 alloc_len, len;
214838d5c833SDouglas Gilbert 	u8 arr[16];
214938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
215038d5c833SDouglas Gilbert 
215138d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
215238d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
215338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
215438d5c833SDouglas Gilbert 	if (alloc_len < 4) {
215538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
215638d5c833SDouglas Gilbert 		return check_condition_result;
215738d5c833SDouglas Gilbert 	}
215838d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
215938d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
216038d5c833SDouglas Gilbert 	if (repd) {
216138d5c833SDouglas Gilbert 		arr[3] = 0xc;
216238d5c833SDouglas Gilbert 		len = 16;
216338d5c833SDouglas Gilbert 	} else
216438d5c833SDouglas Gilbert 		len = 4;
216538d5c833SDouglas Gilbert 
216638d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
216738d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
216838d5c833SDouglas Gilbert }
216938d5c833SDouglas Gilbert 
21701da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21711da177e4SLinus Torvalds 
21721da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21731da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21741da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21751da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21761da177e4SLinus Torvalds 
21771da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21781da177e4SLinus Torvalds 	if (1 == pcontrol)
21791da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21801da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21811da177e4SLinus Torvalds }
21821da177e4SLinus Torvalds 
21831da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21841da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21851da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21861da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21871da177e4SLinus Torvalds 
21881da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21891da177e4SLinus Torvalds 	if (1 == pcontrol)
21901da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21911da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21921da177e4SLinus Torvalds }
21931da177e4SLinus Torvalds 
21941da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21951da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21961da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21971da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21981da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21991da177e4SLinus Torvalds 
22001da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2201773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2202773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2203773642d9SDouglas Gilbert 	if (sdebug_removable)
22041da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
22051da177e4SLinus Torvalds 	if (1 == pcontrol)
22061da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
22071da177e4SLinus Torvalds 	return sizeof(format_pg);
22081da177e4SLinus Torvalds }
22091da177e4SLinus Torvalds 
2210fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2211fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2212fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2213fd32119bSDouglas Gilbert 
22141da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22151da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2216cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2217cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2218cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22191da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22201da177e4SLinus Torvalds 
2221773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2222cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22231da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22241da177e4SLinus Torvalds 	if (1 == pcontrol)
2225cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2226cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2227cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22281da177e4SLinus Torvalds 	return sizeof(caching_pg);
22291da177e4SLinus Torvalds }
22301da177e4SLinus Torvalds 
2231fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2232fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2233fd32119bSDouglas Gilbert 
22341da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22351da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2236c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2237c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2238c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22391da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22401da177e4SLinus Torvalds 
2241773642d9SDouglas Gilbert 	if (sdebug_dsense)
22421da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2243c65b1445SDouglas Gilbert 	else
2244c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2245c6a44287SMartin K. Petersen 
2246773642d9SDouglas Gilbert 	if (sdebug_ato)
2247c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2248c6a44287SMartin K. Petersen 
22491da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22501da177e4SLinus Torvalds 	if (1 == pcontrol)
2251c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2252c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2253c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22541da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22551da177e4SLinus Torvalds }
22561da177e4SLinus Torvalds 
2257c65b1445SDouglas Gilbert 
22581da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22591da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2260c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22611da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2262c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2263c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2264c65b1445SDouglas Gilbert 
22651da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22661da177e4SLinus Torvalds 	if (1 == pcontrol)
2267c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2268c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2269c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22701da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22711da177e4SLinus Torvalds }
22721da177e4SLinus Torvalds 
2273c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2274c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2275c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2276c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2277c65b1445SDouglas Gilbert 
2278c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2279c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2280c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2281c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2282c65b1445SDouglas Gilbert }
2283c65b1445SDouglas Gilbert 
2284c65b1445SDouglas Gilbert 
2285c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2286c65b1445SDouglas Gilbert 			      int target_dev_id)
2287c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2288c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2289c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2290773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2291773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2292c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2293c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2294c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2295c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2296773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2297773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2298c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2299c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2300c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2301c65b1445SDouglas Gilbert 		};
2302c65b1445SDouglas Gilbert 	int port_a, port_b;
2303c65b1445SDouglas Gilbert 
23041b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
23051b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
23061b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
23071b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2308c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2309c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2310c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2311773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2312773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2313c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2314c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2315c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2316c65b1445SDouglas Gilbert }
2317c65b1445SDouglas Gilbert 
2318c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2319c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2320c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2321c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2322c65b1445SDouglas Gilbert 		};
2323c65b1445SDouglas Gilbert 
2324c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2325c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2326c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2327c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2328c65b1445SDouglas Gilbert }
2329c65b1445SDouglas Gilbert 
23301da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23311da177e4SLinus Torvalds 
2332fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2333fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23341da177e4SLinus Torvalds {
233523183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23361da177e4SLinus Torvalds 	unsigned char dev_spec;
233736e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
233836e07d7eSGeorge Kennedy 	int target_dev_id;
2339c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23401da177e4SLinus Torvalds 	unsigned char *ap;
23411da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
234201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2343d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23441da177e4SLinus Torvalds 
2345760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23461da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23471da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23481da177e4SLinus Torvalds 	subpcode = cmd[3];
23491da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2350760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2351760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
235264e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2353d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
235423183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
235523183910SDouglas Gilbert 	else
235623183910SDouglas Gilbert 		bd_len = 0;
2357773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23581da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23591da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2360cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23611da177e4SLinus Torvalds 		return check_condition_result;
23621da177e4SLinus Torvalds 	}
2363c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2364c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2365d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2366d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2367b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23689447b6ceSMartin K. Petersen 		if (sdebug_wp)
23699447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23709447b6ceSMartin K. Petersen 	} else
237123183910SDouglas Gilbert 		dev_spec = 0x0;
23721da177e4SLinus Torvalds 	if (msense_6) {
23731da177e4SLinus Torvalds 		arr[2] = dev_spec;
237423183910SDouglas Gilbert 		arr[3] = bd_len;
23751da177e4SLinus Torvalds 		offset = 4;
23761da177e4SLinus Torvalds 	} else {
23771da177e4SLinus Torvalds 		arr[3] = dev_spec;
237823183910SDouglas Gilbert 		if (16 == bd_len)
237923183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
238023183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23811da177e4SLinus Torvalds 		offset = 8;
23821da177e4SLinus Torvalds 	}
23831da177e4SLinus Torvalds 	ap = arr + offset;
238428898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
238528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
238628898873SFUJITA Tomonori 
238723183910SDouglas Gilbert 	if (8 == bd_len) {
2388773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2389773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2390773642d9SDouglas Gilbert 		else
2391773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2392773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
239323183910SDouglas Gilbert 		offset += bd_len;
239423183910SDouglas Gilbert 		ap = arr + offset;
239523183910SDouglas Gilbert 	} else if (16 == bd_len) {
2396773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2397773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
239823183910SDouglas Gilbert 		offset += bd_len;
239923183910SDouglas Gilbert 		ap = arr + offset;
240023183910SDouglas Gilbert 	}
24011da177e4SLinus Torvalds 
2402c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2403c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
240422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24051da177e4SLinus Torvalds 		return check_condition_result;
24061da177e4SLinus Torvalds 	}
2407760f3b03SDouglas Gilbert 	bad_pcode = false;
2408760f3b03SDouglas Gilbert 
24091da177e4SLinus Torvalds 	switch (pcode) {
24101da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
24111da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
24121da177e4SLinus Torvalds 		offset += len;
24131da177e4SLinus Torvalds 		break;
24141da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
24151da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24161da177e4SLinus Torvalds 		offset += len;
24171da177e4SLinus Torvalds 		break;
24181da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2419760f3b03SDouglas Gilbert 		if (is_disk) {
24201da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24211da177e4SLinus Torvalds 			offset += len;
2422760f3b03SDouglas Gilbert 		} else
2423760f3b03SDouglas Gilbert 			bad_pcode = true;
24241da177e4SLinus Torvalds 		break;
24251da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2426d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24271da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24281da177e4SLinus Torvalds 			offset += len;
2429760f3b03SDouglas Gilbert 		} else
2430760f3b03SDouglas Gilbert 			bad_pcode = true;
24311da177e4SLinus Torvalds 		break;
24321da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24331da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24341da177e4SLinus Torvalds 		offset += len;
24351da177e4SLinus Torvalds 		break;
2436c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2437c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
243822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2439c65b1445SDouglas Gilbert 			return check_condition_result;
2440c65b1445SDouglas Gilbert 		}
2441c65b1445SDouglas Gilbert 		len = 0;
2442c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2443c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2444c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2445c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2446c65b1445SDouglas Gilbert 						  target_dev_id);
2447c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2448c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2449c65b1445SDouglas Gilbert 		offset += len;
2450c65b1445SDouglas Gilbert 		break;
24511da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24521da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24531da177e4SLinus Torvalds 		offset += len;
24541da177e4SLinus Torvalds 		break;
24551da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2456c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24571da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24581da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2459760f3b03SDouglas Gilbert 			if (is_disk) {
2460760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2461760f3b03SDouglas Gilbert 						      target);
2462760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2463760f3b03SDouglas Gilbert 						       target);
2464d36da305SDouglas Gilbert 			} else if (is_zbc) {
2465d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2466d36da305SDouglas Gilbert 						       target);
2467760f3b03SDouglas Gilbert 			}
24681da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2469c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2470c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2471c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2472c65b1445SDouglas Gilbert 						  target, target_dev_id);
2473c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2474c65b1445SDouglas Gilbert 			}
24751da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2476760f3b03SDouglas Gilbert 			offset += len;
2477c65b1445SDouglas Gilbert 		} else {
247822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2479c65b1445SDouglas Gilbert 			return check_condition_result;
2480c65b1445SDouglas Gilbert 		}
24811da177e4SLinus Torvalds 		break;
24821da177e4SLinus Torvalds 	default:
2483760f3b03SDouglas Gilbert 		bad_pcode = true;
2484760f3b03SDouglas Gilbert 		break;
2485760f3b03SDouglas Gilbert 	}
2486760f3b03SDouglas Gilbert 	if (bad_pcode) {
248722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24881da177e4SLinus Torvalds 		return check_condition_result;
24891da177e4SLinus Torvalds 	}
24901da177e4SLinus Torvalds 	if (msense_6)
24911da177e4SLinus Torvalds 		arr[0] = offset - 1;
2492773642d9SDouglas Gilbert 	else
2493773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
249436e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
24951da177e4SLinus Torvalds }
24961da177e4SLinus Torvalds 
2497c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2498c65b1445SDouglas Gilbert 
2499fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2500fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2501c65b1445SDouglas Gilbert {
2502c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2503c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2504c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
250501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2506c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2507c65b1445SDouglas Gilbert 
2508c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2509c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2510c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2511773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2512c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
251322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2514c65b1445SDouglas Gilbert 		return check_condition_result;
2515c65b1445SDouglas Gilbert 	}
2516c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2517c65b1445SDouglas Gilbert 	if (-1 == res)
2518773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2519773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2520cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2521cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2522cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2523773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2524773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2525e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2526e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
252722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2528c65b1445SDouglas Gilbert 		return check_condition_result;
2529c65b1445SDouglas Gilbert 	}
2530c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2531c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2532c65b1445SDouglas Gilbert 	if (ps) {
253322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2534c65b1445SDouglas Gilbert 		return check_condition_result;
2535c65b1445SDouglas Gilbert 	}
2536c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2537773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2538c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2539c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2540cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2541c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2542c65b1445SDouglas Gilbert 		return check_condition_result;
2543c65b1445SDouglas Gilbert 	}
2544c65b1445SDouglas Gilbert 	switch (mpage) {
2545cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2546cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2547cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2548cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2549cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2550cbf67842SDouglas Gilbert 		}
2551cbf67842SDouglas Gilbert 		break;
2552c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2553c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2554c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2555c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25569447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25579447b6ceSMartin K. Petersen 				sdebug_wp = true;
25589447b6ceSMartin K. Petersen 			else
25599447b6ceSMartin K. Petersen 				sdebug_wp = false;
2560773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2561cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2562c65b1445SDouglas Gilbert 		}
2563c65b1445SDouglas Gilbert 		break;
2564c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2565c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2566c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2567c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2568cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2569c65b1445SDouglas Gilbert 		}
2570c65b1445SDouglas Gilbert 		break;
2571c65b1445SDouglas Gilbert 	default:
2572c65b1445SDouglas Gilbert 		break;
2573c65b1445SDouglas Gilbert 	}
257422017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2575c65b1445SDouglas Gilbert 	return check_condition_result;
2576cbf67842SDouglas Gilbert set_mode_changed_ua:
2577cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2578cbf67842SDouglas Gilbert 	return 0;
2579c65b1445SDouglas Gilbert }
2580c65b1445SDouglas Gilbert 
2581c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2582c65b1445SDouglas Gilbert {
2583c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2584c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2585c65b1445SDouglas Gilbert 		};
2586c65b1445SDouglas Gilbert 
2587c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2588c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2589c65b1445SDouglas Gilbert }
2590c65b1445SDouglas Gilbert 
2591c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2592c65b1445SDouglas Gilbert {
2593c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2594c65b1445SDouglas Gilbert 		};
2595c65b1445SDouglas Gilbert 
2596c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2597c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2598c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2599c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2600c65b1445SDouglas Gilbert 	}
2601c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2602c65b1445SDouglas Gilbert }
2603c65b1445SDouglas Gilbert 
26040790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr)
26050790797aSDouglas Gilbert {
26060790797aSDouglas Gilbert 	unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
26070790797aSDouglas Gilbert 					 0x0, 40, 72, 0xff, 45, 18, 0, 0,
26080790797aSDouglas Gilbert 					 0x1, 0x0, 0x23, 0x8,
26090790797aSDouglas Gilbert 					 0x0, 55, 72, 35, 55, 45, 0, 0,
26100790797aSDouglas Gilbert 		};
26110790797aSDouglas Gilbert 
26120790797aSDouglas Gilbert 	memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
26130790797aSDouglas Gilbert 	return sizeof(env_rep_l_spg);
26140790797aSDouglas Gilbert }
26150790797aSDouglas Gilbert 
2616c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2617c65b1445SDouglas Gilbert 
2618c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2619c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2620c65b1445SDouglas Gilbert {
262136e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
262236e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2623c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
262401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2625c65b1445SDouglas Gilbert 
2626c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2627c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2628c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2629c65b1445SDouglas Gilbert 	if (ppc || sp) {
263022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2631c65b1445SDouglas Gilbert 		return check_condition_result;
2632c65b1445SDouglas Gilbert 	}
2633c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
263423183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2635773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2636c65b1445SDouglas Gilbert 	arr[0] = pcode;
263723183910SDouglas Gilbert 	if (0 == subpcode) {
2638c65b1445SDouglas Gilbert 		switch (pcode) {
2639c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2640c65b1445SDouglas Gilbert 			n = 4;
2641c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2642c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2643c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2644c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2645c65b1445SDouglas Gilbert 			break;
2646c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2647c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2648c65b1445SDouglas Gilbert 			break;
2649c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2650c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2651c65b1445SDouglas Gilbert 			break;
2652c65b1445SDouglas Gilbert 		default:
265322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2654c65b1445SDouglas Gilbert 			return check_condition_result;
2655c65b1445SDouglas Gilbert 		}
265623183910SDouglas Gilbert 	} else if (0xff == subpcode) {
265723183910SDouglas Gilbert 		arr[0] |= 0x40;
265823183910SDouglas Gilbert 		arr[1] = subpcode;
265923183910SDouglas Gilbert 		switch (pcode) {
266023183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
266123183910SDouglas Gilbert 			n = 4;
266223183910SDouglas Gilbert 			arr[n++] = 0x0;
266323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
266423183910SDouglas Gilbert 			arr[n++] = 0x0;
266523183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
266623183910SDouglas Gilbert 			arr[n++] = 0xd;
266723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26680790797aSDouglas Gilbert 			arr[n++] = 0xd;
26690790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26700790797aSDouglas Gilbert 			arr[n++] = 0xd;
26710790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0xd subpages */
267223183910SDouglas Gilbert 			arr[n++] = 0x2f;
267323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
26740790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26750790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0x2f subpages */
267623183910SDouglas Gilbert 			arr[3] = n - 4;
267723183910SDouglas Gilbert 			break;
267823183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
267923183910SDouglas Gilbert 			n = 4;
268023183910SDouglas Gilbert 			arr[n++] = 0xd;
268123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26820790797aSDouglas Gilbert 			arr[n++] = 0xd;
26830790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26840790797aSDouglas Gilbert 			arr[n++] = 0xd;
26850790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
268623183910SDouglas Gilbert 			arr[3] = n - 4;
268723183910SDouglas Gilbert 			break;
268823183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
268923183910SDouglas Gilbert 			n = 4;
269023183910SDouglas Gilbert 			arr[n++] = 0x2f;
269123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
26920790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26930790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
269423183910SDouglas Gilbert 			arr[3] = n - 4;
269523183910SDouglas Gilbert 			break;
269623183910SDouglas Gilbert 		default:
269722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
269823183910SDouglas Gilbert 			return check_condition_result;
269923183910SDouglas Gilbert 		}
27000790797aSDouglas Gilbert 	} else if (subpcode > 0) {
27010790797aSDouglas Gilbert 		arr[0] |= 0x40;
27020790797aSDouglas Gilbert 		arr[1] = subpcode;
27030790797aSDouglas Gilbert 		if (pcode == 0xd && subpcode == 1)
27040790797aSDouglas Gilbert 			arr[3] = resp_env_rep_l_spg(arr + 4);
27050790797aSDouglas Gilbert 		else {
27060790797aSDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
27070790797aSDouglas Gilbert 			return check_condition_result;
27080790797aSDouglas Gilbert 		}
270923183910SDouglas Gilbert 	} else {
271022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
271123183910SDouglas Gilbert 		return check_condition_result;
271223183910SDouglas Gilbert 	}
271336e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2714c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
271536e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2716c65b1445SDouglas Gilbert }
2717c65b1445SDouglas Gilbert 
2718f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2719f0d1cf93SDouglas Gilbert {
2720f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2721f0d1cf93SDouglas Gilbert }
2722f0d1cf93SDouglas Gilbert 
2723f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2724f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2725f0d1cf93SDouglas Gilbert {
27264a5fc1c6SDamien Le Moal 	u32 zno = lba >> devip->zsize_shift;
27274a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp;
27284a5fc1c6SDamien Le Moal 
27294a5fc1c6SDamien Le Moal 	if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones)
27304a5fc1c6SDamien Le Moal 		return &devip->zstate[zno];
27314a5fc1c6SDamien Le Moal 
27324a5fc1c6SDamien Le Moal 	/*
27334a5fc1c6SDamien Le Moal 	 * If the zone capacity is less than the zone size, adjust for gap
27344a5fc1c6SDamien Le Moal 	 * zones.
27354a5fc1c6SDamien Le Moal 	 */
27364a5fc1c6SDamien Le Moal 	zno = 2 * zno - devip->nr_conv_zones;
27374a5fc1c6SDamien Le Moal 	WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones);
27384a5fc1c6SDamien Le Moal 	zsp = &devip->zstate[zno];
27394a5fc1c6SDamien Le Moal 	if (lba >= zsp->z_start + zsp->z_size)
27404a5fc1c6SDamien Le Moal 		zsp++;
27414a5fc1c6SDamien Le Moal 	WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size);
27424a5fc1c6SDamien Le Moal 	return zsp;
2743f0d1cf93SDouglas Gilbert }
2744f0d1cf93SDouglas Gilbert 
2745f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2746f0d1cf93SDouglas Gilbert {
274735dbe2b9SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_CNV;
2748f0d1cf93SDouglas Gilbert }
2749f0d1cf93SDouglas Gilbert 
27504a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp)
27514a5fc1c6SDamien Le Moal {
27524a5fc1c6SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_GAP;
27534a5fc1c6SDamien Le Moal }
27544a5fc1c6SDamien Le Moal 
27554a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp)
27564a5fc1c6SDamien Le Moal {
27574a5fc1c6SDamien Le Moal 	return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp);
27584a5fc1c6SDamien Le Moal }
27594a5fc1c6SDamien Le Moal 
2760f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2761f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2762f0d1cf93SDouglas Gilbert {
2763f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2764f0d1cf93SDouglas Gilbert 
27654a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2766f0d1cf93SDouglas Gilbert 		return;
2767f0d1cf93SDouglas Gilbert 
2768f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2769f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2770f0d1cf93SDouglas Gilbert 		return;
2771f0d1cf93SDouglas Gilbert 
2772f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2773f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2774f0d1cf93SDouglas Gilbert 	else
2775f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2776f0d1cf93SDouglas Gilbert 
2777f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2778f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2779f0d1cf93SDouglas Gilbert 	} else {
2780f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2781f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2782f0d1cf93SDouglas Gilbert 	}
2783f0d1cf93SDouglas Gilbert }
2784f0d1cf93SDouglas Gilbert 
2785f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2786f0d1cf93SDouglas Gilbert {
2787f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2788f0d1cf93SDouglas Gilbert 	unsigned int i;
2789f0d1cf93SDouglas Gilbert 
2790f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2791f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2792f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2793f0d1cf93SDouglas Gilbert 			return;
2794f0d1cf93SDouglas Gilbert 		}
2795f0d1cf93SDouglas Gilbert 	}
2796f0d1cf93SDouglas Gilbert }
2797f0d1cf93SDouglas Gilbert 
2798f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2799f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2800f0d1cf93SDouglas Gilbert {
2801f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2802f0d1cf93SDouglas Gilbert 
28034a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2804f0d1cf93SDouglas Gilbert 		return;
2805f0d1cf93SDouglas Gilbert 
2806f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2807f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2808f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2809f0d1cf93SDouglas Gilbert 		return;
2810f0d1cf93SDouglas Gilbert 
2811f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2812f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2813f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2814f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2815f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2816f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2817f0d1cf93SDouglas Gilbert 
2818f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2819f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2820f0d1cf93SDouglas Gilbert 	if (explicit) {
2821f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2822f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2823f0d1cf93SDouglas Gilbert 	} else {
2824f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2825f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2826f0d1cf93SDouglas Gilbert 	}
2827f0d1cf93SDouglas Gilbert }
2828f0d1cf93SDouglas Gilbert 
2829566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip,
2830566d3c57SDamien Le Moal 				     struct sdeb_zone_state *zsp)
2831566d3c57SDamien Le Moal {
2832566d3c57SDamien Le Moal 	switch (zsp->z_cond) {
2833566d3c57SDamien Le Moal 	case ZC2_IMPLICIT_OPEN:
2834566d3c57SDamien Le Moal 		devip->nr_imp_open--;
2835566d3c57SDamien Le Moal 		break;
2836566d3c57SDamien Le Moal 	case ZC3_EXPLICIT_OPEN:
2837566d3c57SDamien Le Moal 		devip->nr_exp_open--;
2838566d3c57SDamien Le Moal 		break;
2839566d3c57SDamien Le Moal 	default:
2840566d3c57SDamien Le Moal 		WARN_ONCE(true, "Invalid zone %llu condition %x\n",
2841566d3c57SDamien Le Moal 			  zsp->z_start, zsp->z_cond);
2842566d3c57SDamien Le Moal 		break;
2843566d3c57SDamien Le Moal 	}
2844566d3c57SDamien Le Moal 	zsp->z_cond = ZC5_FULL;
2845566d3c57SDamien Le Moal }
2846566d3c57SDamien Le Moal 
2847f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2848f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2849f0d1cf93SDouglas Gilbert {
2850f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
285164e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2852f0d1cf93SDouglas Gilbert 
28534a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2854f0d1cf93SDouglas Gilbert 		return;
2855f0d1cf93SDouglas Gilbert 
285635dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2857f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
285864e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2859566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
286064e14eceSDamien Le Moal 		return;
286164e14eceSDamien Le Moal 	}
286264e14eceSDamien Le Moal 
286364e14eceSDamien Le Moal 	while (num) {
286464e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
286564e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
286664e14eceSDamien Le Moal 
286764e14eceSDamien Le Moal 		end = lba + num;
286864e14eceSDamien Le Moal 		if (end >= zend) {
286964e14eceSDamien Le Moal 			n = zend - lba;
287064e14eceSDamien Le Moal 			zsp->z_wp = zend;
287164e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
287264e14eceSDamien Le Moal 			n = num;
287364e14eceSDamien Le Moal 			zsp->z_wp = end;
287464e14eceSDamien Le Moal 		} else {
287564e14eceSDamien Le Moal 			n = num;
287664e14eceSDamien Le Moal 		}
287764e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2878566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
287964e14eceSDamien Le Moal 
288064e14eceSDamien Le Moal 		num -= n;
288164e14eceSDamien Le Moal 		lba += n;
288264e14eceSDamien Le Moal 		if (num) {
288364e14eceSDamien Le Moal 			zsp++;
288464e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
288564e14eceSDamien Le Moal 		}
288664e14eceSDamien Le Moal 	}
2887f0d1cf93SDouglas Gilbert }
2888f0d1cf93SDouglas Gilbert 
2889f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
28909447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
28911da177e4SLinus Torvalds {
2892f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2893f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2894f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2895f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2896f0d1cf93SDouglas Gilbert 
2897f0d1cf93SDouglas Gilbert 	if (!write) {
289864e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
289964e14eceSDamien Le Moal 			return 0;
290064e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
29014a5fc1c6SDamien Le Moal 		if (zsp->z_type != zsp_end->z_type) {
2902f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2903f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2904f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2905f0d1cf93SDouglas Gilbert 			return check_condition_result;
2906f0d1cf93SDouglas Gilbert 		}
2907f0d1cf93SDouglas Gilbert 		return 0;
2908f0d1cf93SDouglas Gilbert 	}
2909f0d1cf93SDouglas Gilbert 
29104a5fc1c6SDamien Le Moal 	/* Writing into a gap zone is not allowed */
29114a5fc1c6SDamien Le Moal 	if (zbc_zone_is_gap(zsp)) {
29124a5fc1c6SDamien Le Moal 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE,
29134a5fc1c6SDamien Le Moal 				ATTEMPT_ACCESS_GAP);
29144a5fc1c6SDamien Le Moal 		return check_condition_result;
29154a5fc1c6SDamien Le Moal 	}
29164a5fc1c6SDamien Le Moal 
2917f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2918f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2919f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2920f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2921f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2922f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2923f0d1cf93SDouglas Gilbert 			return check_condition_result;
2924f0d1cf93SDouglas Gilbert 		}
2925f0d1cf93SDouglas Gilbert 		return 0;
2926f0d1cf93SDouglas Gilbert 	}
2927f0d1cf93SDouglas Gilbert 
292835dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2929f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2930f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2931f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2932f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2933f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2934f0d1cf93SDouglas Gilbert 			return check_condition_result;
2935f0d1cf93SDouglas Gilbert 		}
2936f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2937f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2938f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2939f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2940f0d1cf93SDouglas Gilbert 			return check_condition_result;
2941f0d1cf93SDouglas Gilbert 		}
2942f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2943f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2944f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2945f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2946f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2947f0d1cf93SDouglas Gilbert 			return check_condition_result;
2948f0d1cf93SDouglas Gilbert 		}
294964e14eceSDamien Le Moal 	}
2950f0d1cf93SDouglas Gilbert 
2951f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2952f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2953f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2954f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2955f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2956f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2957f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2958f0d1cf93SDouglas Gilbert 			return check_condition_result;
2959f0d1cf93SDouglas Gilbert 		}
2960f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2961f0d1cf93SDouglas Gilbert 	}
2962f0d1cf93SDouglas Gilbert 
2963f0d1cf93SDouglas Gilbert 	return 0;
2964f0d1cf93SDouglas Gilbert }
2965f0d1cf93SDouglas Gilbert 
2966f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2967f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2968f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2969f0d1cf93SDouglas Gilbert {
2970f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2971f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2972f0d1cf93SDouglas Gilbert 
2973c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
297422017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
29751da177e4SLinus Torvalds 		return check_condition_result;
29761da177e4SLinus Torvalds 	}
2977c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2978c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
297922017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2980cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2981c65b1445SDouglas Gilbert 		return check_condition_result;
2982c65b1445SDouglas Gilbert 	}
29839447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
29849447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29859447b6ceSMartin K. Petersen 		return check_condition_result;
29869447b6ceSMartin K. Petersen 	}
2987f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2988f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2989f0d1cf93SDouglas Gilbert 
299019789100SFUJITA Tomonori 	return 0;
299119789100SFUJITA Tomonori }
299219789100SFUJITA Tomonori 
2993b6ff8ca7SDouglas Gilbert /*
2994b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2995b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2996b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2997b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2998b6ff8ca7SDouglas Gilbert  */
2999b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
3000b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
300187c715dcSDouglas Gilbert {
3002b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
3003b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
3004b6ff8ca7SDouglas Gilbert 		return NULL;
3005b6ff8ca7SDouglas Gilbert 	}
3006b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
300787c715dcSDouglas Gilbert }
300887c715dcSDouglas Gilbert 
3009a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
301087c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
301187c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
301219789100SFUJITA Tomonori {
301319789100SFUJITA Tomonori 	int ret;
3014c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
3015a4517511SAkinobu Mita 	enum dma_data_direction dir;
301687c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
301787c715dcSDouglas Gilbert 	u8 *fsp;
301819789100SFUJITA Tomonori 
3019c2248fc9SDouglas Gilbert 	if (do_write) {
3020a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
30214f2c8bf6SDouglas Gilbert 		write_since_sync = true;
3022a4517511SAkinobu Mita 	} else {
3023a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
3024a4517511SAkinobu Mita 	}
3025a4517511SAkinobu Mita 
302687c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
3027a4517511SAkinobu Mita 		return 0;
302887c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
3029a4517511SAkinobu Mita 		return -1;
303087c715dcSDouglas Gilbert 	fsp = sip->storep;
303119789100SFUJITA Tomonori 
303219789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
303319789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
303419789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
303519789100SFUJITA Tomonori 
3036386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
303787c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
30380a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
3039773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
3040a4517511SAkinobu Mita 		return ret;
3041a4517511SAkinobu Mita 
3042a4517511SAkinobu Mita 	if (rest) {
3043386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
304487c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
30450a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
30460a7e69c7SDouglas Gilbert 			    do_write);
3047a4517511SAkinobu Mita 	}
304819789100SFUJITA Tomonori 
304919789100SFUJITA Tomonori 	return ret;
305019789100SFUJITA Tomonori }
305119789100SFUJITA Tomonori 
305287c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
305387c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
305487c715dcSDouglas Gilbert {
305587c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
305687c715dcSDouglas Gilbert 
305787c715dcSDouglas Gilbert 	if (!sdb->length)
305887c715dcSDouglas Gilbert 		return 0;
305987c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
306087c715dcSDouglas Gilbert 		return -1;
306187c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
306287c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
306387c715dcSDouglas Gilbert }
306487c715dcSDouglas Gilbert 
306587c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
306687c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
306738d5c833SDouglas Gilbert  * return false. */
306887c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
3069c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
307038d5c833SDouglas Gilbert {
307138d5c833SDouglas Gilbert 	bool res;
307238d5c833SDouglas Gilbert 	u64 block, rest = 0;
307338d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
3074773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
307587c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
307638d5c833SDouglas Gilbert 
307738d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
307838d5c833SDouglas Gilbert 	if (block + num > store_blks)
307938d5c833SDouglas Gilbert 		rest = block + num - store_blks;
308038d5c833SDouglas Gilbert 
308187c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
308238d5c833SDouglas Gilbert 	if (!res)
308338d5c833SDouglas Gilbert 		return res;
308438d5c833SDouglas Gilbert 	if (rest)
308587c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
308638d5c833SDouglas Gilbert 			     rest * lb_size);
308738d5c833SDouglas Gilbert 	if (!res)
308838d5c833SDouglas Gilbert 		return res;
3089c3e2fe92SDouglas Gilbert 	if (compare_only)
3090c3e2fe92SDouglas Gilbert 		return true;
309138d5c833SDouglas Gilbert 	arr += num * lb_size;
309287c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
309338d5c833SDouglas Gilbert 	if (rest)
309487c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
309538d5c833SDouglas Gilbert 	return res;
309638d5c833SDouglas Gilbert }
309738d5c833SDouglas Gilbert 
309851d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3099beb40ea4SAkinobu Mita {
310051d648afSAkinobu Mita 	__be16 csum;
3101beb40ea4SAkinobu Mita 
3102773642d9SDouglas Gilbert 	if (sdebug_guard)
310351d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
310451d648afSAkinobu Mita 	else
3105beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
310651d648afSAkinobu Mita 
3107beb40ea4SAkinobu Mita 	return csum;
3108beb40ea4SAkinobu Mita }
3109beb40ea4SAkinobu Mita 
31106ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3111beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3112beb40ea4SAkinobu Mita {
3113773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3114beb40ea4SAkinobu Mita 
3115beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3116c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3117beb40ea4SAkinobu Mita 			(unsigned long)sector,
3118beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3119beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3120beb40ea4SAkinobu Mita 		return 0x01;
3121beb40ea4SAkinobu Mita 	}
31228475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3123beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3124c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3125c1287970STomas Winkler 			(unsigned long)sector);
3126beb40ea4SAkinobu Mita 		return 0x03;
3127beb40ea4SAkinobu Mita 	}
31288475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3129beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3130c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3131c1287970STomas Winkler 			(unsigned long)sector);
3132beb40ea4SAkinobu Mita 		return 0x03;
3133beb40ea4SAkinobu Mita 	}
3134beb40ea4SAkinobu Mita 	return 0;
3135beb40ea4SAkinobu Mita }
3136beb40ea4SAkinobu Mita 
313787c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
313865f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3139c6a44287SMartin K. Petersen {
3140be4e11beSAkinobu Mita 	size_t resid;
3141c6a44287SMartin K. Petersen 	void *paddr;
314287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3143b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
314487c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
314514faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3146be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3147c6a44287SMartin K. Petersen 
3148e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3149e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3150c6a44287SMartin K. Petersen 
315187c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
315287c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3153be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3154be4e11beSAkinobu Mita 
3155be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
315687c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
315787c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3158be4e11beSAkinobu Mita 		size_t rest = 0;
315914faa944SAkinobu Mita 
316014faa944SAkinobu Mita 		if (dif_store_end < start + len)
316114faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3162c6a44287SMartin K. Petersen 
3163be4e11beSAkinobu Mita 		paddr = miter.addr;
316414faa944SAkinobu Mita 
316565f72f2aSAkinobu Mita 		if (read)
316665f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
316765f72f2aSAkinobu Mita 		else
316865f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
316965f72f2aSAkinobu Mita 
317065f72f2aSAkinobu Mita 		if (rest) {
317165f72f2aSAkinobu Mita 			if (read)
317214faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
317365f72f2aSAkinobu Mita 			else
317465f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
317565f72f2aSAkinobu Mita 		}
3176c6a44287SMartin K. Petersen 
3177e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3178c6a44287SMartin K. Petersen 		resid -= len;
3179c6a44287SMartin K. Petersen 	}
3180be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3181bb8c063cSAkinobu Mita }
3182c6a44287SMartin K. Petersen 
318387c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3184bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3185bb8c063cSAkinobu Mita {
3186f7be6772SMartin K. Petersen 	int ret = 0;
3187bb8c063cSAkinobu Mita 	unsigned int i;
3188bb8c063cSAkinobu Mita 	sector_t sector;
318987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3190b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
319187c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3192bb8c063cSAkinobu Mita 
3193c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3194bb8c063cSAkinobu Mita 		sector = start_sec + i;
319587c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3196bb8c063cSAkinobu Mita 
319751d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3198bb8c063cSAkinobu Mita 			continue;
3199bb8c063cSAkinobu Mita 
3200f7be6772SMartin K. Petersen 		/*
3201f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3202f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3203f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3204f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3205f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3206f7be6772SMartin K. Petersen 		 */
3207f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3208f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3209f7be6772SMartin K. Petersen 					 sector, ei_lba);
3210bb8c063cSAkinobu Mita 			if (ret) {
3211bb8c063cSAkinobu Mita 				dif_errors++;
3212f7be6772SMartin K. Petersen 				break;
3213f7be6772SMartin K. Petersen 			}
3214bb8c063cSAkinobu Mita 		}
3215bb8c063cSAkinobu Mita 	}
3216bb8c063cSAkinobu Mita 
321787c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3218c6a44287SMartin K. Petersen 	dix_reads++;
3219c6a44287SMartin K. Petersen 
3220f7be6772SMartin K. Petersen 	return ret;
3221c6a44287SMartin K. Petersen }
3222c6a44287SMartin K. Petersen 
32237109f370SDouglas Gilbert static inline void
32247109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip)
32257109f370SDouglas Gilbert {
3226e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3227e9c47801SDamien Le Moal 		if (sip)
3228e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3229e9c47801SDamien Le Moal 		else
3230e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3231e9c47801SDamien Le Moal 	} else {
32327109f370SDouglas Gilbert 		if (sip)
32337109f370SDouglas Gilbert 			read_lock(&sip->macc_lck);
32347109f370SDouglas Gilbert 		else
32357109f370SDouglas Gilbert 			read_lock(&sdeb_fake_rw_lck);
32367109f370SDouglas Gilbert 	}
3237e9c47801SDamien Le Moal }
32387109f370SDouglas Gilbert 
32397109f370SDouglas Gilbert static inline void
32407109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip)
32417109f370SDouglas Gilbert {
3242e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3243e9c47801SDamien Le Moal 		if (sip)
3244e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3245e9c47801SDamien Le Moal 		else
3246e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3247e9c47801SDamien Le Moal 	} else {
32487109f370SDouglas Gilbert 		if (sip)
32497109f370SDouglas Gilbert 			read_unlock(&sip->macc_lck);
32507109f370SDouglas Gilbert 		else
32517109f370SDouglas Gilbert 			read_unlock(&sdeb_fake_rw_lck);
32527109f370SDouglas Gilbert 	}
3253e9c47801SDamien Le Moal }
32547109f370SDouglas Gilbert 
32557109f370SDouglas Gilbert static inline void
32567109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip)
32577109f370SDouglas Gilbert {
3258e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3259e9c47801SDamien Le Moal 		if (sip)
3260e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3261e9c47801SDamien Le Moal 		else
3262e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3263e9c47801SDamien Le Moal 	} else {
32647109f370SDouglas Gilbert 		if (sip)
32657109f370SDouglas Gilbert 			write_lock(&sip->macc_lck);
32667109f370SDouglas Gilbert 		else
32677109f370SDouglas Gilbert 			write_lock(&sdeb_fake_rw_lck);
32687109f370SDouglas Gilbert 	}
3269e9c47801SDamien Le Moal }
32707109f370SDouglas Gilbert 
32717109f370SDouglas Gilbert static inline void
32727109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip)
32737109f370SDouglas Gilbert {
3274e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3275e9c47801SDamien Le Moal 		if (sip)
3276e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3277e9c47801SDamien Le Moal 		else
3278e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3279e9c47801SDamien Le Moal 	} else {
32807109f370SDouglas Gilbert 		if (sip)
32817109f370SDouglas Gilbert 			write_unlock(&sip->macc_lck);
32827109f370SDouglas Gilbert 		else
32837109f370SDouglas Gilbert 			write_unlock(&sdeb_fake_rw_lck);
32847109f370SDouglas Gilbert 	}
3285e9c47801SDamien Le Moal }
32867109f370SDouglas Gilbert 
3287fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
328819789100SFUJITA Tomonori {
328987c715dcSDouglas Gilbert 	bool check_prot;
3290c2248fc9SDouglas Gilbert 	u32 num;
3291c2248fc9SDouglas Gilbert 	u32 ei_lba;
329219789100SFUJITA Tomonori 	int ret;
329387c715dcSDouglas Gilbert 	u64 lba;
3294b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
329587c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
329619789100SFUJITA Tomonori 
3297c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3298c2248fc9SDouglas Gilbert 	case READ_16:
3299c2248fc9SDouglas Gilbert 		ei_lba = 0;
3300c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3301c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3302c2248fc9SDouglas Gilbert 		check_prot = true;
3303c2248fc9SDouglas Gilbert 		break;
3304c2248fc9SDouglas Gilbert 	case READ_10:
3305c2248fc9SDouglas Gilbert 		ei_lba = 0;
3306c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3307c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3308c2248fc9SDouglas Gilbert 		check_prot = true;
3309c2248fc9SDouglas Gilbert 		break;
3310c2248fc9SDouglas Gilbert 	case READ_6:
3311c2248fc9SDouglas Gilbert 		ei_lba = 0;
3312c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3313c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3314c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3315c2248fc9SDouglas Gilbert 		check_prot = true;
3316c2248fc9SDouglas Gilbert 		break;
3317c2248fc9SDouglas Gilbert 	case READ_12:
3318c2248fc9SDouglas Gilbert 		ei_lba = 0;
3319c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3320c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3321c2248fc9SDouglas Gilbert 		check_prot = true;
3322c2248fc9SDouglas Gilbert 		break;
3323c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3324c2248fc9SDouglas Gilbert 		ei_lba = 0;
3325c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3326c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3327c2248fc9SDouglas Gilbert 		check_prot = false;
3328c2248fc9SDouglas Gilbert 		break;
3329c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3330c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3331c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3332c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3333c2248fc9SDouglas Gilbert 		check_prot = false;
3334c2248fc9SDouglas Gilbert 		break;
3335c2248fc9SDouglas Gilbert 	}
3336f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
33378475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3338c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3339c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3340c2248fc9SDouglas Gilbert 			return check_condition_result;
3341c2248fc9SDouglas Gilbert 		}
33428475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
33438475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3344c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3345c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3346c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3347c2248fc9SDouglas Gilbert 	}
33483a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
33493a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3350c2248fc9SDouglas Gilbert 		num /= 2;
33513a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3352c2248fc9SDouglas Gilbert 	}
3353c2248fc9SDouglas Gilbert 
33549447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
33559447b6ceSMartin K. Petersen 	if (ret)
33569447b6ceSMartin K. Petersen 		return ret;
3357f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3358d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3359d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3360c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3361c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3362c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3363c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3364c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
336532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
336632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3367c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3368c65b1445SDouglas Gilbert 		}
3369c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
33701da177e4SLinus Torvalds 		return check_condition_result;
33711da177e4SLinus Torvalds 	}
3372c6a44287SMartin K. Petersen 
33737109f370SDouglas Gilbert 	sdeb_read_lock(sip);
33746c78cc06SAkinobu Mita 
3375c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3376f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3377f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3378f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3379f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33807109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3381f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3382f7be6772SMartin K. Petersen 				return check_condition_result;
3383f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
33847109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3385f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3386c6a44287SMartin K. Petersen 				return illegal_condition_result;
3387c6a44287SMartin K. Petersen 			}
3388f7be6772SMartin K. Petersen 			break;
3389f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3390f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33917109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3392f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3393f7be6772SMartin K. Petersen 				return check_condition_result;
3394f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
33957109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3396f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3397f7be6772SMartin K. Petersen 				return illegal_condition_result;
3398f7be6772SMartin K. Petersen 			}
3399f7be6772SMartin K. Petersen 			break;
3400f7be6772SMartin K. Petersen 		}
3401c6a44287SMartin K. Petersen 	}
3402c6a44287SMartin K. Petersen 
340387c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
34047109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
3405f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3406a4517511SAkinobu Mita 		return DID_ERROR << 16;
3407a4517511SAkinobu Mita 
340842d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3409a4517511SAkinobu Mita 
34103a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
34113a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
34123a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
34133a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
34143a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3415c2248fc9SDouglas Gilbert 			return check_condition_result;
34163a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3417c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3418c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
34193a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3420c2248fc9SDouglas Gilbert 			return illegal_condition_result;
34213a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3422c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
34233a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3424c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3425c2248fc9SDouglas Gilbert 		}
3426c2248fc9SDouglas Gilbert 	}
3427a4517511SAkinobu Mita 	return 0;
34281da177e4SLinus Torvalds }
34291da177e4SLinus Torvalds 
3430c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3431395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3432c6a44287SMartin K. Petersen {
3433be4e11beSAkinobu Mita 	int ret;
34346ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3435be4e11beSAkinobu Mita 	void *daddr;
343665f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3437c6a44287SMartin K. Petersen 	int ppage_offset;
3438be4e11beSAkinobu Mita 	int dpage_offset;
3439be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3440be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3441c6a44287SMartin K. Petersen 
3442c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3443c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3444c6a44287SMartin K. Petersen 
3445be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3446be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3447be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3448be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3449be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3450c6a44287SMartin K. Petersen 
3451be4e11beSAkinobu Mita 	/* For each protection page */
3452be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3453be4e11beSAkinobu Mita 		dpage_offset = 0;
3454be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3455be4e11beSAkinobu Mita 			ret = 0x01;
3456be4e11beSAkinobu Mita 			goto out;
3457c6a44287SMartin K. Petersen 		}
3458c6a44287SMartin K. Petersen 
3459be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
34606ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3461be4e11beSAkinobu Mita 			/* If we're at the end of the current
3462be4e11beSAkinobu Mita 			 * data page advance to the next one
3463be4e11beSAkinobu Mita 			 */
3464be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3465be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3466be4e11beSAkinobu Mita 					ret = 0x01;
3467be4e11beSAkinobu Mita 					goto out;
3468be4e11beSAkinobu Mita 				}
3469be4e11beSAkinobu Mita 				dpage_offset = 0;
3470be4e11beSAkinobu Mita 			}
3471c6a44287SMartin K. Petersen 
3472be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3473be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3474be4e11beSAkinobu Mita 
3475f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3476be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3477c78be80dSMartin K. Petersen 				if (ret)
3478395cef03SMartin K. Petersen 					goto out;
3479395cef03SMartin K. Petersen 			}
3480395cef03SMartin K. Petersen 
3481c6a44287SMartin K. Petersen 			sector++;
3482395cef03SMartin K. Petersen 			ei_lba++;
3483773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3484c6a44287SMartin K. Petersen 		}
3485be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3486be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3487c6a44287SMartin K. Petersen 	}
3488be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3489c6a44287SMartin K. Petersen 
349065f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3491c6a44287SMartin K. Petersen 	dix_writes++;
3492c6a44287SMartin K. Petersen 
3493c6a44287SMartin K. Petersen 	return 0;
3494c6a44287SMartin K. Petersen 
3495c6a44287SMartin K. Petersen out:
3496c6a44287SMartin K. Petersen 	dif_errors++;
3497be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3498be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3499c6a44287SMartin K. Petersen 	return ret;
3500c6a44287SMartin K. Petersen }
3501c6a44287SMartin K. Petersen 
3502b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3503b90ebc3dSAkinobu Mita {
3504773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3505773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3506773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3507b90ebc3dSAkinobu Mita 	return lba;
3508b90ebc3dSAkinobu Mita }
3509b90ebc3dSAkinobu Mita 
3510b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3511b90ebc3dSAkinobu Mita {
3512773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3513a027b5b9SAkinobu Mita 
3514773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3515773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3516a027b5b9SAkinobu Mita 	return lba;
3517a027b5b9SAkinobu Mita }
3518a027b5b9SAkinobu Mita 
351987c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
352087c715dcSDouglas Gilbert 			      unsigned int *num)
352144d92694SMartin K. Petersen {
3522b90ebc3dSAkinobu Mita 	sector_t end;
3523b90ebc3dSAkinobu Mita 	unsigned int mapped;
3524b90ebc3dSAkinobu Mita 	unsigned long index;
3525b90ebc3dSAkinobu Mita 	unsigned long next;
352644d92694SMartin K. Petersen 
3527b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
352887c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
352944d92694SMartin K. Petersen 
353044d92694SMartin K. Petersen 	if (mapped)
353187c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
353244d92694SMartin K. Petersen 	else
353387c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
353444d92694SMartin K. Petersen 
3535b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
353644d92694SMartin K. Petersen 	*num = end - lba;
353744d92694SMartin K. Petersen 	return mapped;
353844d92694SMartin K. Petersen }
353944d92694SMartin K. Petersen 
354087c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
354187c715dcSDouglas Gilbert 		       unsigned int len)
354244d92694SMartin K. Petersen {
354344d92694SMartin K. Petersen 	sector_t end = lba + len;
354444d92694SMartin K. Petersen 
354544d92694SMartin K. Petersen 	while (lba < end) {
3546b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
354744d92694SMartin K. Petersen 
3548b90ebc3dSAkinobu Mita 		if (index < map_size)
354987c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
355044d92694SMartin K. Petersen 
3551b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
355244d92694SMartin K. Petersen 	}
355344d92694SMartin K. Petersen }
355444d92694SMartin K. Petersen 
355587c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
355687c715dcSDouglas Gilbert 			 unsigned int len)
355744d92694SMartin K. Petersen {
355844d92694SMartin K. Petersen 	sector_t end = lba + len;
355987c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
356044d92694SMartin K. Petersen 
356144d92694SMartin K. Petersen 	while (lba < end) {
3562b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
356344d92694SMartin K. Petersen 
3564b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3565773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3566b90ebc3dSAkinobu Mita 		    index < map_size) {
356787c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3568760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
356987c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3570760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3571773642d9SDouglas Gilbert 				       sdebug_sector_size *
3572773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3573be1dd78dSEric Sandeen 			}
357487c715dcSDouglas Gilbert 			if (sip->dif_storep) {
357587c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
357687c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3577773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3578e9926b43SAkinobu Mita 			}
3579b90ebc3dSAkinobu Mita 		}
3580b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
358144d92694SMartin K. Petersen 	}
358244d92694SMartin K. Petersen }
358344d92694SMartin K. Petersen 
3584fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
35851da177e4SLinus Torvalds {
358687c715dcSDouglas Gilbert 	bool check_prot;
3587c2248fc9SDouglas Gilbert 	u32 num;
3588c2248fc9SDouglas Gilbert 	u32 ei_lba;
358919789100SFUJITA Tomonori 	int ret;
359087c715dcSDouglas Gilbert 	u64 lba;
3591b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
359287c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
35931da177e4SLinus Torvalds 
3594c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3595c2248fc9SDouglas Gilbert 	case WRITE_16:
3596c2248fc9SDouglas Gilbert 		ei_lba = 0;
3597c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3598c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3599c2248fc9SDouglas Gilbert 		check_prot = true;
3600c2248fc9SDouglas Gilbert 		break;
3601c2248fc9SDouglas Gilbert 	case WRITE_10:
3602c2248fc9SDouglas Gilbert 		ei_lba = 0;
3603c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3604c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3605c2248fc9SDouglas Gilbert 		check_prot = true;
3606c2248fc9SDouglas Gilbert 		break;
3607c2248fc9SDouglas Gilbert 	case WRITE_6:
3608c2248fc9SDouglas Gilbert 		ei_lba = 0;
3609c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3610c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3611c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3612c2248fc9SDouglas Gilbert 		check_prot = true;
3613c2248fc9SDouglas Gilbert 		break;
3614c2248fc9SDouglas Gilbert 	case WRITE_12:
3615c2248fc9SDouglas Gilbert 		ei_lba = 0;
3616c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3617c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3618c2248fc9SDouglas Gilbert 		check_prot = true;
3619c2248fc9SDouglas Gilbert 		break;
3620c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3621c2248fc9SDouglas Gilbert 		ei_lba = 0;
3622c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3623c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3624c2248fc9SDouglas Gilbert 		check_prot = false;
3625c2248fc9SDouglas Gilbert 		break;
3626c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3627c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3628c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3629c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3630c2248fc9SDouglas Gilbert 		check_prot = false;
3631c2248fc9SDouglas Gilbert 		break;
3632c2248fc9SDouglas Gilbert 	}
3633f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
36348475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3635c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3636c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3637c2248fc9SDouglas Gilbert 			return check_condition_result;
3638c2248fc9SDouglas Gilbert 		}
36398475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
36408475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3641c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3642c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3643c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3644c2248fc9SDouglas Gilbert 	}
3645f0d1cf93SDouglas Gilbert 
36467109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3647f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3648f0d1cf93SDouglas Gilbert 	if (ret) {
36497109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3650f0d1cf93SDouglas Gilbert 		return ret;
3651f0d1cf93SDouglas Gilbert 	}
36526c78cc06SAkinobu Mita 
3653c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3654f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3655f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3656f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3657f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
36587109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3659f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3660c6a44287SMartin K. Petersen 				return illegal_condition_result;
3661f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36627109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3663f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3664f7be6772SMartin K. Petersen 				return check_condition_result;
3665f7be6772SMartin K. Petersen 			}
3666f7be6772SMartin K. Petersen 			break;
3667f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3668f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
36697109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3670f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3671f7be6772SMartin K. Petersen 				return illegal_condition_result;
3672f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36737109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3674f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3675f7be6772SMartin K. Petersen 				return check_condition_result;
3676f7be6772SMartin K. Petersen 			}
3677f7be6772SMartin K. Petersen 			break;
3678c6a44287SMartin K. Petersen 		}
3679c6a44287SMartin K. Petersen 	}
3680c6a44287SMartin K. Petersen 
368187c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3682f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
368387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3684f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3685f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3686f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
36877109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3688f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3689773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3690c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3691c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3692c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3693cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3694773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
369544d92694SMartin K. Petersen 
36963a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36973a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
36983a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36993a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
37003a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3701c2248fc9SDouglas Gilbert 			return check_condition_result;
37023a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3703c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3704c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37053a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3706c2248fc9SDouglas Gilbert 			return illegal_condition_result;
37073a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3708c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37093a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3710c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3711c2248fc9SDouglas Gilbert 		}
3712c2248fc9SDouglas Gilbert 	}
37131da177e4SLinus Torvalds 	return 0;
37141da177e4SLinus Torvalds }
37151da177e4SLinus Torvalds 
3716481b5e5cSDouglas Gilbert /*
3717481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3718481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3719481b5e5cSDouglas Gilbert  */
3720481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3721481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3722481b5e5cSDouglas Gilbert {
3723481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3724481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3725481b5e5cSDouglas Gilbert 	u8 *up;
3726b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3727481b5e5cSDouglas Gilbert 	u8 wrprotect;
3728481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3729481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3730481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3731481b5e5cSDouglas Gilbert 	u32 ei_lba;
3732481b5e5cSDouglas Gilbert 	u64 lba;
3733481b5e5cSDouglas Gilbert 	int ret, res;
3734481b5e5cSDouglas Gilbert 	bool is_16;
3735481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3736481b5e5cSDouglas Gilbert 
3737481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3738481b5e5cSDouglas Gilbert 		is_16 = false;
3739481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3740481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3741481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3742481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3743481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3744481b5e5cSDouglas Gilbert 		is_16 = true;
3745481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3746481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3747481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3748481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3749481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3750481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3751481b5e5cSDouglas Gilbert 			    wrprotect) {
3752481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3753481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3754481b5e5cSDouglas Gilbert 			}
3755481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3756481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3757481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3758481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3759481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3760481b5e5cSDouglas Gilbert 		}
3761481b5e5cSDouglas Gilbert 	}
3762481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3763481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3764481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3765481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3766481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3767481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3768481b5e5cSDouglas Gilbert 				my_name, __func__);
3769481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3770481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3771481b5e5cSDouglas Gilbert 	}
3772481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3773481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3774481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3775481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3776481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3777481b5e5cSDouglas Gilbert 				my_name, __func__);
3778481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3779481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3780481b5e5cSDouglas Gilbert 	}
3781216e1797SHarshit Mogalapalli 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN);
3782481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3783481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3784481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3785481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3786481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3787481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3788481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3789481b5e5cSDouglas Gilbert 	if (res == -1) {
3790481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3791481b5e5cSDouglas Gilbert 		goto err_out;
3792481b5e5cSDouglas Gilbert 	}
3793481b5e5cSDouglas Gilbert 
37947109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3795481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3796481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3797481b5e5cSDouglas Gilbert 	cum_lb = 0;
3798481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3799481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3800481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3801481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3802481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3803481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3804481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3805481b5e5cSDouglas Gilbert 		if (num == 0)
3806481b5e5cSDouglas Gilbert 			continue;
38079447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3808481b5e5cSDouglas Gilbert 		if (ret)
3809481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3810481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3811481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3812481b5e5cSDouglas Gilbert 
3813481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3814481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3815481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3816481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3817481b5e5cSDouglas Gilbert 				    my_name, __func__);
3818481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3819481b5e5cSDouglas Gilbert 					0);
3820481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3821481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3822481b5e5cSDouglas Gilbert 		}
3823481b5e5cSDouglas Gilbert 
3824481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3825481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3826481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3827481b5e5cSDouglas Gilbert 							 ei_lba);
3828481b5e5cSDouglas Gilbert 
3829481b5e5cSDouglas Gilbert 			if (prot_ret) {
3830481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3831481b5e5cSDouglas Gilbert 						prot_ret);
3832481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3833481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3834481b5e5cSDouglas Gilbert 			}
3835481b5e5cSDouglas Gilbert 		}
3836481b5e5cSDouglas Gilbert 
383787c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3838f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3839f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3840f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3841481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
384287c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3843481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3844481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3845481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3846481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3847481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3848481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3849481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3850481b5e5cSDouglas Gilbert 
38513a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
38523a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
38533a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
38543a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
38553a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
38563a90a63dSDouglas Gilbert 				ret = check_condition_result;
3857481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38583a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3859481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
38603a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
38613a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3862481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3863481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38643a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
38653a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
38663a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3867481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3868481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3869481b5e5cSDouglas Gilbert 			}
3870481b5e5cSDouglas Gilbert 		}
3871481b5e5cSDouglas Gilbert 		sg_off += num_by;
3872481b5e5cSDouglas Gilbert 		cum_lb += num;
3873481b5e5cSDouglas Gilbert 	}
3874481b5e5cSDouglas Gilbert 	ret = 0;
3875481b5e5cSDouglas Gilbert err_out_unlock:
38767109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3877481b5e5cSDouglas Gilbert err_out:
3878481b5e5cSDouglas Gilbert 	kfree(lrdp);
3879481b5e5cSDouglas Gilbert 	return ret;
3880481b5e5cSDouglas Gilbert }
3881481b5e5cSDouglas Gilbert 
3882fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3883fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
388444d92694SMartin K. Petersen {
3885f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3886f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
388744d92694SMartin K. Petersen 	unsigned long long i;
388840d07b52SDouglas Gilbert 	u64 block, lbaa;
388987c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
389087c715dcSDouglas Gilbert 	int ret;
389187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3892b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
389340d07b52SDouglas Gilbert 	u8 *fs1p;
389487c715dcSDouglas Gilbert 	u8 *fsp;
389544d92694SMartin K. Petersen 
38967109f370SDouglas Gilbert 	sdeb_write_lock(sip);
389744d92694SMartin K. Petersen 
3898f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3899f0d1cf93SDouglas Gilbert 	if (ret) {
39007109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3901f0d1cf93SDouglas Gilbert 		return ret;
3902f0d1cf93SDouglas Gilbert 	}
3903f0d1cf93SDouglas Gilbert 
39049ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
390587c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
390644d92694SMartin K. Petersen 		goto out;
390744d92694SMartin K. Petersen 	}
390840d07b52SDouglas Gilbert 	lbaa = lba;
390940d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3910c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
391187c715dcSDouglas Gilbert 	fsp = sip->storep;
391287c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3913c2248fc9SDouglas Gilbert 	if (ndob) {
391440d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3915c2248fc9SDouglas Gilbert 		ret = 0;
3916c2248fc9SDouglas Gilbert 	} else
391740d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
391844d92694SMartin K. Petersen 
391944d92694SMartin K. Petersen 	if (-1 == ret) {
39207109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3921773642d9SDouglas Gilbert 		return DID_ERROR << 16;
392240d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3923c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3924e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
392540d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
392644d92694SMartin K. Petersen 
392744d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
392840d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
392940d07b52SDouglas Gilbert 		lbaa = lba + i;
393040d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
393187c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
393240d07b52SDouglas Gilbert 	}
39339ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
393487c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3935f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3936f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3937f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
393844d92694SMartin K. Petersen out:
39397109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
394044d92694SMartin K. Petersen 
394144d92694SMartin K. Petersen 	return 0;
394244d92694SMartin K. Petersen }
394344d92694SMartin K. Petersen 
3944fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3945fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3946c2248fc9SDouglas Gilbert {
3947c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3948c2248fc9SDouglas Gilbert 	u32 lba;
3949c2248fc9SDouglas Gilbert 	u16 num;
3950c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3951c2248fc9SDouglas Gilbert 	bool unmap = false;
3952c2248fc9SDouglas Gilbert 
3953c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3954773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3955c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3956c2248fc9SDouglas Gilbert 			return check_condition_result;
3957c2248fc9SDouglas Gilbert 		} else
3958c2248fc9SDouglas Gilbert 			unmap = true;
3959c2248fc9SDouglas Gilbert 	}
3960c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3961c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3962773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3963c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3964c2248fc9SDouglas Gilbert 		return check_condition_result;
3965c2248fc9SDouglas Gilbert 	}
3966c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3967c2248fc9SDouglas Gilbert }
3968c2248fc9SDouglas Gilbert 
3969fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3970fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3971c2248fc9SDouglas Gilbert {
3972c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3973c2248fc9SDouglas Gilbert 	u64 lba;
3974c2248fc9SDouglas Gilbert 	u32 num;
3975c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3976c2248fc9SDouglas Gilbert 	bool unmap = false;
3977c2248fc9SDouglas Gilbert 	bool ndob = false;
3978c2248fc9SDouglas Gilbert 
3979c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3980773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3981c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3982c2248fc9SDouglas Gilbert 			return check_condition_result;
3983c2248fc9SDouglas Gilbert 		} else
3984c2248fc9SDouglas Gilbert 			unmap = true;
3985c2248fc9SDouglas Gilbert 	}
3986c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3987c2248fc9SDouglas Gilbert 		ndob = true;
3988c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3989c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3990773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3991c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3992c2248fc9SDouglas Gilbert 		return check_condition_result;
3993c2248fc9SDouglas Gilbert 	}
3994c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3995c2248fc9SDouglas Gilbert }
3996c2248fc9SDouglas Gilbert 
3997acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3998acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3999acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
4000fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
4001fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
4002acafd0b9SEwan D. Milne {
4003acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
4004acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
4005acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
4006acafd0b9SEwan D. Milne 	u8 mode;
4007acafd0b9SEwan D. Milne 
4008acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
4009acafd0b9SEwan D. Milne 	switch (mode) {
4010acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
4011acafd0b9SEwan D. Milne 		/* set UAs on this device only */
4012acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4013acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
4014acafd0b9SEwan D. Milne 		break;
4015acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
4016acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
4017acafd0b9SEwan D. Milne 		break;
4018acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
4019acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
4020acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4021acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4022acafd0b9SEwan D. Milne 				    dev_list)
4023acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
4024acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
4025acafd0b9SEwan D. Milne 				if (devip != dp)
4026acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
4027acafd0b9SEwan D. Milne 						dp->uas_bm);
4028acafd0b9SEwan D. Milne 			}
4029acafd0b9SEwan D. Milne 		break;
4030acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
4031acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
4032acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4033acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4034acafd0b9SEwan D. Milne 				    dev_list)
4035acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
4036acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
4037acafd0b9SEwan D. Milne 					dp->uas_bm);
4038acafd0b9SEwan D. Milne 		break;
4039acafd0b9SEwan D. Milne 	default:
4040acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
4041acafd0b9SEwan D. Milne 		break;
4042acafd0b9SEwan D. Milne 	}
4043acafd0b9SEwan D. Milne 	return 0;
4044acafd0b9SEwan D. Milne }
4045acafd0b9SEwan D. Milne 
4046fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
4047fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
404838d5c833SDouglas Gilbert {
404938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
405038d5c833SDouglas Gilbert 	u8 *arr;
4051b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
405238d5c833SDouglas Gilbert 	u64 lba;
405338d5c833SDouglas Gilbert 	u32 dnum;
4054773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
405538d5c833SDouglas Gilbert 	u8 num;
405638d5c833SDouglas Gilbert 	int ret;
4057d467d31fSDouglas Gilbert 	int retval = 0;
405838d5c833SDouglas Gilbert 
4059d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
406038d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
406138d5c833SDouglas Gilbert 	if (0 == num)
406238d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
40638475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
406438d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
406538d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
406638d5c833SDouglas Gilbert 		return check_condition_result;
406738d5c833SDouglas Gilbert 	}
40688475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
40698475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
407038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
407138d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
407238d5c833SDouglas Gilbert 			    "to DIF device\n");
40739447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
40749447b6ceSMartin K. Petersen 	if (ret)
40759447b6ceSMartin K. Petersen 		return ret;
4076d467d31fSDouglas Gilbert 	dnum = 2 * num;
40776396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
4078d467d31fSDouglas Gilbert 	if (NULL == arr) {
4079d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4080d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
4081d467d31fSDouglas Gilbert 		return check_condition_result;
4082d467d31fSDouglas Gilbert 	}
408338d5c833SDouglas Gilbert 
40847109f370SDouglas Gilbert 	sdeb_write_lock(sip);
408538d5c833SDouglas Gilbert 
408687c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
408738d5c833SDouglas Gilbert 	if (ret == -1) {
4088d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
4089d467d31fSDouglas Gilbert 		goto cleanup;
4090773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
409138d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
409238d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
409338d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
4094c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
409538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4096d467d31fSDouglas Gilbert 		retval = check_condition_result;
4097d467d31fSDouglas Gilbert 		goto cleanup;
409838d5c833SDouglas Gilbert 	}
409938d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
410087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
4101d467d31fSDouglas Gilbert cleanup:
41027109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4103d467d31fSDouglas Gilbert 	kfree(arr);
4104d467d31fSDouglas Gilbert 	return retval;
410538d5c833SDouglas Gilbert }
410638d5c833SDouglas Gilbert 
410744d92694SMartin K. Petersen struct unmap_block_desc {
410844d92694SMartin K. Petersen 	__be64	lba;
410944d92694SMartin K. Petersen 	__be32	blocks;
411044d92694SMartin K. Petersen 	__be32	__reserved;
411144d92694SMartin K. Petersen };
411244d92694SMartin K. Petersen 
4113fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
411444d92694SMartin K. Petersen {
411544d92694SMartin K. Petersen 	unsigned char *buf;
411644d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
4117b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
411844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
411944d92694SMartin K. Petersen 	int ret;
412044d92694SMartin K. Petersen 
4121c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
4122c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
4123c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
4124c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
412544d92694SMartin K. Petersen 
412644d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
4127773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
4128c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
412944d92694SMartin K. Petersen 		return check_condition_result;
4130c2248fc9SDouglas Gilbert 	}
413144d92694SMartin K. Petersen 
4132b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
4133c2248fc9SDouglas Gilbert 	if (!buf) {
4134c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4135c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
4136c2248fc9SDouglas Gilbert 		return check_condition_result;
4137c2248fc9SDouglas Gilbert 	}
4138c2248fc9SDouglas Gilbert 
4139c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
414044d92694SMartin K. Petersen 
414144d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
414244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
414344d92694SMartin K. Petersen 
414444d92694SMartin K. Petersen 	desc = (void *)&buf[8];
414544d92694SMartin K. Petersen 
41467109f370SDouglas Gilbert 	sdeb_write_lock(sip);
41476c78cc06SAkinobu Mita 
414844d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
414944d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
415044d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
415144d92694SMartin K. Petersen 
41529447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
415344d92694SMartin K. Petersen 		if (ret)
415444d92694SMartin K. Petersen 			goto out;
415544d92694SMartin K. Petersen 
415687c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
415744d92694SMartin K. Petersen 	}
415844d92694SMartin K. Petersen 
415944d92694SMartin K. Petersen 	ret = 0;
416044d92694SMartin K. Petersen 
416144d92694SMartin K. Petersen out:
41627109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
416344d92694SMartin K. Petersen 	kfree(buf);
416444d92694SMartin K. Petersen 
416544d92694SMartin K. Petersen 	return ret;
416644d92694SMartin K. Petersen }
416744d92694SMartin K. Petersen 
416844d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
416944d92694SMartin K. Petersen 
4170fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4171fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
417244d92694SMartin K. Petersen {
4173c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4174c2248fc9SDouglas Gilbert 	u64 lba;
4175c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
417644d92694SMartin K. Petersen 	int ret;
417787c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
417844d92694SMartin K. Petersen 
4179c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4180c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
418144d92694SMartin K. Petersen 
418244d92694SMartin K. Petersen 	if (alloc_len < 24)
418344d92694SMartin K. Petersen 		return 0;
418444d92694SMartin K. Petersen 
41859447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
418644d92694SMartin K. Petersen 	if (ret)
418744d92694SMartin K. Petersen 		return ret;
418844d92694SMartin K. Petersen 
4189b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4190b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4191b6ff8ca7SDouglas Gilbert 
419287c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4193b6ff8ca7SDouglas Gilbert 	} else {
4194c2248fc9SDouglas Gilbert 		mapped = 1;
4195c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4196c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4197c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4198c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4199c2248fc9SDouglas Gilbert 		else
4200c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4201c2248fc9SDouglas Gilbert 	}
420244d92694SMartin K. Petersen 
420344d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4204c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4205c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4206c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4207c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
420844d92694SMartin K. Petersen 
4209c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
421044d92694SMartin K. Petersen }
421144d92694SMartin K. Petersen 
421280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
421380c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
421480c49563SDouglas Gilbert {
42154f2c8bf6SDouglas Gilbert 	int res = 0;
421680c49563SDouglas Gilbert 	u64 lba;
421780c49563SDouglas Gilbert 	u32 num_blocks;
421880c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
421980c49563SDouglas Gilbert 
422080c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
422180c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
422280c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
422380c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
422480c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
422580c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
422680c49563SDouglas Gilbert 	}
422780c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
422880c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
422980c49563SDouglas Gilbert 		return check_condition_result;
423080c49563SDouglas Gilbert 	}
4231fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
42324f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
42334f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
42344f2c8bf6SDouglas Gilbert 		write_since_sync = false;
42354f2c8bf6SDouglas Gilbert 	return res;
423680c49563SDouglas Gilbert }
423780c49563SDouglas Gilbert 
4238ed9f3e25SDouglas Gilbert /*
4239ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4240ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4241ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4242ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4243ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4244ed9f3e25SDouglas Gilbert  */
4245ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4246ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4247ed9f3e25SDouglas Gilbert {
4248ed9f3e25SDouglas Gilbert 	int res = 0;
4249ed9f3e25SDouglas Gilbert 	u64 lba;
4250ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4251ed9f3e25SDouglas Gilbert 	u32 nblks;
4252ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4253b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4254b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4255ed9f3e25SDouglas Gilbert 
4256ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4257ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4258ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4259ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4260ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4261ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4262ed9f3e25SDouglas Gilbert 	}
4263ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4264ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4265ed9f3e25SDouglas Gilbert 		return check_condition_result;
4266ed9f3e25SDouglas Gilbert 	}
4267ed9f3e25SDouglas Gilbert 	if (!fsp)
4268ed9f3e25SDouglas Gilbert 		goto fini;
4269ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4270ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4271ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4272ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4273ed9f3e25SDouglas Gilbert 
4274ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
42757109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4276ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4277ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4278ed9f3e25SDouglas Gilbert 	if (rest)
4279ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
42807109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4281ed9f3e25SDouglas Gilbert fini:
4282ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4283ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4284ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4285ed9f3e25SDouglas Gilbert }
4286ed9f3e25SDouglas Gilbert 
4287fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4288fb0cc8d1SDouglas Gilbert 
42898d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
42908d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
42918d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
42928d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
42938d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
42948d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
42958d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
42968d039e22SDouglas Gilbert  */
42971da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
42981da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
42991da177e4SLinus Torvalds {
430001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
43018d039e22SDouglas Gilbert 	unsigned int alloc_len;
43028d039e22SDouglas Gilbert 	unsigned char select_report;
43038d039e22SDouglas Gilbert 	u64 lun;
43048d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4305fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
43068d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
43078d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
43088d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
43098d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4310fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4311fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4312fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
43131da177e4SLinus Torvalds 
431419c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
43158d039e22SDouglas Gilbert 
43168d039e22SDouglas Gilbert 	select_report = cmd[2];
43178d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
43188d039e22SDouglas Gilbert 
43198d039e22SDouglas Gilbert 	if (alloc_len < 4) {
43208d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
43218d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
43221da177e4SLinus Torvalds 		return check_condition_result;
43231da177e4SLinus Torvalds 	}
43248d039e22SDouglas Gilbert 
43258d039e22SDouglas Gilbert 	switch (select_report) {
43268d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4327773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43288d039e22SDouglas Gilbert 		wlun_cnt = 0;
43298d039e22SDouglas Gilbert 		break;
43308d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4331c65b1445SDouglas Gilbert 		lun_cnt = 0;
43328d039e22SDouglas Gilbert 		wlun_cnt = 1;
43338d039e22SDouglas Gilbert 		break;
43348d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
43358d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43368d039e22SDouglas Gilbert 		wlun_cnt = 1;
43378d039e22SDouglas Gilbert 		break;
43388d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
43398d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
43408d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
43418d039e22SDouglas Gilbert 	default:
43428d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
43438d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
43448d039e22SDouglas Gilbert 		return check_condition_result;
43458d039e22SDouglas Gilbert 	}
43468d039e22SDouglas Gilbert 
43478d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4348c65b1445SDouglas Gilbert 		--lun_cnt;
43498d039e22SDouglas Gilbert 
43508d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4351fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4352fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
43538d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
43548d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
43558d039e22SDouglas Gilbert 
4356fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
43578d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4358fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4359fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4360fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4361fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4362fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4363fb0cc8d1SDouglas Gilbert 			++lun_p;
4364fb0cc8d1SDouglas Gilbert 			j = 1;
4365fb0cc8d1SDouglas Gilbert 		}
4366fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4367fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4368fb0cc8d1SDouglas Gilbert 				break;
4369fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4370ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4371ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4372fb0cc8d1SDouglas Gilbert 		}
4373fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4374fb0cc8d1SDouglas Gilbert 			break;
4375fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4376fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4377fb0cc8d1SDouglas Gilbert 		if (res)
4378fb0cc8d1SDouglas Gilbert 			return res;
4379fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4380fb0cc8d1SDouglas Gilbert 	}
4381fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4382fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4383fb0cc8d1SDouglas Gilbert 		++j;
4384fb0cc8d1SDouglas Gilbert 	}
4385fb0cc8d1SDouglas Gilbert 	if (j > 0)
4386fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
43878d039e22SDouglas Gilbert 	return res;
43881da177e4SLinus Torvalds }
43891da177e4SLinus Torvalds 
4390c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4391c3e2fe92SDouglas Gilbert {
4392c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4393c3e2fe92SDouglas Gilbert 	u8 bytchk;
4394c3e2fe92SDouglas Gilbert 	int ret, j;
4395c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4396c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4397c3e2fe92SDouglas Gilbert 	u64 lba;
4398c3e2fe92SDouglas Gilbert 	u8 *arr;
4399c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4400b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4401c3e2fe92SDouglas Gilbert 
4402c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4403c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4404c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4405c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4406c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4407c3e2fe92SDouglas Gilbert 		return check_condition_result;
4408c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4409c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4410c3e2fe92SDouglas Gilbert 	}
4411c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4412c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4413c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4414c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4415c3e2fe92SDouglas Gilbert 		break;
4416c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4417c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4418c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4419c3e2fe92SDouglas Gilbert 		break;
4420c3e2fe92SDouglas Gilbert 	default:
4421c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4422c3e2fe92SDouglas Gilbert 		return check_condition_result;
4423c3e2fe92SDouglas Gilbert 	}
44243344b58bSGeorge Kennedy 	if (vnum == 0)
44253344b58bSGeorge Kennedy 		return 0;	/* not an error */
4426c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4427c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4428c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4429c3e2fe92SDouglas Gilbert 	if (ret)
4430c3e2fe92SDouglas Gilbert 		return ret;
4431c3e2fe92SDouglas Gilbert 
4432ed0f17b7SHarshit Mogalapalli 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN);
4433c3e2fe92SDouglas Gilbert 	if (!arr) {
4434c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4435c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4436c3e2fe92SDouglas Gilbert 		return check_condition_result;
4437c3e2fe92SDouglas Gilbert 	}
4438c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
44397109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4440c3e2fe92SDouglas Gilbert 
4441c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4442c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4443c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4444c3e2fe92SDouglas Gilbert 		goto cleanup;
4445c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4446c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4447c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4448c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4449c3e2fe92SDouglas Gilbert 	}
4450c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4451c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4452c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4453c3e2fe92SDouglas Gilbert 	}
4454c3e2fe92SDouglas Gilbert 	ret = 0;
4455c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4456c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4457c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4458c3e2fe92SDouglas Gilbert 		goto cleanup;
4459c3e2fe92SDouglas Gilbert 	}
4460c3e2fe92SDouglas Gilbert cleanup:
44617109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4462c3e2fe92SDouglas Gilbert 	kfree(arr);
4463c3e2fe92SDouglas Gilbert 	return ret;
4464c3e2fe92SDouglas Gilbert }
4465c3e2fe92SDouglas Gilbert 
4466f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4467f0d1cf93SDouglas Gilbert 
4468897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */
4469f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4470f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4471f0d1cf93SDouglas Gilbert {
44724a5fc1c6SDamien Le Moal 	unsigned int rep_max_zones, nrz = 0;
4473f0d1cf93SDouglas Gilbert 	int ret = 0;
4474f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4475f0d1cf93SDouglas Gilbert 	bool partial;
4476f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4477f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4478f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
44794a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp = NULL;
4480b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4481f0d1cf93SDouglas Gilbert 
4482f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4483f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4484f0d1cf93SDouglas Gilbert 		return check_condition_result;
4485f0d1cf93SDouglas Gilbert 	}
4486f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4487f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
44883344b58bSGeorge Kennedy 	if (alloc_len == 0)
44893344b58bSGeorge Kennedy 		return 0;	/* not an error */
4490f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4491f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4492f0d1cf93SDouglas Gilbert 
4493f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4494f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4495f0d1cf93SDouglas Gilbert 		return check_condition_result;
4496f0d1cf93SDouglas Gilbert 	}
4497f0d1cf93SDouglas Gilbert 
44984a5fc1c6SDamien Le Moal 	rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
4499f0d1cf93SDouglas Gilbert 
4500*07f2ca13SHarshit Mogalapalli 	arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
4501f0d1cf93SDouglas Gilbert 	if (!arr) {
4502f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4503f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4504f0d1cf93SDouglas Gilbert 		return check_condition_result;
4505f0d1cf93SDouglas Gilbert 	}
4506f0d1cf93SDouglas Gilbert 
45077109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4508f0d1cf93SDouglas Gilbert 
4509f0d1cf93SDouglas Gilbert 	desc = arr + 64;
45104a5fc1c6SDamien Le Moal 	for (lba = zs_lba; lba < sdebug_capacity;
45114a5fc1c6SDamien Le Moal 	     lba = zsp->z_start + zsp->z_size) {
45124a5fc1c6SDamien Le Moal 		if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba))
4513f0d1cf93SDouglas Gilbert 			break;
4514f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4515f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4516f0d1cf93SDouglas Gilbert 		case 0x00:
4517f0d1cf93SDouglas Gilbert 			/* All zones */
4518f0d1cf93SDouglas Gilbert 			break;
4519f0d1cf93SDouglas Gilbert 		case 0x01:
4520f0d1cf93SDouglas Gilbert 			/* Empty zones */
4521f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4522f0d1cf93SDouglas Gilbert 				continue;
4523f0d1cf93SDouglas Gilbert 			break;
4524f0d1cf93SDouglas Gilbert 		case 0x02:
4525f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4526f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4527f0d1cf93SDouglas Gilbert 				continue;
4528f0d1cf93SDouglas Gilbert 			break;
4529f0d1cf93SDouglas Gilbert 		case 0x03:
4530f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4531f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4532f0d1cf93SDouglas Gilbert 				continue;
4533f0d1cf93SDouglas Gilbert 			break;
4534f0d1cf93SDouglas Gilbert 		case 0x04:
4535f0d1cf93SDouglas Gilbert 			/* Closed zones */
4536f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4537f0d1cf93SDouglas Gilbert 				continue;
4538f0d1cf93SDouglas Gilbert 			break;
4539f0d1cf93SDouglas Gilbert 		case 0x05:
4540f0d1cf93SDouglas Gilbert 			/* Full zones */
4541f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4542f0d1cf93SDouglas Gilbert 				continue;
4543f0d1cf93SDouglas Gilbert 			break;
4544f0d1cf93SDouglas Gilbert 		case 0x06:
4545f0d1cf93SDouglas Gilbert 		case 0x07:
4546f0d1cf93SDouglas Gilbert 		case 0x10:
4547f0d1cf93SDouglas Gilbert 			/*
454864e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
454964e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4550f0d1cf93SDouglas Gilbert 			 */
4551f0d1cf93SDouglas Gilbert 			continue;
455264e14eceSDamien Le Moal 		case 0x11:
455364e14eceSDamien Le Moal 			/* non-seq-resource set */
455464e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
455564e14eceSDamien Le Moal 				continue;
455664e14eceSDamien Le Moal 			break;
45574a5fc1c6SDamien Le Moal 		case 0x3e:
45584a5fc1c6SDamien Le Moal 			/* All zones except gap zones. */
45594a5fc1c6SDamien Le Moal 			if (zbc_zone_is_gap(zsp))
45604a5fc1c6SDamien Le Moal 				continue;
45614a5fc1c6SDamien Le Moal 			break;
4562f0d1cf93SDouglas Gilbert 		case 0x3f:
4563f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
45644a5fc1c6SDamien Le Moal 			if (zbc_zone_is_seq(zsp))
4565f0d1cf93SDouglas Gilbert 				continue;
4566f0d1cf93SDouglas Gilbert 			break;
4567f0d1cf93SDouglas Gilbert 		default:
4568f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4569f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4570f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4571f0d1cf93SDouglas Gilbert 			goto fini;
4572f0d1cf93SDouglas Gilbert 		}
4573f0d1cf93SDouglas Gilbert 
4574f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4575f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
457664e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4577f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
457864e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
457964e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4580f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4581f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4582f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4583f0d1cf93SDouglas Gilbert 			desc += 64;
4584f0d1cf93SDouglas Gilbert 		}
4585f0d1cf93SDouglas Gilbert 
4586f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4587f0d1cf93SDouglas Gilbert 			break;
4588f0d1cf93SDouglas Gilbert 
4589f0d1cf93SDouglas Gilbert 		nrz++;
4590f0d1cf93SDouglas Gilbert 	}
4591f0d1cf93SDouglas Gilbert 
4592f0d1cf93SDouglas Gilbert 	/* Report header */
45934a5fc1c6SDamien Le Moal 	/* Zone list length. */
4594f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
45954a5fc1c6SDamien Le Moal 	/* Maximum LBA */
4596f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
45974a5fc1c6SDamien Le Moal 	/* Zone starting LBA granularity. */
45984a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
45994a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, arr + 16);
4600f0d1cf93SDouglas Gilbert 
4601f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
460236e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4603f0d1cf93SDouglas Gilbert 
4604f0d1cf93SDouglas Gilbert fini:
46057109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4606f0d1cf93SDouglas Gilbert 	kfree(arr);
4607f0d1cf93SDouglas Gilbert 	return ret;
4608f0d1cf93SDouglas Gilbert }
4609f0d1cf93SDouglas Gilbert 
4610f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4611f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4612f0d1cf93SDouglas Gilbert {
4613f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4614f0d1cf93SDouglas Gilbert 	unsigned int i;
4615f0d1cf93SDouglas Gilbert 
4616f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4617f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4618f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4619f0d1cf93SDouglas Gilbert 	}
4620f0d1cf93SDouglas Gilbert }
4621f0d1cf93SDouglas Gilbert 
4622f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4623f0d1cf93SDouglas Gilbert {
4624f0d1cf93SDouglas Gilbert 	int res = 0;
4625f0d1cf93SDouglas Gilbert 	u64 z_id;
4626f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4627f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4628f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4629f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4630b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4631f0d1cf93SDouglas Gilbert 
4632f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4633f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4634f0d1cf93SDouglas Gilbert 		return check_condition_result;
4635f0d1cf93SDouglas Gilbert 	}
4636f0d1cf93SDouglas Gilbert 
46377109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4638f0d1cf93SDouglas Gilbert 
4639f0d1cf93SDouglas Gilbert 	if (all) {
4640f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4641f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4642f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4643f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4644f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4645f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4646f0d1cf93SDouglas Gilbert 			goto fini;
4647f0d1cf93SDouglas Gilbert 		}
4648f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4649f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4650f0d1cf93SDouglas Gilbert 		goto fini;
4651f0d1cf93SDouglas Gilbert 	}
4652f0d1cf93SDouglas Gilbert 
4653f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4654f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4655f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4656f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4657f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4658f0d1cf93SDouglas Gilbert 		goto fini;
4659f0d1cf93SDouglas Gilbert 	}
4660f0d1cf93SDouglas Gilbert 
4661f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4662f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4663f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4664f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4665f0d1cf93SDouglas Gilbert 		goto fini;
4666f0d1cf93SDouglas Gilbert 	}
4667f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4668f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4669f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4670f0d1cf93SDouglas Gilbert 		goto fini;
4671f0d1cf93SDouglas Gilbert 	}
4672f0d1cf93SDouglas Gilbert 
4673f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4674f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4675f0d1cf93SDouglas Gilbert 		goto fini;
4676f0d1cf93SDouglas Gilbert 
4677f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4678f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4679f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4680f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4681f0d1cf93SDouglas Gilbert 		goto fini;
4682f0d1cf93SDouglas Gilbert 	}
4683f0d1cf93SDouglas Gilbert 
4684f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4685f0d1cf93SDouglas Gilbert fini:
46867109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4687f0d1cf93SDouglas Gilbert 	return res;
4688f0d1cf93SDouglas Gilbert }
4689f0d1cf93SDouglas Gilbert 
4690f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4691f0d1cf93SDouglas Gilbert {
4692f0d1cf93SDouglas Gilbert 	unsigned int i;
4693f0d1cf93SDouglas Gilbert 
4694f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4695f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4696f0d1cf93SDouglas Gilbert }
4697f0d1cf93SDouglas Gilbert 
4698f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4699f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4700f0d1cf93SDouglas Gilbert {
4701f0d1cf93SDouglas Gilbert 	int res = 0;
4702f0d1cf93SDouglas Gilbert 	u64 z_id;
4703f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4704f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4705f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4706b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4707f0d1cf93SDouglas Gilbert 
4708f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4709f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4710f0d1cf93SDouglas Gilbert 		return check_condition_result;
4711f0d1cf93SDouglas Gilbert 	}
4712f0d1cf93SDouglas Gilbert 
47137109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4714f0d1cf93SDouglas Gilbert 
4715f0d1cf93SDouglas Gilbert 	if (all) {
4716f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4717f0d1cf93SDouglas Gilbert 		goto fini;
4718f0d1cf93SDouglas Gilbert 	}
4719f0d1cf93SDouglas Gilbert 
4720f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4721f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4722f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4723f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4724f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4725f0d1cf93SDouglas Gilbert 		goto fini;
4726f0d1cf93SDouglas Gilbert 	}
4727f0d1cf93SDouglas Gilbert 
4728f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4729f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4730f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4731f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4732f0d1cf93SDouglas Gilbert 		goto fini;
4733f0d1cf93SDouglas Gilbert 	}
4734f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4735f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4736f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4737f0d1cf93SDouglas Gilbert 		goto fini;
4738f0d1cf93SDouglas Gilbert 	}
4739f0d1cf93SDouglas Gilbert 
4740f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4741f0d1cf93SDouglas Gilbert fini:
47427109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4743f0d1cf93SDouglas Gilbert 	return res;
4744f0d1cf93SDouglas Gilbert }
4745f0d1cf93SDouglas Gilbert 
4746f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4747f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4748f0d1cf93SDouglas Gilbert {
4749f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4750f0d1cf93SDouglas Gilbert 
4751f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4752f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4753f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4754f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4755f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4756f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4757f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4758f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4759f0d1cf93SDouglas Gilbert 	}
4760f0d1cf93SDouglas Gilbert }
4761f0d1cf93SDouglas Gilbert 
4762f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4763f0d1cf93SDouglas Gilbert {
4764f0d1cf93SDouglas Gilbert 	unsigned int i;
4765f0d1cf93SDouglas Gilbert 
4766f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4767f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4768f0d1cf93SDouglas Gilbert }
4769f0d1cf93SDouglas Gilbert 
4770f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4771f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4772f0d1cf93SDouglas Gilbert {
4773f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4774f0d1cf93SDouglas Gilbert 	int res = 0;
4775f0d1cf93SDouglas Gilbert 	u64 z_id;
4776f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4777f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4778b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4779f0d1cf93SDouglas Gilbert 
4780f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4781f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4782f0d1cf93SDouglas Gilbert 		return check_condition_result;
4783f0d1cf93SDouglas Gilbert 	}
4784f0d1cf93SDouglas Gilbert 
47857109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4786f0d1cf93SDouglas Gilbert 
4787f0d1cf93SDouglas Gilbert 	if (all) {
4788f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4789f0d1cf93SDouglas Gilbert 		goto fini;
4790f0d1cf93SDouglas Gilbert 	}
4791f0d1cf93SDouglas Gilbert 
4792f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4793f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4794f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4795f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4796f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4797f0d1cf93SDouglas Gilbert 		goto fini;
4798f0d1cf93SDouglas Gilbert 	}
4799f0d1cf93SDouglas Gilbert 
4800f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4801f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4802f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4803f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4804f0d1cf93SDouglas Gilbert 		goto fini;
4805f0d1cf93SDouglas Gilbert 	}
4806f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4807f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4808f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4809f0d1cf93SDouglas Gilbert 		goto fini;
4810f0d1cf93SDouglas Gilbert 	}
4811f0d1cf93SDouglas Gilbert 
4812f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4813f0d1cf93SDouglas Gilbert fini:
48147109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4815f0d1cf93SDouglas Gilbert 	return res;
4816f0d1cf93SDouglas Gilbert }
4817f0d1cf93SDouglas Gilbert 
4818f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4819f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4820f0d1cf93SDouglas Gilbert {
4821f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
48222d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4823f0d1cf93SDouglas Gilbert 
48244a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
4825f0d1cf93SDouglas Gilbert 		return;
4826f0d1cf93SDouglas Gilbert 
4827f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4828f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4829f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4830f0d1cf93SDouglas Gilbert 
4831f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4832f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4833f0d1cf93SDouglas Gilbert 
48342d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
48352d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
48362d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
48372d62253eSShin'ichiro Kawasaki 
483864e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4839f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4840f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4841f0d1cf93SDouglas Gilbert }
4842f0d1cf93SDouglas Gilbert 
4843f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4844f0d1cf93SDouglas Gilbert {
4845f0d1cf93SDouglas Gilbert 	unsigned int i;
4846f0d1cf93SDouglas Gilbert 
4847f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4848f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4849f0d1cf93SDouglas Gilbert }
4850f0d1cf93SDouglas Gilbert 
4851f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4852f0d1cf93SDouglas Gilbert {
4853f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4854f0d1cf93SDouglas Gilbert 	int res = 0;
4855f0d1cf93SDouglas Gilbert 	u64 z_id;
4856f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4857f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4858b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4859f0d1cf93SDouglas Gilbert 
4860f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4861f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4862f0d1cf93SDouglas Gilbert 		return check_condition_result;
4863f0d1cf93SDouglas Gilbert 	}
4864f0d1cf93SDouglas Gilbert 
48657109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4866f0d1cf93SDouglas Gilbert 
4867f0d1cf93SDouglas Gilbert 	if (all) {
4868f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4869f0d1cf93SDouglas Gilbert 		goto fini;
4870f0d1cf93SDouglas Gilbert 	}
4871f0d1cf93SDouglas Gilbert 
4872f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4873f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4874f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4875f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4876f0d1cf93SDouglas Gilbert 		goto fini;
4877f0d1cf93SDouglas Gilbert 	}
4878f0d1cf93SDouglas Gilbert 
4879f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4880f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4881f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4882f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4883f0d1cf93SDouglas Gilbert 		goto fini;
4884f0d1cf93SDouglas Gilbert 	}
4885f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4886f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4887f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4888f0d1cf93SDouglas Gilbert 		goto fini;
4889f0d1cf93SDouglas Gilbert 	}
4890f0d1cf93SDouglas Gilbert 
4891f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4892f0d1cf93SDouglas Gilbert fini:
48937109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4894f0d1cf93SDouglas Gilbert 	return res;
4895f0d1cf93SDouglas Gilbert }
4896f0d1cf93SDouglas Gilbert 
4897c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4898c4837394SDouglas Gilbert {
4899c10fa55fSJohn Garry 	u16 hwq;
4900a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4901c10fa55fSJohn Garry 
4902c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4903c4837394SDouglas Gilbert 
4904458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4905458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4906458df78bSBart Van Assche 		hwq = 0;
4907f7c4cdc7SJohn Garry 
4908458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4909c4837394SDouglas Gilbert }
4910c4837394SDouglas Gilbert 
4911c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4912c10fa55fSJohn Garry {
4913a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4914c10fa55fSJohn Garry }
4915c10fa55fSJohn Garry 
4916c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4917fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
49181da177e4SLinus Torvalds {
49197382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4920c4837394SDouglas Gilbert 	int qc_idx;
4921cbf67842SDouglas Gilbert 	int retiring = 0;
49221da177e4SLinus Torvalds 	unsigned long iflags;
4923c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4924cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4925cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4926cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
49271da177e4SLinus Torvalds 
49287382f9d8SDouglas Gilbert 	if (unlikely(aborted))
49297382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4930c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4931c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4932c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4933cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4934c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4935c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4936c4837394SDouglas Gilbert 	}
4937c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4938c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
49391da177e4SLinus Torvalds 		return;
49401da177e4SLinus Torvalds 	}
4941c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4942d9d23a5aSDouglas Gilbert 	WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
4943c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4944cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4945b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4946c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4947c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4948c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
49491da177e4SLinus Torvalds 		return;
49501da177e4SLinus Torvalds 	}
4951cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4952f46eb0e9SDouglas Gilbert 	if (likely(devip))
4953cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4954cbf67842SDouglas Gilbert 	else
4955c1287970STomas Winkler 		pr_err("devip=NULL\n");
4956f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4957cbf67842SDouglas Gilbert 		retiring = 1;
4958cbf67842SDouglas Gilbert 
4959cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4960c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4961c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4962c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4963cbf67842SDouglas Gilbert 		return;
49641da177e4SLinus Torvalds 	}
49651da177e4SLinus Torvalds 
4966cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4967cbf67842SDouglas Gilbert 		int k, retval;
4968cbf67842SDouglas Gilbert 
4969cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4970c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4971c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4972c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4973cbf67842SDouglas Gilbert 			return;
4974cbf67842SDouglas Gilbert 		}
4975c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4976773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4977cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4978cbf67842SDouglas Gilbert 		else
4979cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4980cbf67842SDouglas Gilbert 	}
4981c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
49827382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
49837382f9d8SDouglas Gilbert 		if (sdebug_verbose)
49847382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
49857382f9d8SDouglas Gilbert 		return;
49867382f9d8SDouglas Gilbert 	}
49876c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
4988cbf67842SDouglas Gilbert }
4989cbf67842SDouglas Gilbert 
4990cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4991fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4992cbf67842SDouglas Gilbert {
4993a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4994a10bc12aSDouglas Gilbert 						  hrt);
4995a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4996cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4997cbf67842SDouglas Gilbert }
49981da177e4SLinus Torvalds 
4999a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
5000fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
5001a10bc12aSDouglas Gilbert {
5002a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
5003a10bc12aSDouglas Gilbert 						  ew.work);
5004a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5005a10bc12aSDouglas Gilbert }
5006a10bc12aSDouglas Gilbert 
500709ba24c1SDouglas Gilbert static bool got_shared_uuid;
5008bf476433SChristoph Hellwig static uuid_t shared_uuid;
500909ba24c1SDouglas Gilbert 
5010f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
5011f0d1cf93SDouglas Gilbert {
5012f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
5013f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
50144a5fc1c6SDamien Le Moal 	sector_t conv_capacity;
5015f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
5016f0d1cf93SDouglas Gilbert 	unsigned int i;
5017f0d1cf93SDouglas Gilbert 
5018f0d1cf93SDouglas Gilbert 	/*
501998e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
502098e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
5021f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
5022f0d1cf93SDouglas Gilbert 	 * created for the device.
5023f0d1cf93SDouglas Gilbert 	 */
502498e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
5025f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
5026f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5027f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
5028f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
5029f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
5030f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
5031f0d1cf93SDouglas Gilbert 			return -EINVAL;
5032f0d1cf93SDouglas Gilbert 		}
5033f0d1cf93SDouglas Gilbert 	} else {
5034108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
5035108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
5036108e36f0SDamien Le Moal 			return -EINVAL;
5037108e36f0SDamien Le Moal 		}
503898e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
5039f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5040f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
5041f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
5042f0d1cf93SDouglas Gilbert 			return -EINVAL;
5043f0d1cf93SDouglas Gilbert 		}
5044f0d1cf93SDouglas Gilbert 	}
5045f0d1cf93SDouglas Gilbert 
5046f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
5047f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
5048f0d1cf93SDouglas Gilbert 
50494a5fc1c6SDamien Le Moal 	if (sdeb_zbc_zone_cap_mb == 0) {
50504a5fc1c6SDamien Le Moal 		devip->zcap = devip->zsize;
50514a5fc1c6SDamien Le Moal 	} else {
50524a5fc1c6SDamien Le Moal 		devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >>
50534a5fc1c6SDamien Le Moal 			      ilog2(sdebug_sector_size);
50544a5fc1c6SDamien Le Moal 		if (devip->zcap > devip->zsize) {
50554a5fc1c6SDamien Le Moal 			pr_err("Zone capacity too large\n");
50564a5fc1c6SDamien Le Moal 			return -EINVAL;
50574a5fc1c6SDamien Le Moal 		}
50584a5fc1c6SDamien Le Moal 	}
50594a5fc1c6SDamien Le Moal 
50604a5fc1c6SDamien Le Moal 	conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift;
50614a5fc1c6SDamien Le Moal 	if (conv_capacity >= capacity) {
5062aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
5063aa8fecf9SDamien Le Moal 		return -EINVAL;
5064aa8fecf9SDamien Le Moal 	}
5065aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
50664a5fc1c6SDamien Le Moal 	devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >>
50674a5fc1c6SDamien Le Moal 			      devip->zsize_shift;
50684a5fc1c6SDamien Le Moal 	devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones;
50694a5fc1c6SDamien Le Moal 
50704a5fc1c6SDamien Le Moal 	/* Add gap zones if zone capacity is smaller than the zone size */
50714a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
50724a5fc1c6SDamien Le Moal 		devip->nr_zones += devip->nr_seq_zones;
5073aa8fecf9SDamien Le Moal 
507464e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
507564e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
5076380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
5077f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
5078f0d1cf93SDouglas Gilbert 		else
5079380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
508064e14eceSDamien Le Moal 	}
5081f0d1cf93SDouglas Gilbert 
5082f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
5083f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
5084f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
5085f0d1cf93SDouglas Gilbert 		return -ENOMEM;
5086f0d1cf93SDouglas Gilbert 
5087f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
5088f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
5089f0d1cf93SDouglas Gilbert 
5090f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
5091f0d1cf93SDouglas Gilbert 
5092aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
509335dbe2b9SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_CNV;
5094f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
5095f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
50964a5fc1c6SDamien Le Moal 			zsp->z_size =
50974a5fc1c6SDamien Le Moal 				min_t(u64, devip->zsize, capacity - zstart);
50984a5fc1c6SDamien Le Moal 		} else if ((zstart & (devip->zsize - 1)) == 0) {
509964e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
510035dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWR;
510164e14eceSDamien Le Moal 			else
510235dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWP;
5103f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
5104f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
51054a5fc1c6SDamien Le Moal 			zsp->z_size =
51064a5fc1c6SDamien Le Moal 				min_t(u64, devip->zcap, capacity - zstart);
51074a5fc1c6SDamien Le Moal 		} else {
51084a5fc1c6SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_GAP;
51094a5fc1c6SDamien Le Moal 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
51104a5fc1c6SDamien Le Moal 			zsp->z_wp = (sector_t)-1;
51114a5fc1c6SDamien Le Moal 			zsp->z_size = min_t(u64, devip->zsize - devip->zcap,
51124a5fc1c6SDamien Le Moal 					    capacity - zstart);
5113f0d1cf93SDouglas Gilbert 		}
5114f0d1cf93SDouglas Gilbert 
51154a5fc1c6SDamien Le Moal 		WARN_ON_ONCE((int)zsp->z_size <= 0);
5116f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
5117f0d1cf93SDouglas Gilbert 	}
5118f0d1cf93SDouglas Gilbert 
5119f0d1cf93SDouglas Gilbert 	return 0;
5120f0d1cf93SDouglas Gilbert }
5121f0d1cf93SDouglas Gilbert 
5122fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
5123fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
51245cb2fc06SFUJITA Tomonori {
51255cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
51265cb2fc06SFUJITA Tomonori 
51275cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
51285cb2fc06SFUJITA Tomonori 	if (devip) {
512909ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
5130bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
513109ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
513209ba24c1SDouglas Gilbert 			if (got_shared_uuid)
513309ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
513409ba24c1SDouglas Gilbert 			else {
5135bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
513609ba24c1SDouglas Gilbert 				got_shared_uuid = true;
513709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
513809ba24c1SDouglas Gilbert 			}
513909ba24c1SDouglas Gilbert 		}
51405cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
5141f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
514264e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
5143f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
5144f0d1cf93SDouglas Gilbert 				kfree(devip);
5145f0d1cf93SDouglas Gilbert 				return NULL;
5146f0d1cf93SDouglas Gilbert 			}
514764e14eceSDamien Le Moal 		} else {
514864e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
5149f0d1cf93SDouglas Gilbert 		}
5150f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
5151fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
5152fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
51535cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
51545cb2fc06SFUJITA Tomonori 	}
51555cb2fc06SFUJITA Tomonori 	return devip;
51565cb2fc06SFUJITA Tomonori }
51575cb2fc06SFUJITA Tomonori 
5158f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
51591da177e4SLinus Torvalds {
51601da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51611da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
5162f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
51631da177e4SLinus Torvalds 
5164d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
51651da177e4SLinus Torvalds 	if (!sdbg_host) {
5166c1287970STomas Winkler 		pr_err("Host info NULL\n");
51671da177e4SLinus Torvalds 		return NULL;
51681da177e4SLinus Torvalds 	}
5169ad0c7775SDouglas Gilbert 
51701da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
51711da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
51721da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
51731da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
51741da177e4SLinus Torvalds 			return devip;
51751da177e4SLinus Torvalds 		else {
51761da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
51771da177e4SLinus Torvalds 				open_devip = devip;
51781da177e4SLinus Torvalds 		}
51791da177e4SLinus Torvalds 	}
51805cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
51815cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
51825cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5183c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51841da177e4SLinus Torvalds 			return NULL;
51851da177e4SLinus Torvalds 		}
51861da177e4SLinus Torvalds 	}
5187a75869d1SFUJITA Tomonori 
51881da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
51891da177e4SLinus Torvalds 	open_devip->target = sdev->id;
51901da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
51911da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5192cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
5193500d0d24SDouglas Gilbert 	set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
5194c2248fc9SDouglas Gilbert 	open_devip->used = true;
51951da177e4SLinus Torvalds 	return open_devip;
51961da177e4SLinus Torvalds }
51971da177e4SLinus Torvalds 
51988dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
51991da177e4SLinus Torvalds {
5200773642d9SDouglas Gilbert 	if (sdebug_verbose)
5201c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
52028dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52038dea0d02SFUJITA Tomonori 	return 0;
52048dea0d02SFUJITA Tomonori }
52051da177e4SLinus Torvalds 
52068dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
52078dea0d02SFUJITA Tomonori {
5208f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5209f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5210a34c4e98SFUJITA Tomonori 
5211773642d9SDouglas Gilbert 	if (sdebug_verbose)
5212c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
52138dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5214b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5215b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5216b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5217f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5218b01f6f83SDouglas Gilbert 		if (devip == NULL)
52198dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5220f46eb0e9SDouglas Gilbert 	}
5221c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5222773642d9SDouglas Gilbert 	if (sdebug_no_uld)
522378d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
52249b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
52258dea0d02SFUJITA Tomonori 	return 0;
52268dea0d02SFUJITA Tomonori }
52278dea0d02SFUJITA Tomonori 
52288dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
52298dea0d02SFUJITA Tomonori {
52308dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
52318dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
52328dea0d02SFUJITA Tomonori 
5233773642d9SDouglas Gilbert 	if (sdebug_verbose)
5234c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
52358dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52368dea0d02SFUJITA Tomonori 	if (devip) {
523725985edcSLucas De Marchi 		/* make this slot available for re-use */
5238c2248fc9SDouglas Gilbert 		devip->used = false;
52398dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
52408dea0d02SFUJITA Tomonori 	}
52418dea0d02SFUJITA Tomonori }
52428dea0d02SFUJITA Tomonori 
524310bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
524410bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5245c4837394SDouglas Gilbert {
5246c4837394SDouglas Gilbert 	if (!sd_dp)
5247c4837394SDouglas Gilbert 		return;
524810bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5249c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
525010bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5251c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5252c4837394SDouglas Gilbert }
5253c4837394SDouglas Gilbert 
5254a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5255a10bc12aSDouglas Gilbert    returns false */
5256a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
52578dea0d02SFUJITA Tomonori {
52588dea0d02SFUJITA Tomonori 	unsigned long iflags;
5259c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
526010bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5261c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
52628dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5263cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5264a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
52658dea0d02SFUJITA Tomonori 
5266c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5267c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5268773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5269cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5270cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5271cbf67842SDouglas Gilbert 			qmax = r_qmax;
5272cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5273c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5274c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5275a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5276a10bc12aSDouglas Gilbert 					continue;
5277c4837394SDouglas Gilbert 				/* found */
5278db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5279db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5280db525fceSDouglas Gilbert 				if (devip)
5281db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5282db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5283a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
528410bde980SDouglas Gilbert 				if (sd_dp) {
5285d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5286d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
528710bde980SDouglas Gilbert 				} else
528810bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5289c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
529010bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5291c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5292a10bc12aSDouglas Gilbert 				return true;
52938dea0d02SFUJITA Tomonori 			}
5294cbf67842SDouglas Gilbert 		}
5295c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5296c4837394SDouglas Gilbert 	}
5297a10bc12aSDouglas Gilbert 	return false;
52988dea0d02SFUJITA Tomonori }
52998dea0d02SFUJITA Tomonori 
5300a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
5301f19fe8f3SBart Van Assche static void stop_all_queued(void)
53028dea0d02SFUJITA Tomonori {
53038dea0d02SFUJITA Tomonori 	unsigned long iflags;
5304c4837394SDouglas Gilbert 	int j, k;
530510bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5306c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
53078dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5308cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5309a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53108dea0d02SFUJITA Tomonori 
5311c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5312c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5313c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5314c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5315c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5316f19fe8f3SBart Van Assche 				if (sqcp->a_cmnd == NULL)
5317a10bc12aSDouglas Gilbert 					continue;
5318db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5319db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5320db525fceSDouglas Gilbert 				if (devip)
5321db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5322db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5323a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
532410bde980SDouglas Gilbert 				if (sd_dp) {
5325d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5326d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
532710bde980SDouglas Gilbert 				} else
532810bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5329c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
533010bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5331c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5332c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
53338dea0d02SFUJITA Tomonori 			}
53348dea0d02SFUJITA Tomonori 		}
5335c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5336c4837394SDouglas Gilbert 	}
5337cbf67842SDouglas Gilbert }
5338cbf67842SDouglas Gilbert 
5339cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5340cbf67842SDouglas Gilbert static void free_all_queued(void)
5341cbf67842SDouglas Gilbert {
5342c4837394SDouglas Gilbert 	int j, k;
5343c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5344cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5345cbf67842SDouglas Gilbert 
5346c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5347c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5348c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5349a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5350a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5351cbf67842SDouglas Gilbert 		}
53521da177e4SLinus Torvalds 	}
5353c4837394SDouglas Gilbert }
53541da177e4SLinus Torvalds 
53551da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
53561da177e4SLinus Torvalds {
5357a10bc12aSDouglas Gilbert 	bool ok;
5358a10bc12aSDouglas Gilbert 
53591da177e4SLinus Torvalds 	++num_aborts;
5360cbf67842SDouglas Gilbert 	if (SCpnt) {
5361a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5362a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5363a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5364a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5365a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5366cbf67842SDouglas Gilbert 	}
53671da177e4SLinus Torvalds 	return SUCCESS;
53681da177e4SLinus Torvalds }
53691da177e4SLinus Torvalds 
53701da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
53711da177e4SLinus Torvalds {
53721da177e4SLinus Torvalds 	++num_dev_resets;
5373cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5374cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5375f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5376f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5377cbf67842SDouglas Gilbert 
5378773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5379cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
53801da177e4SLinus Torvalds 		if (devip)
5381cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
53821da177e4SLinus Torvalds 	}
53831da177e4SLinus Torvalds 	return SUCCESS;
53841da177e4SLinus Torvalds }
53851da177e4SLinus Torvalds 
5386cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5387cbf67842SDouglas Gilbert {
5388cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5389cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5390cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5391cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5392cbf67842SDouglas Gilbert 	int k = 0;
5393cbf67842SDouglas Gilbert 
5394cbf67842SDouglas Gilbert 	++num_target_resets;
5395cbf67842SDouglas Gilbert 	if (!SCpnt)
5396cbf67842SDouglas Gilbert 		goto lie;
5397cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5398cbf67842SDouglas Gilbert 	if (!sdp)
5399cbf67842SDouglas Gilbert 		goto lie;
5400773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5401cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5402cbf67842SDouglas Gilbert 	hp = sdp->host;
5403cbf67842SDouglas Gilbert 	if (!hp)
5404cbf67842SDouglas Gilbert 		goto lie;
5405cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5406cbf67842SDouglas Gilbert 	if (sdbg_host) {
5407cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5408cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5409cbf67842SDouglas Gilbert 				    dev_list)
5410cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5411cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5412cbf67842SDouglas Gilbert 				++k;
5413cbf67842SDouglas Gilbert 			}
5414cbf67842SDouglas Gilbert 	}
5415773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5416cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5417cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5418cbf67842SDouglas Gilbert lie:
5419cbf67842SDouglas Gilbert 	return SUCCESS;
5420cbf67842SDouglas Gilbert }
5421cbf67842SDouglas Gilbert 
54221da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
54231da177e4SLinus Torvalds {
54241da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5425cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
54261da177e4SLinus Torvalds 	struct scsi_device *sdp;
54271da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5428cbf67842SDouglas Gilbert 	int k = 0;
54291da177e4SLinus Torvalds 
54301da177e4SLinus Torvalds 	++num_bus_resets;
5431cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5432cbf67842SDouglas Gilbert 		goto lie;
5433cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5434773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5435cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5436cbf67842SDouglas Gilbert 	hp = sdp->host;
5437cbf67842SDouglas Gilbert 	if (hp) {
5438d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
54391da177e4SLinus Torvalds 		if (sdbg_host) {
5440cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
54411da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5442cbf67842SDouglas Gilbert 					    dev_list) {
5443cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5444cbf67842SDouglas Gilbert 				++k;
54451da177e4SLinus Torvalds 			}
54461da177e4SLinus Torvalds 		}
5447cbf67842SDouglas Gilbert 	}
5448773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5449cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5450cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5451cbf67842SDouglas Gilbert lie:
54521da177e4SLinus Torvalds 	return SUCCESS;
54531da177e4SLinus Torvalds }
54541da177e4SLinus Torvalds 
54551da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
54561da177e4SLinus Torvalds {
54571da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5458cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5459cbf67842SDouglas Gilbert 	int k = 0;
54601da177e4SLinus Torvalds 
54611da177e4SLinus Torvalds 	++num_host_resets;
5462773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5463cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
54641da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
54651da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5466cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5467cbf67842SDouglas Gilbert 				    dev_list) {
5468cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5469cbf67842SDouglas Gilbert 			++k;
5470cbf67842SDouglas Gilbert 		}
54711da177e4SLinus Torvalds 	}
54721da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
5473f19fe8f3SBart Van Assche 	stop_all_queued();
5474773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5475cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5476cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
54771da177e4SLinus Torvalds 	return SUCCESS;
54781da177e4SLinus Torvalds }
54791da177e4SLinus Torvalds 
548087c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
54811da177e4SLinus Torvalds {
54821442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5483979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
54841da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
54851da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
54861da177e4SLinus Torvalds 
54871da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5488773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
54891da177e4SLinus Torvalds 		return;
5490773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5491773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5492c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
54931da177e4SLinus Torvalds 	}
54948c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
54951da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5496773642d9SDouglas Gilbert 			   / sdebug_num_parts;
54971da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
54981da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5499979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5500979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
55011da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
55021da177e4SLinus Torvalds 			    * heads_by_sects;
5503979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5504979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5505979e0dc3SJohn Pittman 	}
5506773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5507773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
55081da177e4SLinus Torvalds 
55091da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
55101da177e4SLinus Torvalds 	ramp[511] = 0xAA;
55111442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
55121da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
55131da177e4SLinus Torvalds 		start_sec = starts[k];
5514979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
55151da177e4SLinus Torvalds 		pp->boot_ind = 0;
55161da177e4SLinus Torvalds 
55171da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
55181da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
55191da177e4SLinus Torvalds 			   / sdebug_sectors_per;
55201da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
55211da177e4SLinus Torvalds 
55221da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
55231da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
55241da177e4SLinus Torvalds 			       / sdebug_sectors_per;
55251da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
55261da177e4SLinus Torvalds 
5527150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5528150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
55291da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
55301da177e4SLinus Torvalds 	}
55311da177e4SLinus Torvalds }
55321da177e4SLinus Torvalds 
5533f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block)
5534c4837394SDouglas Gilbert {
5535c4837394SDouglas Gilbert 	int j;
5536c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5537c4837394SDouglas Gilbert 
5538c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5539f19fe8f3SBart Van Assche 		atomic_set(&sqp->blocked, (int)block);
5540c4837394SDouglas Gilbert }
5541c4837394SDouglas Gilbert 
5542c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5543c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5544c4837394SDouglas Gilbert  */
5545c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5546c4837394SDouglas Gilbert {
5547c4837394SDouglas Gilbert 	int count, modulo;
5548c4837394SDouglas Gilbert 
5549c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5550c4837394SDouglas Gilbert 	if (modulo < 2)
5551c4837394SDouglas Gilbert 		return;
5552f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
5553c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5554c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5555f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
5556c4837394SDouglas Gilbert }
5557c4837394SDouglas Gilbert 
5558c4837394SDouglas Gilbert static void clear_queue_stats(void)
5559c4837394SDouglas Gilbert {
5560c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5561c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5562c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5563c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5564c4837394SDouglas Gilbert }
5565c4837394SDouglas Gilbert 
55663a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5567c4837394SDouglas Gilbert {
55683a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
55693a90a63dSDouglas Gilbert 		return false;
55703a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5571c4837394SDouglas Gilbert }
5572c4837394SDouglas Gilbert 
5573a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5574a2aede97SDouglas Gilbert 
5575c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5576c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5577c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5578c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5579c4837394SDouglas Gilbert  */
5580fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5581f66b8517SMartin Wilck 			 int scsi_result,
5582f19fe8f3SBart Van Assche 			 int (*pfp)(struct scsi_cmnd *,
5583f19fe8f3SBart Van Assche 				    struct sdebug_dev_info *),
5584f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
55851da177e4SLinus Torvalds {
5586a2aede97SDouglas Gilbert 	bool new_sd_dp;
55873a90a63dSDouglas Gilbert 	bool inject = false;
55886ce913feSChristoph Hellwig 	bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED;
55893a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5590a2aede97SDouglas Gilbert 	unsigned long iflags;
5591a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5592c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5593c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5594299b6c07STomas Winkler 	struct scsi_device *sdp;
5595a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
55961da177e4SLinus Torvalds 
5597b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5598b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5599f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5600f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
56011da177e4SLinus Torvalds 	}
5602299b6c07STomas Winkler 	sdp = cmnd->device;
5603299b6c07STomas Winkler 
5604f19fe8f3SBart Van Assche 	if (delta_jiff == 0)
5605cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56061da177e4SLinus Torvalds 
5607c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5608c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5609c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5610c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5611c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5612c4837394SDouglas Gilbert 	}
5613cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5614cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5615f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5616cd62b7daSDouglas Gilbert 		if (scsi_result) {
5617c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5618cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5619cd62b7daSDouglas Gilbert 		} else
5620cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5621c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5622773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5623f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5624cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5625cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5626773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5627cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
56283a90a63dSDouglas Gilbert 			inject = true;
5629cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
56301da177e4SLinus Torvalds 		}
5631cbf67842SDouglas Gilbert 	}
5632cbf67842SDouglas Gilbert 
5633c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5634f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5635c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5636cd62b7daSDouglas Gilbert 		if (scsi_result)
5637cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5638cd62b7daSDouglas Gilbert 		scsi_result = device_qfull_result;
5639773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
56407d5a129bSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
56417d5a129bSDouglas Gilbert 				    __func__, sdebug_max_queue);
5642cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56431da177e4SLinus Torvalds 	}
564474595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5645cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5646c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
56471da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5648c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5649a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5650c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5651c4b57d89SKashyap Desai 
565274595c04SDouglas Gilbert 	if (!sd_dp) {
565310bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
565474595c04SDouglas Gilbert 		if (!sd_dp) {
565574595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
565674595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
565710bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
565874595c04SDouglas Gilbert 		}
5659a2aede97SDouglas Gilbert 		new_sd_dp = true;
5660a2aede97SDouglas Gilbert 	} else {
5661a2aede97SDouglas Gilbert 		new_sd_dp = false;
566210bde980SDouglas Gilbert 	}
5663f66b8517SMartin Wilck 
5664c10fa55fSJohn Garry 	/* Set the hostwide tag */
5665c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5666c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5667c10fa55fSJohn Garry 
56686ce913feSChristoph Hellwig 	if (polled)
5669a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5670a2aede97SDouglas Gilbert 
5671a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
56723a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5673f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5674f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5675f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5676f66b8517SMartin Wilck 	}
5677f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5678f66b8517SMartin Wilck 		cmnd->result = scsi_result;
56793a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
56803a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
56813a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
56823a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56833a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
56843a90a63dSDouglas Gilbert 		}
56853a90a63dSDouglas Gilbert 	}
5686f66b8517SMartin Wilck 
5687f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5688f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5689f66b8517SMartin Wilck 			    __func__, cmnd->result);
5690f66b8517SMartin Wilck 
569110bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5692b333a819SDouglas Gilbert 		ktime_t kt;
5693cbf67842SDouglas Gilbert 
5694b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
56950c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
56960c4bc91dSDouglas Gilbert 
56970c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
56980c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
56990c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
57000c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
57010c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
57020c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
57030c4bc91dSDouglas Gilbert 				ns <<= 12;
57040c4bc91dSDouglas Gilbert 			}
57050c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
57060c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
57070c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
57080c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5709a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5710a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5711a2aede97SDouglas Gilbert 
5712a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5713223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5714a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5715a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5716a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5717223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5718a2aede97SDouglas Gilbert 					if (new_sd_dp)
5719a2aede97SDouglas Gilbert 						kfree(sd_dp);
5720a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
57216c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5722a2aede97SDouglas Gilbert 					return 0;
5723a2aede97SDouglas Gilbert 				}
5724a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5725a2aede97SDouglas Gilbert 				kt -= d;
5726a2aede97SDouglas Gilbert 			}
57270c4bc91dSDouglas Gilbert 		}
57286ce913feSChristoph Hellwig 		if (polled) {
57294a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
57304a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57314a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57324a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57334a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57344a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57354a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57364a0c6f43SDouglas Gilbert 			}
5737d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57384a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57394a0c6f43SDouglas Gilbert 		} else {
574010bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
574110bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5742a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5743a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5744c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5745a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5746c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5747c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5748cbf67842SDouglas Gilbert 			}
5749d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
5750a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5751c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
57524a0c6f43SDouglas Gilbert 		}
57534a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
57544a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5755c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
57564a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
57574a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
57584a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
57596ce913feSChristoph Hellwig 		if (polled) {
57604a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
57614a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57624a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57634a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57644a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57654a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57664a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57674a0c6f43SDouglas Gilbert 			}
5768d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57694a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57704a0c6f43SDouglas Gilbert 		} else {
577110bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
577210bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5773a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5774c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5775c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5776a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5777cbf67842SDouglas Gilbert 			}
5778d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
57794a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
57804a0c6f43SDouglas Gilbert 		}
5781c4837394SDouglas Gilbert 		if (sdebug_statistics)
5782c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
57834a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
5784a6e76e6fSBart Van Assche 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5785a6e76e6fSBart Van Assche 				    scsi_cmd_to_rq(cmnd)->tag);
5786a6e76e6fSBart Van Assche 			blk_abort_request(scsi_cmd_to_rq(cmnd));
57873a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
57884a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
57897382f9d8SDouglas Gilbert 		}
5790cbf67842SDouglas Gilbert 	}
57913a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
57923a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
57933a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
57941da177e4SLinus Torvalds 	return 0;
5795cd62b7daSDouglas Gilbert 
5796cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5797f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5798f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5799f19fe8f3SBart Van Assche 	if (cmnd->result == 0 && scsi_result != 0)
5800cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
58016c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5802cd62b7daSDouglas Gilbert 	return 0;
58031da177e4SLinus Torvalds }
5804cbf67842SDouglas Gilbert 
580523183910SDouglas Gilbert /* Note: The following macros create attribute files in the
580623183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
580723183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
580823183910SDouglas Gilbert    as it can when the corresponding attribute in the
580923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
581023183910SDouglas Gilbert  */
5811773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5812773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
58139b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5814773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5815c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5816773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5817773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5818773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5819773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5820773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5821773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5822773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5823773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5824c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5825e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5826e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5827e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5828e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
58295d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
58305d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
58315d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5832773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5833773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5834773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5835773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5836ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5837773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5838773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
58395d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
58405d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58415d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
58425d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5843773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5844773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
58457109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
5846773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5847773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5848773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5849773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
58505d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5851773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
585287c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
585387c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5854773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5855773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
58560c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5857773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5858773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5859773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5860c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5861773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5862c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5863c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5864fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5865773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5866773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5867773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5868773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
586909ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
58705d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5871773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
587223183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58739447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5874773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
58755b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
58769267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
58774a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO);
5878380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5879aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
588098e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
58811da177e4SLinus Torvalds 
58821da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
58831da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
58841da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5885b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
58861da177e4SLinus Torvalds 
58875d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
58885b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
58899b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
58900759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5891cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5892c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
58935b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
58945b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5895c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5896beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
589723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
58985b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5899185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5900c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5901c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5902e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
59039b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
59049b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
59055d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
59065d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
59075d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
59085b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
59095b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
59105b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
59115b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5912ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5913fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5914cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5915d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
59165d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5917cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5918c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
59197109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
592078d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
59211da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5922c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
592332c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
592486e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
59255d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
59265d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
59275d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5928fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
59291da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
59300c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5931d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5932760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5933ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5934c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5935c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5936c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5937fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
59385b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
59395b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
59406014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
59416014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
594209ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
594309ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5944c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
59455b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
59469447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
59475b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
59489267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
59494a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)");
5950380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5951aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
595298e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
59531da177e4SLinus Torvalds 
5954760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5955760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
59561da177e4SLinus Torvalds 
59571da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
59581da177e4SLinus Torvalds {
5959c4837394SDouglas Gilbert 	int k;
5960c4837394SDouglas Gilbert 
5961760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5962760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5963760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5964c4837394SDouglas Gilbert 		return sdebug_info;
5965760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5966760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5967760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5968760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
59691da177e4SLinus Torvalds 	return sdebug_info;
59701da177e4SLinus Torvalds }
59711da177e4SLinus Torvalds 
5972cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5973fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5974fd32119bSDouglas Gilbert 				 int length)
59751da177e4SLinus Torvalds {
59761da177e4SLinus Torvalds 	char arr[16];
5977c8ed555aSAl Viro 	int opts;
59781da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
59791da177e4SLinus Torvalds 
59801da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
59811da177e4SLinus Torvalds 		return -EACCES;
59821da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
59831da177e4SLinus Torvalds 	arr[minLen] = '\0';
5984c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
59851da177e4SLinus Torvalds 		return -EINVAL;
5986773642d9SDouglas Gilbert 	sdebug_opts = opts;
5987773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5988773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5989773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5990c4837394SDouglas Gilbert 		tweak_cmnd_count();
59911da177e4SLinus Torvalds 	return length;
59921da177e4SLinus Torvalds }
5993c8ed555aSAl Viro 
5994cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5995cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5996cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5997c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5998c8ed555aSAl Viro {
5999c4837394SDouglas Gilbert 	int f, j, l;
6000c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
600187c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
6002cbf67842SDouglas Gilbert 
6003c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
6004c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
6005c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
6006c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
6007c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
6008c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
6009c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
6010c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
6011c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
6012c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
6013c4837394SDouglas Gilbert 		   num_aborts);
6014c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
6015c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
6016c4837394SDouglas Gilbert 		   num_host_resets);
6017c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
6018c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
6019458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
6020458df78bSBart Van Assche 		   sdebug_statistics);
60214a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
6022c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
6023c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
6024c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
60254a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
60264a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
6027cbf67842SDouglas Gilbert 
6028c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
6029c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
6030c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
6031c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
6032773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
6033c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
6034c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
6035c4837394SDouglas Gilbert 				   "first,last bits", f, l);
6036c4837394SDouglas Gilbert 		}
6037cbf67842SDouglas Gilbert 	}
603887c715dcSDouglas Gilbert 
603987c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
604087c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
604187c715dcSDouglas Gilbert 		bool niu;
604287c715dcSDouglas Gilbert 		int idx;
604387c715dcSDouglas Gilbert 		unsigned long l_idx;
604487c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
604587c715dcSDouglas Gilbert 
604687c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
604787c715dcSDouglas Gilbert 		j = 0;
604887c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
604987c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
605087c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
605187c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
605287c715dcSDouglas Gilbert 			++j;
605387c715dcSDouglas Gilbert 		}
605487c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
605587c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
605687c715dcSDouglas Gilbert 		j = 0;
605787c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
605887c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
605987c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
606087c715dcSDouglas Gilbert 			idx = (int)l_idx;
606187c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
606287c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
606387c715dcSDouglas Gilbert 			++j;
606487c715dcSDouglas Gilbert 		}
606587c715dcSDouglas Gilbert 	}
6066c8ed555aSAl Viro 	return 0;
60671da177e4SLinus Torvalds }
60681da177e4SLinus Torvalds 
606982069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
60701da177e4SLinus Torvalds {
6071c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
60721da177e4SLinus Torvalds }
6073c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
6074c4837394SDouglas Gilbert  * of delay is jiffies.
6075c4837394SDouglas Gilbert  */
607682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
607782069379SAkinobu Mita 			   size_t count)
60781da177e4SLinus Torvalds {
6079c2206098SDouglas Gilbert 	int jdelay, res;
60801da177e4SLinus Torvalds 
6081b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
6082cbf67842SDouglas Gilbert 		res = count;
6083c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
6084c4837394SDouglas Gilbert 			int j, k;
6085c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6086cbf67842SDouglas Gilbert 
6087f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6088c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6089c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6090c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6091c4837394SDouglas Gilbert 						   sdebug_max_queue);
6092c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6093c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6094c4837394SDouglas Gilbert 					break;
6095c4837394SDouglas Gilbert 				}
6096c4837394SDouglas Gilbert 			}
6097c4837394SDouglas Gilbert 			if (res > 0) {
6098c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
6099773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
61001da177e4SLinus Torvalds 			}
6101f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
6102cbf67842SDouglas Gilbert 		}
6103cbf67842SDouglas Gilbert 		return res;
61041da177e4SLinus Torvalds 	}
61051da177e4SLinus Torvalds 	return -EINVAL;
61061da177e4SLinus Torvalds }
610782069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
61081da177e4SLinus Torvalds 
6109cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
6110cbf67842SDouglas Gilbert {
6111773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
6112cbf67842SDouglas Gilbert }
6113cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6114c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
6115cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6116cbf67842SDouglas Gilbert 			    size_t count)
6117cbf67842SDouglas Gilbert {
6118c4837394SDouglas Gilbert 	int ndelay, res;
6119cbf67842SDouglas Gilbert 
6120cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6121c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6122cbf67842SDouglas Gilbert 		res = count;
6123773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
6124c4837394SDouglas Gilbert 			int j, k;
6125c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6126c4837394SDouglas Gilbert 
6127f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6128c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6129c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6130c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6131c4837394SDouglas Gilbert 						   sdebug_max_queue);
6132c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6133c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6134c4837394SDouglas Gilbert 					break;
6135c4837394SDouglas Gilbert 				}
6136c4837394SDouglas Gilbert 			}
6137c4837394SDouglas Gilbert 			if (res > 0) {
6138773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6139c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6140c2206098SDouglas Gilbert 							: DEF_JDELAY;
6141cbf67842SDouglas Gilbert 			}
6142f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
6143cbf67842SDouglas Gilbert 		}
6144cbf67842SDouglas Gilbert 		return res;
6145cbf67842SDouglas Gilbert 	}
6146cbf67842SDouglas Gilbert 	return -EINVAL;
6147cbf67842SDouglas Gilbert }
6148cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6149cbf67842SDouglas Gilbert 
615082069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
61511da177e4SLinus Torvalds {
6152773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
61531da177e4SLinus Torvalds }
61541da177e4SLinus Torvalds 
615582069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
615682069379SAkinobu Mita 			  size_t count)
61571da177e4SLinus Torvalds {
61581da177e4SLinus Torvalds 	int opts;
61591da177e4SLinus Torvalds 	char work[20];
61601da177e4SLinus Torvalds 
61619a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61629a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61639a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
61641da177e4SLinus Torvalds 				goto opts_done;
61651da177e4SLinus Torvalds 		} else {
61669a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
61671da177e4SLinus Torvalds 				goto opts_done;
61681da177e4SLinus Torvalds 		}
61691da177e4SLinus Torvalds 	}
61701da177e4SLinus Torvalds 	return -EINVAL;
61711da177e4SLinus Torvalds opts_done:
6172773642d9SDouglas Gilbert 	sdebug_opts = opts;
6173773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6174773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6175c4837394SDouglas Gilbert 	tweak_cmnd_count();
61761da177e4SLinus Torvalds 	return count;
61771da177e4SLinus Torvalds }
617882069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
61791da177e4SLinus Torvalds 
618082069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
61811da177e4SLinus Torvalds {
6182773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
61831da177e4SLinus Torvalds }
618482069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
618582069379SAkinobu Mita 			   size_t count)
61861da177e4SLinus Torvalds {
61871da177e4SLinus Torvalds 	int n;
61881da177e4SLinus Torvalds 
6189f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6190f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6191f0d1cf93SDouglas Gilbert 		return -EINVAL;
6192f0d1cf93SDouglas Gilbert 
61931da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6194f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6195f0d1cf93SDouglas Gilbert 			return -EINVAL;
6196773642d9SDouglas Gilbert 		sdebug_ptype = n;
61971da177e4SLinus Torvalds 		return count;
61981da177e4SLinus Torvalds 	}
61991da177e4SLinus Torvalds 	return -EINVAL;
62001da177e4SLinus Torvalds }
620182069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
62021da177e4SLinus Torvalds 
620382069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
62041da177e4SLinus Torvalds {
6205773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
62061da177e4SLinus Torvalds }
620782069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
620882069379SAkinobu Mita 			    size_t count)
62091da177e4SLinus Torvalds {
62101da177e4SLinus Torvalds 	int n;
62111da177e4SLinus Torvalds 
62121da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6213773642d9SDouglas Gilbert 		sdebug_dsense = n;
62141da177e4SLinus Torvalds 		return count;
62151da177e4SLinus Torvalds 	}
62161da177e4SLinus Torvalds 	return -EINVAL;
62171da177e4SLinus Torvalds }
621882069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
62191da177e4SLinus Torvalds 
622082069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
622123183910SDouglas Gilbert {
6222773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
622323183910SDouglas Gilbert }
622482069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
622582069379SAkinobu Mita 			     size_t count)
622623183910SDouglas Gilbert {
622787c715dcSDouglas Gilbert 	int n, idx;
622823183910SDouglas Gilbert 
622923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
623087c715dcSDouglas Gilbert 		bool want_store = (n == 0);
623187c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
623287c715dcSDouglas Gilbert 
6233cbf67842SDouglas Gilbert 		n = (n > 0);
6234773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
623587c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
623687c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6237cbf67842SDouglas Gilbert 
623887c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
623987c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
624087c715dcSDouglas Gilbert 				idx = sdebug_add_store();
624187c715dcSDouglas Gilbert 				if (idx < 0)
624287c715dcSDouglas Gilbert 					return idx;
624387c715dcSDouglas Gilbert 			} else {
624487c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
624587c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
624687c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6247cbf67842SDouglas Gilbert 			}
624887c715dcSDouglas Gilbert 			/* make all hosts use same store */
624987c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
625087c715dcSDouglas Gilbert 					    host_list) {
625187c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
625287c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
625387c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
625487c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
625587c715dcSDouglas Gilbert 				}
625687c715dcSDouglas Gilbert 			}
625787c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
625887c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
625987c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6260cbf67842SDouglas Gilbert 		}
6261773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
626223183910SDouglas Gilbert 		return count;
626323183910SDouglas Gilbert 	}
626423183910SDouglas Gilbert 	return -EINVAL;
626523183910SDouglas Gilbert }
626682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
626723183910SDouglas Gilbert 
626882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6269c65b1445SDouglas Gilbert {
6270773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6271c65b1445SDouglas Gilbert }
627282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
627382069379SAkinobu Mita 			      size_t count)
6274c65b1445SDouglas Gilbert {
6275c65b1445SDouglas Gilbert 	int n;
6276c65b1445SDouglas Gilbert 
6277c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6278773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6279c65b1445SDouglas Gilbert 		return count;
6280c65b1445SDouglas Gilbert 	}
6281c65b1445SDouglas Gilbert 	return -EINVAL;
6282c65b1445SDouglas Gilbert }
628382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6284c65b1445SDouglas Gilbert 
628582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
62861da177e4SLinus Torvalds {
6287773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
62881da177e4SLinus Torvalds }
628982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
629082069379SAkinobu Mita 			      size_t count)
62911da177e4SLinus Torvalds {
62921da177e4SLinus Torvalds 	int n;
62931da177e4SLinus Torvalds 
62941da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6295773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
62961da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
62971da177e4SLinus Torvalds 		return count;
62981da177e4SLinus Torvalds 	}
62991da177e4SLinus Torvalds 	return -EINVAL;
63001da177e4SLinus Torvalds }
630182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
63021da177e4SLinus Torvalds 
630382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
63041da177e4SLinus Torvalds {
6305773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
63061da177e4SLinus Torvalds }
630782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
63081da177e4SLinus Torvalds 
630987c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
631087c715dcSDouglas Gilbert {
631187c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
631287c715dcSDouglas Gilbert }
631387c715dcSDouglas Gilbert 
631487c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
631587c715dcSDouglas Gilbert 				    size_t count)
631687c715dcSDouglas Gilbert {
631787c715dcSDouglas Gilbert 	bool v;
631887c715dcSDouglas Gilbert 
631987c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
632087c715dcSDouglas Gilbert 		return -EINVAL;
632187c715dcSDouglas Gilbert 
632287c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
632387c715dcSDouglas Gilbert 	return count;
632487c715dcSDouglas Gilbert }
632587c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
632687c715dcSDouglas Gilbert 
632782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
63281da177e4SLinus Torvalds {
6329773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
63301da177e4SLinus Torvalds }
633182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
63321da177e4SLinus Torvalds 
633382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
63341da177e4SLinus Torvalds {
6335773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
63361da177e4SLinus Torvalds }
633782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
633882069379SAkinobu Mita 			       size_t count)
63391da177e4SLinus Torvalds {
63401da177e4SLinus Torvalds 	int nth;
63413a90a63dSDouglas Gilbert 	char work[20];
63421da177e4SLinus Torvalds 
63433a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
63443a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
63453a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
63463a90a63dSDouglas Gilbert 				goto every_nth_done;
63473a90a63dSDouglas Gilbert 		} else {
63483a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
63493a90a63dSDouglas Gilbert 				goto every_nth_done;
63503a90a63dSDouglas Gilbert 		}
63513a90a63dSDouglas Gilbert 	}
63523a90a63dSDouglas Gilbert 	return -EINVAL;
63533a90a63dSDouglas Gilbert 
63543a90a63dSDouglas Gilbert every_nth_done:
6355773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6356c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6357c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6358c4837394SDouglas Gilbert 		sdebug_statistics = true;
6359c4837394SDouglas Gilbert 	}
6360c4837394SDouglas Gilbert 	tweak_cmnd_count();
63611da177e4SLinus Torvalds 	return count;
63621da177e4SLinus Torvalds }
636382069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
63641da177e4SLinus Torvalds 
6365ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6366ad0c7775SDouglas Gilbert {
6367ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6368ad0c7775SDouglas Gilbert }
6369ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6370ad0c7775SDouglas Gilbert 				size_t count)
6371ad0c7775SDouglas Gilbert {
6372ad0c7775SDouglas Gilbert 	int n;
6373ad0c7775SDouglas Gilbert 	bool changed;
6374ad0c7775SDouglas Gilbert 
6375ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6376ad0c7775SDouglas Gilbert 		return -EINVAL;
6377ad0c7775SDouglas Gilbert 	if (n >= 0) {
6378ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6379ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6380ad0c7775SDouglas Gilbert 			return -EINVAL;
6381ad0c7775SDouglas Gilbert 		}
6382ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6383ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6384ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6385ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6386ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6387ad0c7775SDouglas Gilbert 
6388ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6389ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6390ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6391ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6392ad0c7775SDouglas Gilbert 				}
6393ad0c7775SDouglas Gilbert 			}
6394ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6395ad0c7775SDouglas Gilbert 		}
6396ad0c7775SDouglas Gilbert 		return count;
6397ad0c7775SDouglas Gilbert 	}
6398ad0c7775SDouglas Gilbert 	return -EINVAL;
6399ad0c7775SDouglas Gilbert }
6400ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6401ad0c7775SDouglas Gilbert 
640282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
64031da177e4SLinus Torvalds {
6404773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
64051da177e4SLinus Torvalds }
640682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
640782069379SAkinobu Mita 			      size_t count)
64081da177e4SLinus Torvalds {
64091da177e4SLinus Torvalds 	int n;
641019c8ead7SEwan D. Milne 	bool changed;
64111da177e4SLinus Torvalds 
64121da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
64138d039e22SDouglas Gilbert 		if (n > 256) {
64148d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
64158d039e22SDouglas Gilbert 			return -EINVAL;
64168d039e22SDouglas Gilbert 		}
6417773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6418773642d9SDouglas Gilbert 		sdebug_max_luns = n;
64191da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6420773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
642119c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
642219c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
642319c8ead7SEwan D. Milne 
642419c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
642519c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
642619c8ead7SEwan D. Milne 					    host_list) {
642719c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
642819c8ead7SEwan D. Milne 						    dev_list) {
642919c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
643019c8ead7SEwan D. Milne 						dp->uas_bm);
643119c8ead7SEwan D. Milne 				}
643219c8ead7SEwan D. Milne 			}
643319c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
643419c8ead7SEwan D. Milne 		}
64351da177e4SLinus Torvalds 		return count;
64361da177e4SLinus Torvalds 	}
64371da177e4SLinus Torvalds 	return -EINVAL;
64381da177e4SLinus Torvalds }
643982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
64401da177e4SLinus Torvalds 
644182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
644278d4e5a0SDouglas Gilbert {
6443773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
644478d4e5a0SDouglas Gilbert }
6445cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6446cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
644782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
644882069379SAkinobu Mita 			       size_t count)
644978d4e5a0SDouglas Gilbert {
6450c4837394SDouglas Gilbert 	int j, n, k, a;
6451c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
645278d4e5a0SDouglas Gilbert 
645378d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6454c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6455c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6456f19fe8f3SBart Van Assche 		block_unblock_all_queues(true);
6457c4837394SDouglas Gilbert 		k = 0;
6458c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6459c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6460c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6461c4837394SDouglas Gilbert 			if (a > k)
6462c4837394SDouglas Gilbert 				k = a;
6463c4837394SDouglas Gilbert 		}
6464773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6465c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6466cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6467cbf67842SDouglas Gilbert 		else if (k >= n)
6468cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6469cbf67842SDouglas Gilbert 		else
6470cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6471f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
647278d4e5a0SDouglas Gilbert 		return count;
647378d4e5a0SDouglas Gilbert 	}
647478d4e5a0SDouglas Gilbert 	return -EINVAL;
647578d4e5a0SDouglas Gilbert }
647682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
647778d4e5a0SDouglas Gilbert 
6478c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6479c10fa55fSJohn Garry {
6480c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6481c10fa55fSJohn Garry }
6482c10fa55fSJohn Garry 
64837109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
64847109f370SDouglas Gilbert {
64857109f370SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
64867109f370SDouglas Gilbert }
64877109f370SDouglas Gilbert 
64887109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
64897109f370SDouglas Gilbert {
64907109f370SDouglas Gilbert 	bool v;
64917109f370SDouglas Gilbert 
64927109f370SDouglas Gilbert 	if (kstrtobool(buf, &v))
64937109f370SDouglas Gilbert 		return -EINVAL;
64947109f370SDouglas Gilbert 
64957109f370SDouglas Gilbert 	sdebug_no_rwlock = v;
64967109f370SDouglas Gilbert 	return count;
64977109f370SDouglas Gilbert }
64987109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock);
64997109f370SDouglas Gilbert 
6500c10fa55fSJohn Garry /*
6501c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6502c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6503c10fa55fSJohn Garry  */
6504c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6505c10fa55fSJohn Garry 
650682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
650778d4e5a0SDouglas Gilbert {
6508773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
650978d4e5a0SDouglas Gilbert }
651082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
651178d4e5a0SDouglas Gilbert 
651282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
65131da177e4SLinus Torvalds {
6514773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
65151da177e4SLinus Torvalds }
651682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
65171da177e4SLinus Torvalds 
651882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6519c65b1445SDouglas Gilbert {
6520773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6521c65b1445SDouglas Gilbert }
652282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
652382069379SAkinobu Mita 				size_t count)
6524c65b1445SDouglas Gilbert {
6525c65b1445SDouglas Gilbert 	int n;
65260d01c5dfSDouglas Gilbert 	bool changed;
6527c65b1445SDouglas Gilbert 
6528f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6529f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6530f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6531f0d1cf93SDouglas Gilbert 
6532c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6533773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6534773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
653528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
65360d01c5dfSDouglas Gilbert 		if (changed) {
65370d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
65380d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
653928898873SFUJITA Tomonori 
65404bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
65410d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
65420d01c5dfSDouglas Gilbert 					    host_list) {
65430d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
65440d01c5dfSDouglas Gilbert 						    dev_list) {
65450d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
65460d01c5dfSDouglas Gilbert 						dp->uas_bm);
65470d01c5dfSDouglas Gilbert 				}
65480d01c5dfSDouglas Gilbert 			}
65494bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
65500d01c5dfSDouglas Gilbert 		}
6551c65b1445SDouglas Gilbert 		return count;
6552c65b1445SDouglas Gilbert 	}
6553c65b1445SDouglas Gilbert 	return -EINVAL;
6554c65b1445SDouglas Gilbert }
655582069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6556c65b1445SDouglas Gilbert 
655782069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
65581da177e4SLinus Torvalds {
655987c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
6560f19fe8f3SBart Van Assche 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
65611da177e4SLinus Torvalds }
65621da177e4SLinus Torvalds 
656382069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
656482069379SAkinobu Mita 			      size_t count)
65651da177e4SLinus Torvalds {
6566f19fe8f3SBart Van Assche 	bool found;
6567f19fe8f3SBart Van Assche 	unsigned long idx;
6568f19fe8f3SBart Van Assche 	struct sdeb_store_info *sip;
6569f19fe8f3SBart Van Assche 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
65701da177e4SLinus Torvalds 	int delta_hosts;
65711da177e4SLinus Torvalds 
6572f19fe8f3SBart Van Assche 	if (sscanf(buf, "%d", &delta_hosts) != 1)
65731da177e4SLinus Torvalds 		return -EINVAL;
65741da177e4SLinus Torvalds 	if (delta_hosts > 0) {
65751da177e4SLinus Torvalds 		do {
6576f19fe8f3SBart Van Assche 			found = false;
6577f19fe8f3SBart Van Assche 			if (want_phs) {
6578f19fe8f3SBart Van Assche 				xa_for_each_marked(per_store_ap, idx, sip,
6579f19fe8f3SBart Van Assche 						   SDEB_XA_NOT_IN_USE) {
6580f19fe8f3SBart Van Assche 					sdeb_most_recent_idx = (int)idx;
6581f19fe8f3SBart Van Assche 					found = true;
658287c715dcSDouglas Gilbert 					break;
658387c715dcSDouglas Gilbert 				}
6584f19fe8f3SBart Van Assche 				if (found)	/* re-use case */
6585f19fe8f3SBart Van Assche 					sdebug_add_host_helper((int)idx);
6586f19fe8f3SBart Van Assche 				else
6587f19fe8f3SBart Van Assche 					sdebug_do_add_host(true);
6588f19fe8f3SBart Van Assche 			} else {
6589f19fe8f3SBart Van Assche 				sdebug_do_add_host(false);
6590f19fe8f3SBart Van Assche 			}
6591f19fe8f3SBart Van Assche 		} while (--delta_hosts);
6592f19fe8f3SBart Van Assche 	} else if (delta_hosts < 0) {
6593f19fe8f3SBart Van Assche 		do {
659487c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
65951da177e4SLinus Torvalds 		} while (++delta_hosts);
65961da177e4SLinus Torvalds 	}
65971da177e4SLinus Torvalds 	return count;
65981da177e4SLinus Torvalds }
659982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
66001da177e4SLinus Torvalds 
660182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
660223183910SDouglas Gilbert {
6603773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
660423183910SDouglas Gilbert }
660582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
660682069379SAkinobu Mita 				    size_t count)
660723183910SDouglas Gilbert {
660823183910SDouglas Gilbert 	int n;
660923183910SDouglas Gilbert 
661023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6611773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
661223183910SDouglas Gilbert 		return count;
661323183910SDouglas Gilbert 	}
661423183910SDouglas Gilbert 	return -EINVAL;
661523183910SDouglas Gilbert }
661682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
661723183910SDouglas Gilbert 
6618c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6619c4837394SDouglas Gilbert {
6620c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6621c4837394SDouglas Gilbert }
6622c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6623c4837394SDouglas Gilbert 				size_t count)
6624c4837394SDouglas Gilbert {
6625c4837394SDouglas Gilbert 	int n;
6626c4837394SDouglas Gilbert 
6627c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6628c4837394SDouglas Gilbert 		if (n > 0)
6629c4837394SDouglas Gilbert 			sdebug_statistics = true;
6630c4837394SDouglas Gilbert 		else {
6631c4837394SDouglas Gilbert 			clear_queue_stats();
6632c4837394SDouglas Gilbert 			sdebug_statistics = false;
6633c4837394SDouglas Gilbert 		}
6634c4837394SDouglas Gilbert 		return count;
6635c4837394SDouglas Gilbert 	}
6636c4837394SDouglas Gilbert 	return -EINVAL;
6637c4837394SDouglas Gilbert }
6638c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6639c4837394SDouglas Gilbert 
664082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6641597136abSMartin K. Petersen {
6642773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6643597136abSMartin K. Petersen }
664482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6645597136abSMartin K. Petersen 
6646c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6647c4837394SDouglas Gilbert {
6648c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6649c4837394SDouglas Gilbert }
6650c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6651c4837394SDouglas Gilbert 
665282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6653c6a44287SMartin K. Petersen {
6654773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6655c6a44287SMartin K. Petersen }
665682069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6657c6a44287SMartin K. Petersen 
665882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6659c6a44287SMartin K. Petersen {
6660773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6661c6a44287SMartin K. Petersen }
666282069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6663c6a44287SMartin K. Petersen 
666482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6665c6a44287SMartin K. Petersen {
6666773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6667c6a44287SMartin K. Petersen }
666882069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6669c6a44287SMartin K. Petersen 
667082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6671c6a44287SMartin K. Petersen {
6672773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6673c6a44287SMartin K. Petersen }
667482069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6675c6a44287SMartin K. Petersen 
667682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
667744d92694SMartin K. Petersen {
667887c715dcSDouglas Gilbert 	ssize_t count = 0;
667944d92694SMartin K. Petersen 
66805b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
668144d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
668244d92694SMartin K. Petersen 				 sdebug_store_sectors);
668344d92694SMartin K. Petersen 
668487c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
668587c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
668687c715dcSDouglas Gilbert 
668787c715dcSDouglas Gilbert 		if (sip)
6688c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
668987c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
669087c715dcSDouglas Gilbert 	}
669144d92694SMartin K. Petersen 	buf[count++] = '\n';
6692c7badc90STejun Heo 	buf[count] = '\0';
669344d92694SMartin K. Petersen 
669444d92694SMartin K. Petersen 	return count;
669544d92694SMartin K. Petersen }
669682069379SAkinobu Mita static DRIVER_ATTR_RO(map);
669744d92694SMartin K. Petersen 
66980c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
66990c4bc91dSDouglas Gilbert {
67000c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
67010c4bc91dSDouglas Gilbert }
67020c4bc91dSDouglas Gilbert 
67030c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
67040c4bc91dSDouglas Gilbert 			    size_t count)
67050c4bc91dSDouglas Gilbert {
67060c4bc91dSDouglas Gilbert 	bool v;
67070c4bc91dSDouglas Gilbert 
67080c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
67090c4bc91dSDouglas Gilbert 		return -EINVAL;
67100c4bc91dSDouglas Gilbert 
67110c4bc91dSDouglas Gilbert 	sdebug_random = v;
67120c4bc91dSDouglas Gilbert 	return count;
67130c4bc91dSDouglas Gilbert }
67140c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
67150c4bc91dSDouglas Gilbert 
671682069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6717d986788bSMartin Pitt {
6718773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6719d986788bSMartin Pitt }
672082069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
672182069379SAkinobu Mita 			       size_t count)
6722d986788bSMartin Pitt {
6723d986788bSMartin Pitt 	int n;
6724d986788bSMartin Pitt 
6725d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6726773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6727d986788bSMartin Pitt 		return count;
6728d986788bSMartin Pitt 	}
6729d986788bSMartin Pitt 	return -EINVAL;
6730d986788bSMartin Pitt }
673182069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6732d986788bSMartin Pitt 
6733cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6734cbf67842SDouglas Gilbert {
6735773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6736cbf67842SDouglas Gilbert }
6737185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6738cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6739cbf67842SDouglas Gilbert 			       size_t count)
6740cbf67842SDouglas Gilbert {
6741185dd232SDouglas Gilbert 	int n;
6742cbf67842SDouglas Gilbert 
6743cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6744185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6745185dd232SDouglas Gilbert 		return count;
6746cbf67842SDouglas Gilbert 	}
6747cbf67842SDouglas Gilbert 	return -EINVAL;
6748cbf67842SDouglas Gilbert }
6749cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6750cbf67842SDouglas Gilbert 
6751c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6752c2248fc9SDouglas Gilbert {
6753773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6754c2248fc9SDouglas Gilbert }
6755c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6756c2248fc9SDouglas Gilbert 			    size_t count)
6757c2248fc9SDouglas Gilbert {
6758c2248fc9SDouglas Gilbert 	int n;
6759c2248fc9SDouglas Gilbert 
6760c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6761773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6762c2248fc9SDouglas Gilbert 		return count;
6763c2248fc9SDouglas Gilbert 	}
6764c2248fc9SDouglas Gilbert 	return -EINVAL;
6765c2248fc9SDouglas Gilbert }
6766c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6767c2248fc9SDouglas Gilbert 
676809ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
676909ba24c1SDouglas Gilbert {
677009ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
677109ba24c1SDouglas Gilbert }
677209ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
677309ba24c1SDouglas Gilbert 
67749b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
67759b760fd8SDouglas Gilbert {
67769b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
67779b760fd8SDouglas Gilbert }
67789b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
67799b760fd8SDouglas Gilbert 			     size_t count)
67809b760fd8SDouglas Gilbert {
67819b760fd8SDouglas Gilbert 	int ret, n;
67829b760fd8SDouglas Gilbert 
67839b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
67849b760fd8SDouglas Gilbert 	if (ret)
67859b760fd8SDouglas Gilbert 		return ret;
67869b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
67879b760fd8SDouglas Gilbert 	all_config_cdb_len();
67889b760fd8SDouglas Gilbert 	return count;
67899b760fd8SDouglas Gilbert }
67909b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
67919b760fd8SDouglas Gilbert 
67929267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
67939267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
67949267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
67959267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
67969267e0ebSDouglas Gilbert };
67979267e0ebSDouglas Gilbert 
67989267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
67999267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
68009267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
68019267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
68029267e0ebSDouglas Gilbert };
68039267e0ebSDouglas Gilbert 
68049267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
68059267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
68069267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
68079267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
68089267e0ebSDouglas Gilbert };
68099267e0ebSDouglas Gilbert 
68109267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
68119267e0ebSDouglas Gilbert {
68129267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
68139267e0ebSDouglas Gilbert 
68149267e0ebSDouglas Gilbert 	if (res < 0) {
68159267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
68169267e0ebSDouglas Gilbert 		if (res < 0) {
68179267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
681847742bdeSDan Carpenter 			if (res < 0)
68199267e0ebSDouglas Gilbert 				return -EINVAL;
68209267e0ebSDouglas Gilbert 		}
68219267e0ebSDouglas Gilbert 	}
68229267e0ebSDouglas Gilbert 	return res;
68239267e0ebSDouglas Gilbert }
68249267e0ebSDouglas Gilbert 
68259267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
68269267e0ebSDouglas Gilbert {
68279267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
68289267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
68299267e0ebSDouglas Gilbert }
68309267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6831cbf67842SDouglas Gilbert 
6832fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6833fc13638aSDouglas Gilbert {
6834fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6835fc13638aSDouglas Gilbert }
6836fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6837fc13638aSDouglas Gilbert 
683882069379SAkinobu Mita /* Note: The following array creates attribute files in the
683923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
684023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
684123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
684287c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
684323183910SDouglas Gilbert  */
68446ecaff7fSRandy Dunlap 
684582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
684682069379SAkinobu Mita 	&driver_attr_delay.attr,
684782069379SAkinobu Mita 	&driver_attr_opts.attr,
684882069379SAkinobu Mita 	&driver_attr_ptype.attr,
684982069379SAkinobu Mita 	&driver_attr_dsense.attr,
685082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6851c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
685282069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
685382069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
685482069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
685582069379SAkinobu Mita 	&driver_attr_num_parts.attr,
685682069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6857ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
685882069379SAkinobu Mita 	&driver_attr_max_luns.attr,
685982069379SAkinobu Mita 	&driver_attr_max_queue.attr,
68607109f370SDouglas Gilbert 	&driver_attr_no_rwlock.attr,
686182069379SAkinobu Mita 	&driver_attr_no_uld.attr,
686282069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
686382069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
686482069379SAkinobu Mita 	&driver_attr_add_host.attr,
686587c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
686682069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
686782069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6868c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6869c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
687082069379SAkinobu Mita 	&driver_attr_dix.attr,
687182069379SAkinobu Mita 	&driver_attr_dif.attr,
687282069379SAkinobu Mita 	&driver_attr_guard.attr,
687382069379SAkinobu Mita 	&driver_attr_ato.attr,
687482069379SAkinobu Mita 	&driver_attr_map.attr,
68750c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
687682069379SAkinobu Mita 	&driver_attr_removable.attr,
6877cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6878cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6879c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
688009ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
68819b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6882fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
68839267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
688482069379SAkinobu Mita 	NULL,
688582069379SAkinobu Mita };
688682069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
68871da177e4SLinus Torvalds 
688811ddcecaSAkinobu Mita static struct device *pseudo_primary;
68898dea0d02SFUJITA Tomonori 
68901da177e4SLinus Torvalds static int __init scsi_debug_init(void)
68911da177e4SLinus Torvalds {
689287c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
68935f2578e5SFUJITA Tomonori 	unsigned long sz;
689487c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
689587c715dcSDouglas Gilbert 	int idx = -1;
68961da177e4SLinus Torvalds 
689787c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
689887c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6899cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6900cbf67842SDouglas Gilbert 
6901773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6902c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6903773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6904773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6905c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6906cbf67842SDouglas Gilbert 
6907773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6908597136abSMartin K. Petersen 	case  512:
6909597136abSMartin K. Petersen 	case 1024:
6910597136abSMartin K. Petersen 	case 2048:
6911597136abSMartin K. Petersen 	case 4096:
6912597136abSMartin K. Petersen 		break;
6913597136abSMartin K. Petersen 	default:
6914773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6915597136abSMartin K. Petersen 		return -EINVAL;
6916597136abSMartin K. Petersen 	}
6917597136abSMartin K. Petersen 
6918773642d9SDouglas Gilbert 	switch (sdebug_dif) {
69198475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6920f46eb0e9SDouglas Gilbert 		break;
69218475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
69228475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
69238475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6924f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6925c6a44287SMartin K. Petersen 		break;
6926c6a44287SMartin K. Petersen 
6927c6a44287SMartin K. Petersen 	default:
6928c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6929c6a44287SMartin K. Petersen 		return -EINVAL;
6930c6a44287SMartin K. Petersen 	}
6931c6a44287SMartin K. Petersen 
6932aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6933aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6934aa5334c4SMaurizio Lombardi 		return -EINVAL;
6935aa5334c4SMaurizio Lombardi 	}
6936aa5334c4SMaurizio Lombardi 
6937773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6938c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6939c6a44287SMartin K. Petersen 		return -EINVAL;
6940c6a44287SMartin K. Petersen 	}
6941c6a44287SMartin K. Petersen 
6942773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6943c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6944c6a44287SMartin K. Petersen 		return -EINVAL;
6945c6a44287SMartin K. Petersen 	}
6946c6a44287SMartin K. Petersen 
6947773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6948773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6949ea61fca5SMartin K. Petersen 		return -EINVAL;
6950ea61fca5SMartin K. Petersen 	}
6951ad0c7775SDouglas Gilbert 
6952ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6953ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6954ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6955ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6956ad0c7775SDouglas Gilbert 	}
6957ad0c7775SDouglas Gilbert 
69588d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6959ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6960ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
69618d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
69628d039e22SDouglas Gilbert 		}
6963ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6964ad0c7775SDouglas Gilbert 	}
6965ea61fca5SMartin K. Petersen 
6966773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6967773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6968ea61fca5SMartin K. Petersen 		return -EINVAL;
6969ea61fca5SMartin K. Petersen 	}
6970ea61fca5SMartin K. Petersen 
6971c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6972c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6973c4837394SDouglas Gilbert 		return -EINVAL;
6974c4837394SDouglas Gilbert 	}
6975c87bf24cSJohn Garry 
6976c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6977c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6978c87bf24cSJohn Garry 		return -EINVAL;
6979c87bf24cSJohn Garry 	}
6980c87bf24cSJohn Garry 
6981c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6982c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6983c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6984c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6985c10fa55fSJohn Garry 		return -EINVAL;
6986c10fa55fSJohn Garry 	}
6987c10fa55fSJohn Garry 
6988c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6989c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6990c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6991c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6992c10fa55fSJohn Garry 			sdebug_max_queue);
6993c10fa55fSJohn Garry 	}
6994c10fa55fSJohn Garry 
6995c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6996c4837394SDouglas Gilbert 			       GFP_KERNEL);
6997c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6998c4837394SDouglas Gilbert 		return -ENOMEM;
6999c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
7000c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
7001c4837394SDouglas Gilbert 
7002f0d1cf93SDouglas Gilbert 	/*
70039267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
70049267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
7005f0d1cf93SDouglas Gilbert 	 */
70069267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
70079267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
70089267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
70099267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
70109267e0ebSDouglas Gilbert 		if (k < 0) {
70119267e0ebSDouglas Gilbert 			ret = k;
70123b01d7eaSDinghao Liu 			goto free_q_arr;
70139267e0ebSDouglas Gilbert 		}
70149267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
70159267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
70169267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
701764e14eceSDamien Le Moal 		case BLK_ZONED_HA:
70189267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
70199267e0ebSDouglas Gilbert 			break;
70209267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
70219267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
70229267e0ebSDouglas Gilbert 			break;
70239267e0ebSDouglas Gilbert 		default:
70249267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
70253b01d7eaSDinghao Liu 			ret = -EINVAL;
70263b01d7eaSDinghao Liu 			goto free_q_arr;
70279267e0ebSDouglas Gilbert 		}
70289267e0ebSDouglas Gilbert 	}
70299267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
7030f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
70319267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70329267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
70339267e0ebSDouglas Gilbert 	}
7034f0d1cf93SDouglas Gilbert 
70359267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70369267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
7037773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
7038773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
7039773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
7040773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
704128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
70421da177e4SLinus Torvalds 
70431da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
70441da177e4SLinus Torvalds 	sdebug_heads = 8;
70451da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
7046773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
70471da177e4SLinus Torvalds 		sdebug_heads = 64;
7048773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
7049fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
70501da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70511da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70521da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
70531da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
70541da177e4SLinus Torvalds 		sdebug_heads = 255;
70551da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
70561da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70571da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70581da177e4SLinus Torvalds 	}
70595b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
7060773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
7061773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
70626014759cSMartin K. Petersen 
7063773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
7064773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
70656014759cSMartin K. Petersen 
7066773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
7067773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
70686014759cSMartin K. Petersen 
7069773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
7070773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
7071773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
7072c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
7073c4837394SDouglas Gilbert 			ret = -EINVAL;
707487c715dcSDouglas Gilbert 			goto free_q_arr;
707544d92694SMartin K. Petersen 		}
707644d92694SMartin K. Petersen 	}
707787c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
707887c715dcSDouglas Gilbert 	if (want_store) {
707987c715dcSDouglas Gilbert 		idx = sdebug_add_store();
708087c715dcSDouglas Gilbert 		if (idx < 0) {
708187c715dcSDouglas Gilbert 			ret = idx;
708287c715dcSDouglas Gilbert 			goto free_q_arr;
708387c715dcSDouglas Gilbert 		}
708444d92694SMartin K. Petersen 	}
708544d92694SMartin K. Petersen 
70869b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
70879b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
7088c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
70899b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
70906ecaff7fSRandy Dunlap 		goto free_vm;
70916ecaff7fSRandy Dunlap 	}
70926ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
70936ecaff7fSRandy Dunlap 	if (ret < 0) {
7094c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
70956ecaff7fSRandy Dunlap 		goto dev_unreg;
70966ecaff7fSRandy Dunlap 	}
70976ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
70986ecaff7fSRandy Dunlap 	if (ret < 0) {
7099c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
71006ecaff7fSRandy Dunlap 		goto bus_unreg;
71016ecaff7fSRandy Dunlap 	}
71021da177e4SLinus Torvalds 
710387c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
7104773642d9SDouglas Gilbert 	sdebug_add_host = 0;
71051da177e4SLinus Torvalds 
710687c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
710787c715dcSDouglas Gilbert 		if (want_store && k == 0) {
710887c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
710987c715dcSDouglas Gilbert 			if (ret < 0) {
711087c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
711187c715dcSDouglas Gilbert 				       k, -ret);
711287c715dcSDouglas Gilbert 				break;
711387c715dcSDouglas Gilbert 			}
711487c715dcSDouglas Gilbert 		} else {
711587c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
711687c715dcSDouglas Gilbert 						 sdebug_per_host_store);
711787c715dcSDouglas Gilbert 			if (ret < 0) {
711887c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
71191da177e4SLinus Torvalds 				break;
71201da177e4SLinus Torvalds 			}
71211da177e4SLinus Torvalds 		}
712287c715dcSDouglas Gilbert 	}
7123773642d9SDouglas Gilbert 	if (sdebug_verbose)
7124f19fe8f3SBart Van Assche 		pr_info("built %d host(s)\n", sdebug_num_hosts);
7125c1287970STomas Winkler 
71261da177e4SLinus Torvalds 	return 0;
71276ecaff7fSRandy Dunlap 
71286ecaff7fSRandy Dunlap bus_unreg:
71296ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
71306ecaff7fSRandy Dunlap dev_unreg:
71319b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71326ecaff7fSRandy Dunlap free_vm:
713387c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
7134c4837394SDouglas Gilbert free_q_arr:
7135c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
71366ecaff7fSRandy Dunlap 	return ret;
71371da177e4SLinus Torvalds }
71381da177e4SLinus Torvalds 
71391da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
71401da177e4SLinus Torvalds {
7141f19fe8f3SBart Van Assche 	int k = sdebug_num_hosts;
71421da177e4SLinus Torvalds 
7143f19fe8f3SBart Van Assche 	stop_all_queued();
7144f19fe8f3SBart Van Assche 	for (; k; k--)
714587c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
714652ab9768SLuis Henriques 	free_all_queued();
71471da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
71481da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
71499b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71501da177e4SLinus Torvalds 
715187c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
715287c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
7153f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
71541da177e4SLinus Torvalds }
71551da177e4SLinus Torvalds 
71561da177e4SLinus Torvalds device_initcall(scsi_debug_init);
71571da177e4SLinus Torvalds module_exit(scsi_debug_exit);
71581da177e4SLinus Torvalds 
71591da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
71601da177e4SLinus Torvalds {
71611da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71621da177e4SLinus Torvalds 
71631da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
71641da177e4SLinus Torvalds 	kfree(sdbg_host);
71651da177e4SLinus Torvalds }
71661da177e4SLinus Torvalds 
716787c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
716887c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
71691da177e4SLinus Torvalds {
717087c715dcSDouglas Gilbert 	if (idx < 0)
717187c715dcSDouglas Gilbert 		return;
717287c715dcSDouglas Gilbert 	if (!sip) {
717387c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
717487c715dcSDouglas Gilbert 			return;
717587c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
717687c715dcSDouglas Gilbert 		if (!sip)
717787c715dcSDouglas Gilbert 			return;
717887c715dcSDouglas Gilbert 	}
717987c715dcSDouglas Gilbert 	vfree(sip->map_storep);
718087c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
718187c715dcSDouglas Gilbert 	vfree(sip->storep);
718287c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
718387c715dcSDouglas Gilbert 	kfree(sip);
718487c715dcSDouglas Gilbert }
718587c715dcSDouglas Gilbert 
718687c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
718787c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
718887c715dcSDouglas Gilbert {
718987c715dcSDouglas Gilbert 	unsigned long idx;
719087c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
719187c715dcSDouglas Gilbert 
719287c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
719387c715dcSDouglas Gilbert 		if (apart_from_first)
719487c715dcSDouglas Gilbert 			apart_from_first = false;
719587c715dcSDouglas Gilbert 		else
719687c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
719787c715dcSDouglas Gilbert 	}
719887c715dcSDouglas Gilbert 	if (apart_from_first)
719987c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
720087c715dcSDouglas Gilbert }
720187c715dcSDouglas Gilbert 
720287c715dcSDouglas Gilbert /*
720387c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
720487c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
720587c715dcSDouglas Gilbert  */
720687c715dcSDouglas Gilbert static int sdebug_add_store(void)
720787c715dcSDouglas Gilbert {
720887c715dcSDouglas Gilbert 	int res;
720987c715dcSDouglas Gilbert 	u32 n_idx;
721087c715dcSDouglas Gilbert 	unsigned long iflags;
721187c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
721287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
721387c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
721487c715dcSDouglas Gilbert 
721587c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
721687c715dcSDouglas Gilbert 	if (!sip)
721787c715dcSDouglas Gilbert 		return -ENOMEM;
721887c715dcSDouglas Gilbert 
721987c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
722087c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
722187c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
722287c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
722387c715dcSDouglas Gilbert 		kfree(sip);
722487c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
722587c715dcSDouglas Gilbert 		return res;
722687c715dcSDouglas Gilbert 	}
722787c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
722887c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
722987c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
723087c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
723187c715dcSDouglas Gilbert 
723287c715dcSDouglas Gilbert 	res = -ENOMEM;
723387c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
723487c715dcSDouglas Gilbert 	if (!sip->storep) {
723587c715dcSDouglas Gilbert 		pr_err("user data oom\n");
723687c715dcSDouglas Gilbert 		goto err;
723787c715dcSDouglas Gilbert 	}
723887c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
723987c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
724087c715dcSDouglas Gilbert 
724187c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
724287c715dcSDouglas Gilbert 	if (sdebug_dix) {
724387c715dcSDouglas Gilbert 		int dif_size;
724487c715dcSDouglas Gilbert 
724587c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
724687c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
724787c715dcSDouglas Gilbert 
724887c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
724987c715dcSDouglas Gilbert 			sip->dif_storep);
725087c715dcSDouglas Gilbert 
725187c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
725287c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
725387c715dcSDouglas Gilbert 			goto err;
725487c715dcSDouglas Gilbert 		}
725587c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
725687c715dcSDouglas Gilbert 	}
725787c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
725887c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
725987c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
726087c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
726187c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
726287c715dcSDouglas Gilbert 
726387c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
726487c715dcSDouglas Gilbert 
726587c715dcSDouglas Gilbert 		if (!sip->map_storep) {
726687c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
726787c715dcSDouglas Gilbert 			goto err;
726887c715dcSDouglas Gilbert 		}
726987c715dcSDouglas Gilbert 
727087c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
727187c715dcSDouglas Gilbert 
727287c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
727387c715dcSDouglas Gilbert 		if (sdebug_num_parts)
727487c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
727587c715dcSDouglas Gilbert 	}
727687c715dcSDouglas Gilbert 
727787c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
727887c715dcSDouglas Gilbert 	return (int)n_idx;
727987c715dcSDouglas Gilbert err:
728087c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
728187c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
728287c715dcSDouglas Gilbert 	return res;
728387c715dcSDouglas Gilbert }
728487c715dcSDouglas Gilbert 
728587c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
728687c715dcSDouglas Gilbert {
728787c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
728887c715dcSDouglas Gilbert 	int error = -ENOMEM;
72891da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72908b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
72911da177e4SLinus Torvalds 
729224669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
729387c715dcSDouglas Gilbert 	if (!sdbg_host)
72941da177e4SLinus Torvalds 		return -ENOMEM;
729587c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
729687c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
729787c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
729887c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
72991da177e4SLinus Torvalds 
73001da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
73011da177e4SLinus Torvalds 
7302773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
73031da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
73045cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
730587c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
73061da177e4SLinus Torvalds 			goto clean;
73071da177e4SLinus Torvalds 	}
73081da177e4SLinus Torvalds 
73091da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73101da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
73111da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73121da177e4SLinus Torvalds 
73131da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
73149b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
73151da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
7316f19fe8f3SBart Van Assche 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
73171da177e4SLinus Torvalds 
73181da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
73191da177e4SLinus Torvalds 	if (error)
73201da177e4SLinus Torvalds 		goto clean;
73211da177e4SLinus Torvalds 
7322f19fe8f3SBart Van Assche 	++sdebug_num_hosts;
732387c715dcSDouglas Gilbert 	return 0;
73241da177e4SLinus Torvalds 
73251da177e4SLinus Torvalds clean:
73268b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73278b40228fSFUJITA Tomonori 				 dev_list) {
73281da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7329f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73301da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73311da177e4SLinus Torvalds 	}
73321da177e4SLinus Torvalds 	kfree(sdbg_host);
733387c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
73341da177e4SLinus Torvalds 	return error;
73351da177e4SLinus Torvalds }
73361da177e4SLinus Torvalds 
733787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
73381da177e4SLinus Torvalds {
733987c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
734087c715dcSDouglas Gilbert 
734187c715dcSDouglas Gilbert 	if (mk_new_store) {
734287c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
734387c715dcSDouglas Gilbert 		if (ph_idx < 0)
734487c715dcSDouglas Gilbert 			return ph_idx;
734587c715dcSDouglas Gilbert 	}
734687c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
734787c715dcSDouglas Gilbert }
734887c715dcSDouglas Gilbert 
734987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
735087c715dcSDouglas Gilbert {
735187c715dcSDouglas Gilbert 	int idx = -1;
73521da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
735387c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
73541da177e4SLinus Torvalds 
73551da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73561da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
73571da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
73581da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
735987c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
73601da177e4SLinus Torvalds 	}
736187c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
736287c715dcSDouglas Gilbert 		bool unique = true;
736387c715dcSDouglas Gilbert 
736487c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
736587c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
736687c715dcSDouglas Gilbert 				continue;
736787c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
736887c715dcSDouglas Gilbert 				unique = false;
736987c715dcSDouglas Gilbert 				break;
737087c715dcSDouglas Gilbert 			}
737187c715dcSDouglas Gilbert 		}
737287c715dcSDouglas Gilbert 		if (unique) {
737387c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
737487c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
737587c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
737687c715dcSDouglas Gilbert 		}
737787c715dcSDouglas Gilbert 	}
737887c715dcSDouglas Gilbert 	if (sdbg_host)
737987c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
73801da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73811da177e4SLinus Torvalds 
73821da177e4SLinus Torvalds 	if (!sdbg_host)
73831da177e4SLinus Torvalds 		return;
73841da177e4SLinus Torvalds 
73851da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
7386f19fe8f3SBart Van Assche 	--sdebug_num_hosts;
73871da177e4SLinus Torvalds }
73881da177e4SLinus Torvalds 
7389fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7390cbf67842SDouglas Gilbert {
7391cbf67842SDouglas Gilbert 	int num_in_q = 0;
7392cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7393cbf67842SDouglas Gilbert 
7394f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
7395cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7396cbf67842SDouglas Gilbert 	if (NULL == devip) {
7397f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
7398cbf67842SDouglas Gilbert 		return	-ENODEV;
7399cbf67842SDouglas Gilbert 	}
7400cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7401c40ecc12SChristoph Hellwig 
7402fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7403fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7404fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7405fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7406fc09acb7SDouglas Gilbert 	}
7407cbf67842SDouglas Gilbert 	if (qdepth < 1)
7408cbf67842SDouglas Gilbert 		qdepth = 1;
7409fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7410db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7411cbf67842SDouglas Gilbert 
7412773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7413c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7414c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7415cbf67842SDouglas Gilbert 	}
7416f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
7417cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7418cbf67842SDouglas Gilbert }
7419cbf67842SDouglas Gilbert 
7420c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7421817fd66bSDouglas Gilbert {
7422c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7423773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7424773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7425773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7426c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7427773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7428817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7429c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7430817fd66bSDouglas Gilbert 	}
7431c4837394SDouglas Gilbert 	return false;
7432817fd66bSDouglas Gilbert }
7433817fd66bSDouglas Gilbert 
7434fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7435fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7436fc13638aSDouglas Gilbert {
7437fc13638aSDouglas Gilbert 	int stopped_state;
7438fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7439fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7440fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7441fc13638aSDouglas Gilbert 
7442fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7443fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7444fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7445fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7446fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7447fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7448fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7449fc13638aSDouglas Gilbert 				return 0;
7450fc13638aSDouglas Gilbert 			}
7451fc13638aSDouglas Gilbert 		}
7452fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7453fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7454fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7455fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7456fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7457fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7458fc13638aSDouglas Gilbert 
7459fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7460fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7461fc13638aSDouglas Gilbert 			else
7462fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7463fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7464fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7465fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7466fc13638aSDouglas Gilbert 						   diff_ns);
7467fc13638aSDouglas Gilbert 			return check_condition_result;
7468fc13638aSDouglas Gilbert 		}
7469fc13638aSDouglas Gilbert 	}
7470fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7471fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7472fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7473fc13638aSDouglas Gilbert 			    my_name);
7474fc13638aSDouglas Gilbert 	return check_condition_result;
7475fc13638aSDouglas Gilbert }
7476fc13638aSDouglas Gilbert 
7477a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost)
7478c4b57d89SKashyap Desai {
7479c4b57d89SKashyap Desai 	int i, qoff;
7480c4b57d89SKashyap Desai 
7481c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7482a4e1d0b7SBart Van Assche 		return;
7483c4b57d89SKashyap Desai 
7484c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7485c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7486c4b57d89SKashyap Desai 
7487c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7488c4b57d89SKashyap Desai 
7489c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7490c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7491c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7492c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7493c4b57d89SKashyap Desai 
7494c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7495c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7496c4b57d89SKashyap Desai 			continue;
7497c4b57d89SKashyap Desai 		}
7498c4b57d89SKashyap Desai 
7499c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7500c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7501c4b57d89SKashyap Desai 
7502c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7503c4b57d89SKashyap Desai 	}
7504c4b57d89SKashyap Desai }
7505c4b57d89SKashyap Desai 
7506c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7507c4b57d89SKashyap Desai {
75084a0c6f43SDouglas Gilbert 	bool first;
75094a0c6f43SDouglas Gilbert 	bool retiring = false;
75104a0c6f43SDouglas Gilbert 	int num_entries = 0;
75114a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7512c4b57d89SKashyap Desai 	unsigned long iflags;
75134a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7514c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7515c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7516c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7517c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
75184a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7519c4b57d89SKashyap Desai 
7520c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
75214a0c6f43SDouglas Gilbert 
7522c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
75234a0c6f43SDouglas Gilbert 
75246a0d0ae3SDamien Le Moal 	qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
75256a0d0ae3SDamien Le Moal 	if (qc_idx >= sdebug_max_queue)
75266a0d0ae3SDamien Le Moal 		goto unlock;
75276a0d0ae3SDamien Le Moal 
75284a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
75294a0c6f43SDouglas Gilbert 		if (first) {
75304a0c6f43SDouglas Gilbert 			first = false;
7531b05d4e48SDouglas Gilbert 			if (!test_bit(qc_idx, sqp->in_use_bm))
7532b05d4e48SDouglas Gilbert 				continue;
75334a0c6f43SDouglas Gilbert 		} else {
75344a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
75354a0c6f43SDouglas Gilbert 		}
7536b05d4e48SDouglas Gilbert 		if (qc_idx >= sdebug_max_queue)
75374a0c6f43SDouglas Gilbert 			break;
7538c4b57d89SKashyap Desai 
7539c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
75404a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
75414a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
75424a0c6f43SDouglas Gilbert 			continue;
7543c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7544c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
75454a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7546c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
75474a0c6f43SDouglas Gilbert 			break;
7548c4b57d89SKashyap Desai 		}
7549d9d23a5aSDouglas Gilbert 		if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) {
75504a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
75514a0c6f43SDouglas Gilbert 				continue;
75524a0c6f43SDouglas Gilbert 
75536ce913feSChristoph Hellwig 		} else		/* ignoring non REQ_POLLED requests */
75544a0c6f43SDouglas Gilbert 			continue;
7555c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7556c4b57d89SKashyap Desai 		if (likely(devip))
7557c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7558c4b57d89SKashyap Desai 		else
7559c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7560c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
75614a0c6f43SDouglas Gilbert 			retiring = true;
7562c4b57d89SKashyap Desai 
7563c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7564c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
75654a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7566c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
75674a0c6f43SDouglas Gilbert 			break;
7568c4b57d89SKashyap Desai 		}
7569c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7570c4b57d89SKashyap Desai 			int k, retval;
7571c4b57d89SKashyap Desai 
7572c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7573c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7574c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
75754a0c6f43SDouglas Gilbert 				break;
7576c4b57d89SKashyap Desai 			}
7577c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7578c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7579c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7580c4b57d89SKashyap Desai 			else
7581c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7582c4b57d89SKashyap Desai 		}
7583d9d23a5aSDouglas Gilbert 		WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
7584c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75856c2c7d6aSBart Van Assche 		scsi_done(scp); /* callback to mid level */
7586c4b57d89SKashyap Desai 		num_entries++;
75873fd07aecSDamien Le Moal 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7588b05d4e48SDouglas Gilbert 		if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue)
75893fd07aecSDamien Le Moal 			break;
75904a0c6f43SDouglas Gilbert 	}
75913fd07aecSDamien Le Moal 
75926a0d0ae3SDamien Le Moal unlock:
7593c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75943fd07aecSDamien Le Moal 
75954a0c6f43SDouglas Gilbert 	if (num_entries > 0)
75964a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7597c4b57d89SKashyap Desai 	return num_entries;
7598c4b57d89SKashyap Desai }
7599c4b57d89SKashyap Desai 
7600fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7601fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7602c2248fc9SDouglas Gilbert {
7603c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7604c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7605c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7606c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7607c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7608c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7609c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7610f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7611c2248fc9SDouglas Gilbert 	int k, na;
7612c2248fc9SDouglas Gilbert 	int errsts = 0;
7613ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7614c2248fc9SDouglas Gilbert 	u32 flags;
7615c2248fc9SDouglas Gilbert 	u16 sa;
7616c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7617c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
76183a90a63dSDouglas Gilbert 	bool inject_now;
7619c2248fc9SDouglas Gilbert 
7620c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
76213a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7622c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
76233a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
76243a90a63dSDouglas Gilbert 	} else {
76253a90a63dSDouglas Gilbert 		inject_now = false;
76263a90a63dSDouglas Gilbert 	}
7627f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7628f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7629c2248fc9SDouglas Gilbert 		char b[120];
7630c2248fc9SDouglas Gilbert 		int n, len, sb;
7631c2248fc9SDouglas Gilbert 
7632c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7633c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7634c2248fc9SDouglas Gilbert 		if (len > 32)
7635c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7636c2248fc9SDouglas Gilbert 		else {
7637c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7638c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7639c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7640c2248fc9SDouglas Gilbert 		}
7641458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7642a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7643c2248fc9SDouglas Gilbert 	}
76443a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
76457ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
764634d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7647ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7648f46eb0e9SDouglas Gilbert 		goto err_out;
7649c2248fc9SDouglas Gilbert 
7650c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7651c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7652c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7653f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7654f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7655c2248fc9SDouglas Gilbert 		if (NULL == devip)
7656f46eb0e9SDouglas Gilbert 			goto err_out;
7657c2248fc9SDouglas Gilbert 	}
76583a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
76593a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
76603a90a63dSDouglas Gilbert 
7661c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7662c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7663c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7664c2248fc9SDouglas Gilbert 		r_oip = oip;
7665c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7666c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7667c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7668c2248fc9SDouglas Gilbert 			else
7669c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7670c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7671c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7672c2248fc9SDouglas Gilbert 					break;
7673c2248fc9SDouglas Gilbert 			}
7674c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7675c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7676c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7677c2248fc9SDouglas Gilbert 					break;
7678c2248fc9SDouglas Gilbert 			}
7679c2248fc9SDouglas Gilbert 		}
7680c2248fc9SDouglas Gilbert 		if (k > na) {
7681c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7682c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7683c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7684c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7685c2248fc9SDouglas Gilbert 			else
7686c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7687c2248fc9SDouglas Gilbert 			goto check_cond;
7688c2248fc9SDouglas Gilbert 		}
7689c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7690c2248fc9SDouglas Gilbert 	flags = oip->flags;
7691f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7692c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7693c2248fc9SDouglas Gilbert 		goto check_cond;
7694c2248fc9SDouglas Gilbert 	}
7695f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7696773642d9SDouglas Gilbert 		if (sdebug_verbose)
7697773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7698773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7699c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7700c2248fc9SDouglas Gilbert 		goto check_cond;
7701c2248fc9SDouglas Gilbert 	}
7702f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7703c2248fc9SDouglas Gilbert 		u8 rem;
7704c2248fc9SDouglas Gilbert 		int j;
7705c2248fc9SDouglas Gilbert 
7706c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7707c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7708c2248fc9SDouglas Gilbert 			if (rem) {
7709c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7710c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7711c2248fc9SDouglas Gilbert 						break;
7712c2248fc9SDouglas Gilbert 				}
7713c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7714c2248fc9SDouglas Gilbert 				goto check_cond;
7715c2248fc9SDouglas Gilbert 			}
7716c2248fc9SDouglas Gilbert 		}
7717c2248fc9SDouglas Gilbert 	}
7718f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7719b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7720b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7721f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7722c2248fc9SDouglas Gilbert 		if (errsts)
7723c2248fc9SDouglas Gilbert 			goto check_cond;
7724c2248fc9SDouglas Gilbert 	}
7725fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7726fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7727fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7728fc13638aSDouglas Gilbert 		if (errsts)
7729c2248fc9SDouglas Gilbert 			goto fini;
7730c2248fc9SDouglas Gilbert 	}
7731773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7732c2248fc9SDouglas Gilbert 		goto fini;
7733f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7734c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7735c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7736c2248fc9SDouglas Gilbert 	}
7737f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7738f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7739f66b8517SMartin Wilck 	else
7740f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7741c2248fc9SDouglas Gilbert 
7742c2248fc9SDouglas Gilbert fini:
774367da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7744f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
774575aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
774675aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
774780c49563SDouglas Gilbert 		/*
774875aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
774975aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
775075aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
775175aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
775280c49563SDouglas Gilbert 		 */
775380c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
77544f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
775580c49563SDouglas Gilbert 
77564f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7757f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
775880c49563SDouglas Gilbert 	} else
7759f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
776010bde980SDouglas Gilbert 				     sdebug_ndelay);
7761c2248fc9SDouglas Gilbert check_cond:
7762f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7763f46eb0e9SDouglas Gilbert err_out:
7764f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7765c2248fc9SDouglas Gilbert }
7766c2248fc9SDouglas Gilbert 
77679e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7768c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7769c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
77709e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
77719e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
77729e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
77739e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
77749e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
77759e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
77769e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7777185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7778cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7779c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7780c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
77819e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
77829e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7783cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7784cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
77859e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7786c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
77879e603ca0SFUJITA Tomonori 	.this_id =		7,
778865e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7789cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
77906bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
779150c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
77929e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7793c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
77949e603ca0SFUJITA Tomonori };
77959e603ca0SFUJITA Tomonori 
77961da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
77971da177e4SLinus Torvalds {
77981da177e4SLinus Torvalds 	int error = 0;
77991da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
78001da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7801f46eb0e9SDouglas Gilbert 	int hprot;
78021da177e4SLinus Torvalds 
78031da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
78041da177e4SLinus Torvalds 
7805773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7806fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
78072a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
78084af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
78094af14d11SChristoph Hellwig 
78101da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
78111da177e4SLinus Torvalds 	if (NULL == hpnt) {
7812c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
78131da177e4SLinus Torvalds 		error = -ENODEV;
78141da177e4SLinus Torvalds 		return error;
78151da177e4SLinus Torvalds 	}
7816c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
78179b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7818c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7819c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7820c4837394SDouglas Gilbert 	}
7821c10fa55fSJohn Garry 	/*
7822c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7823f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7824c10fa55fSJohn Garry 	 */
7825c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7826f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7827f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
78281da177e4SLinus Torvalds 
7829c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7830c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7831c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7832c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7833c4b57d89SKashyap Desai 		poll_queues = 0;
7834c4b57d89SKashyap Desai 	}
7835c4b57d89SKashyap Desai 
7836c4b57d89SKashyap Desai 	/*
7837c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7838c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7839c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7840c4b57d89SKashyap Desai 	 */
7841c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7842fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7843c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7844fc09acb7SDouglas Gilbert 		else
7845fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7846fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7847c4b57d89SKashyap Desai 		poll_queues = 1;
7848c4b57d89SKashyap Desai 	}
7849c4b57d89SKashyap Desai 	if (poll_queues)
7850c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7851c4b57d89SKashyap Desai 
78521da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
78531da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7854773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7855773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
78561da177e4SLinus Torvalds 	else
7857773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7858773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7859f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
78601da177e4SLinus Torvalds 
7861f46eb0e9SDouglas Gilbert 	hprot = 0;
7862c6a44287SMartin K. Petersen 
7863773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7864c6a44287SMartin K. Petersen 
78658475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7866f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7867773642d9SDouglas Gilbert 		if (sdebug_dix)
7868f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7869c6a44287SMartin K. Petersen 		break;
7870c6a44287SMartin K. Petersen 
78718475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7872f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7873773642d9SDouglas Gilbert 		if (sdebug_dix)
7874f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7875c6a44287SMartin K. Petersen 		break;
7876c6a44287SMartin K. Petersen 
78778475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7878f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7879773642d9SDouglas Gilbert 		if (sdebug_dix)
7880f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7881c6a44287SMartin K. Petersen 		break;
7882c6a44287SMartin K. Petersen 
7883c6a44287SMartin K. Petersen 	default:
7884773642d9SDouglas Gilbert 		if (sdebug_dix)
7885f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7886c6a44287SMartin K. Petersen 		break;
7887c6a44287SMartin K. Petersen 	}
7888c6a44287SMartin K. Petersen 
7889f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7890c6a44287SMartin K. Petersen 
7891f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7892c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7893f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7894f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7895f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7896f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7897f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7898f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7899f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7900c6a44287SMartin K. Petersen 
7901773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7902c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7903c6a44287SMartin K. Petersen 	else
7904c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7905c6a44287SMartin K. Petersen 
7906773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7907773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7908c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7909c4837394SDouglas Gilbert 		sdebug_statistics = true;
79101da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
79111da177e4SLinus Torvalds 	if (error) {
7912c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
79131da177e4SLinus Torvalds 		error = -ENODEV;
79141da177e4SLinus Torvalds 		scsi_host_put(hpnt);
791587c715dcSDouglas Gilbert 	} else {
79161da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
791787c715dcSDouglas Gilbert 	}
79181da177e4SLinus Torvalds 
79191da177e4SLinus Torvalds 	return error;
79201da177e4SLinus Torvalds }
79211da177e4SLinus Torvalds 
7922fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
79231da177e4SLinus Torvalds {
79241da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
79258b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
79261da177e4SLinus Torvalds 
79271da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
79281da177e4SLinus Torvalds 
79291da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
79301da177e4SLinus Torvalds 
79318b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
79328b40228fSFUJITA Tomonori 				 dev_list) {
79331da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7934f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
79351da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
79361da177e4SLinus Torvalds 	}
79371da177e4SLinus Torvalds 
79381da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
79391da177e4SLinus Torvalds }
79401da177e4SLinus Torvalds 
79418dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
79428dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
79431da177e4SLinus Torvalds {
79448dea0d02SFUJITA Tomonori 	return 1;
79458dea0d02SFUJITA Tomonori }
79461da177e4SLinus Torvalds 
79478dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
79488dea0d02SFUJITA Tomonori 	.name = "pseudo",
79498dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
79508dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
79518dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
795282069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
79538dea0d02SFUJITA Tomonori };
7954