xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 6a0d0ae3)
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>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/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>
352aad3cd8SDouglas Gilbert #include <linux/mutex.h>
36cbf67842SDouglas Gilbert #include <linux/interrupt.h>
37cbf67842SDouglas Gilbert #include <linux/atomic.h>
38cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3909ba24c1SDouglas Gilbert #include <linux/uuid.h>
406ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
411442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
420c4bc91dSDouglas Gilbert #include <linux/random.h>
4387c715dcSDouglas Gilbert #include <linux/xarray.h>
44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
63500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191"	/* format to fit INQUIRY revision field */
64500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1
87cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
88cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8922017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
901da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
916f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
92c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
93c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9422017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
96acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
97481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
98f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
99f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
100f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
101f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1031da177e4SLinus Torvalds 
1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1066f3cbf55SDouglas Gilbert 
1071da177e4SLinus Torvalds /* Default values for driver parameters */
1081da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1091da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1101da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1121da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1131da177e4SLinus Torvalds  */
1145b94e232SMartin K. Petersen #define DEF_ATO 1
1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
116c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1205b94e232SMartin K. Petersen #define DEF_DIF 0
1215b94e232SMartin K. Petersen #define DEF_DIX 0
12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1235b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1241da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1255b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1265b94e232SMartin K. Petersen #define DEF_GUARD 0
127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1285b94e232SMartin K. Petersen #define DEF_LBPU 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS 0
1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0
131be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
133cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1351da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1361da177e4SLinus Torvalds #define DEF_OPTS   0
13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
140b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false
142d986788bSMartin Pitt #define DEF_REMOVABLE false
143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
152c2248fc9SDouglas Gilbert #define DEF_STRICT 0
153c4837394SDouglas Gilbert #define DEF_STATISTICS false
154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1581da177e4SLinus Torvalds 
159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
163f0d1cf93SDouglas Gilbert 
164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
165b01f6f83SDouglas Gilbert 
166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
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 {
25564e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_CNV	= 0x1,
25664e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWR	= 0x2,
25764e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWP	= 0x3,
25864e14eceSDamien Le Moal };
25964e14eceSDamien Le Moal 
260f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
261f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
262f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
263f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
264f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
265f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
266f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
267f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
268f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
269f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
270f0d1cf93SDouglas Gilbert };
271f0d1cf93SDouglas Gilbert 
272f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
27364e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
274f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
27564e14eceSDamien Le Moal 	bool z_non_seq_resource;
276f0d1cf93SDouglas Gilbert 	unsigned int z_size;
277f0d1cf93SDouglas Gilbert 	sector_t z_start;
278f0d1cf93SDouglas Gilbert 	sector_t z_wp;
279f0d1cf93SDouglas Gilbert };
280fd32119bSDouglas Gilbert 
281fd32119bSDouglas Gilbert struct sdebug_dev_info {
282fd32119bSDouglas Gilbert 	struct list_head dev_list;
283fd32119bSDouglas Gilbert 	unsigned int channel;
284fd32119bSDouglas Gilbert 	unsigned int target;
285fd32119bSDouglas Gilbert 	u64 lun;
286bf476433SChristoph Hellwig 	uuid_t lu_name;
287fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
288fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
289fd32119bSDouglas Gilbert 	atomic_t num_in_q;
290fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
291fd32119bSDouglas Gilbert 	bool used;
292f0d1cf93SDouglas Gilbert 
293f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
29464e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
295f0d1cf93SDouglas Gilbert 	unsigned int zsize;
296f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
297f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
298aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
299f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
300f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
301f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
302f0d1cf93SDouglas Gilbert 	unsigned int max_open;
303fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
304f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
305fd32119bSDouglas Gilbert };
306fd32119bSDouglas Gilbert 
307fd32119bSDouglas Gilbert struct sdebug_host_info {
308fd32119bSDouglas Gilbert 	struct list_head host_list;
30987c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
310fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
311fd32119bSDouglas Gilbert 	struct device dev;
312fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
313fd32119bSDouglas Gilbert };
314fd32119bSDouglas Gilbert 
31587c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
31687c715dcSDouglas Gilbert struct sdeb_store_info {
31787c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
31887c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
31987c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
32087c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32187c715dcSDouglas Gilbert };
32287c715dcSDouglas Gilbert 
323fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
324fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
325fd32119bSDouglas Gilbert 
32610bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3274a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
32810bde980SDouglas Gilbert 
329fd32119bSDouglas Gilbert struct sdebug_defer {
330fd32119bSDouglas Gilbert 	struct hrtimer hrt;
331fd32119bSDouglas Gilbert 	struct execute_work ew;
3324a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
333c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
334c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
335c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
336c4837394SDouglas Gilbert 	int issuing_cpu;
33710bde980SDouglas Gilbert 	bool init_hrt;
33810bde980SDouglas Gilbert 	bool init_wq;
3394a0c6f43SDouglas Gilbert 	bool init_poll;
3407382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34110bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
342fd32119bSDouglas Gilbert };
343fd32119bSDouglas Gilbert 
344fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
345c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
346c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
347c4837394SDouglas Gilbert 	 */
348fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
349fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
350fd32119bSDouglas Gilbert };
351fd32119bSDouglas Gilbert 
352c4837394SDouglas Gilbert struct sdebug_queue {
353c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
354c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
355c4837394SDouglas Gilbert 	spinlock_t qc_lock;
356c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
357fd32119bSDouglas Gilbert };
358fd32119bSDouglas Gilbert 
359c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
360c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
361c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
362c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3633a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3644a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
365c4837394SDouglas Gilbert 
366fd32119bSDouglas Gilbert struct opcode_info_t {
367b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
368b01f6f83SDouglas Gilbert 				/* for terminating element */
369fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
370fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
371fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
372fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
373fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3749a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3759a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
376fd32119bSDouglas Gilbert };
377fd32119bSDouglas Gilbert 
378fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
379c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
380c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
381c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
382c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
383c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
384c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
385c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
386c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
387c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
388c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
389c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
390c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
391c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39246f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39346f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
394c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
395c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
396c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
397481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
398c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
399c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
400c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
401c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
402c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
403c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
404c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
405c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
406c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
407c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
408c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
409ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
410f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
411f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
412f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
413c2248fc9SDouglas Gilbert };
414c2248fc9SDouglas Gilbert 
415c4837394SDouglas Gilbert 
416c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
417c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
418c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
419c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
420c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
421c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
422c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
423c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
424c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
425c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
426c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
427c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
428ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
429c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
430c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
431c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
432c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
433c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
434c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
435c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
436fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
437c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
438c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
439c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
440c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
441c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
442c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
443c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
444f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
445f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44646f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
447c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
448c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
449c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
45046f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
45146f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
452c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
455c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
456c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
457c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
458c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
459c2248fc9SDouglas Gilbert };
460c2248fc9SDouglas Gilbert 
46180c49563SDouglas Gilbert /*
46280c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46380c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46480c49563SDouglas Gilbert  * command completion, they can mask their return value with
46580c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46680c49563SDouglas Gilbert  */
46780c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46880c49563SDouglas Gilbert 
469c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
470c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
478481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
486c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
488c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
48938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
490acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
49180c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
492ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
493f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
494f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
495f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
496f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
497f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
498c2248fc9SDouglas Gilbert 
49987c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
50087c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
50187c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50287c715dcSDouglas Gilbert static int sdebug_add_store(void);
50387c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50487c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50587c715dcSDouglas Gilbert 
50646f64e70SDouglas Gilbert /*
50746f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50846f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
50946f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
51046f64e70SDouglas Gilbert  */
51146f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
512c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
513c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
514c2248fc9SDouglas Gilbert };
515c2248fc9SDouglas Gilbert 
51646f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
517c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
518c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
519c2248fc9SDouglas Gilbert };
520c2248fc9SDouglas Gilbert 
52146f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52246f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
523b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
524c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52546f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
526c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52746f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
528b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
529c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
530c2248fc9SDouglas Gilbert };
531c2248fc9SDouglas Gilbert 
53246f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53346f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53446f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53546f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53646f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53746f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53846f64e70SDouglas Gilbert 		   0, 0, 0} },
53946f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
54046f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54146f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
542c2248fc9SDouglas Gilbert };
543c2248fc9SDouglas Gilbert 
544c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
545c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
546c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
547c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
548c3e2fe92SDouglas Gilbert };
549c3e2fe92SDouglas Gilbert 
55046f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
551c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
552c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55346f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
554c2248fc9SDouglas Gilbert };
555c2248fc9SDouglas Gilbert 
55646f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55746f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
558b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
559c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
560481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
561481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
562481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
563c2248fc9SDouglas Gilbert };
564c2248fc9SDouglas Gilbert 
56546f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56638d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
567c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56846f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
56938d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
570c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
57146f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
572c2248fc9SDouglas Gilbert };
573c2248fc9SDouglas Gilbert 
57446f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57546f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
576c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57746f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
578c2248fc9SDouglas Gilbert };
579c2248fc9SDouglas Gilbert 
58046f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
581c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
582c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
583c2248fc9SDouglas Gilbert };
584c2248fc9SDouglas Gilbert 
58546f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
586c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
587c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
588c2248fc9SDouglas Gilbert };
589c2248fc9SDouglas Gilbert 
59080c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5914f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59280c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59380c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59480c49563SDouglas Gilbert };
59580c49563SDouglas Gilbert 
596ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
597b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
598ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
599ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
600ed9f3e25SDouglas Gilbert };
601ed9f3e25SDouglas Gilbert 
602f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
603b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
604f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
605f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
606b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
607f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
608f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
609b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
610f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
611f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
612f0d1cf93SDouglas Gilbert };
613f0d1cf93SDouglas Gilbert 
614f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
615b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
616f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
617f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
618f0d1cf93SDouglas Gilbert };
619f0d1cf93SDouglas Gilbert 
620c2248fc9SDouglas Gilbert 
621c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
622c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
623c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
624ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
625c2248fc9SDouglas Gilbert /* 0 */
62646f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
627c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62846f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
629c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
630c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
631c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63246f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
633c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
634c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
635c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
636c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63746f64e70SDouglas Gilbert /* 5 */
63846f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
63946f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
64046f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64146f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64246f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64346f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64446f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
645c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
646c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64746f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
648c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
649c2248fc9SDouglas Gilbert 	     0, 0} },
65046f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
65146f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65246f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
653c2248fc9SDouglas Gilbert /* 10 */
65446f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65546f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65646f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65780c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6584f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
659c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
66046f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
66146f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66246f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66346f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
664481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
665481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
666481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66746f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66846f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
66946f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
67046f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
67146f64e70SDouglas Gilbert /* 15 */
672c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
673c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
674c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
675c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
676c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
677c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67846f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
67946f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
68046f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
68146f64e70SDouglas Gilbert 	     0xff, 0xff} },
68246f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68346f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
684c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
685c2248fc9SDouglas Gilbert 	     0} },
68646f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68746f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
688c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
689c2248fc9SDouglas Gilbert 	     0} },
690c2248fc9SDouglas Gilbert /* 20 */
691f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
692f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
693c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
694c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
695c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
696c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
697c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
698c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
69946f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
700b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
70146f64e70SDouglas Gilbert /* 25 */
702acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
703acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
704acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70546f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70646f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70746f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70846f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7094f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
71080c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
711b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71280c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71346f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
714c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
715b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
716b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
717ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
718ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
719ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
720c2248fc9SDouglas Gilbert 
721ed9f3e25SDouglas Gilbert /* 30 */
722b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
723f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
724f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
725f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
726b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
727f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
728f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
729f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
730f0d1cf93SDouglas Gilbert /* sentinel */
731c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
732c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
733c2248fc9SDouglas Gilbert };
734c2248fc9SDouglas Gilbert 
7352aad3cd8SDouglas Gilbert static atomic_t sdebug_num_hosts;
7362aad3cd8SDouglas Gilbert static DEFINE_MUTEX(add_host_mutex);
7372aad3cd8SDouglas Gilbert 
73887c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
739773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7409b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
741c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7429267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
743773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
744773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
745773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
746773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
747773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
748773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
749c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
750773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
751773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
752c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
753d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
754d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
755cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
756c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
757773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
758773642d9SDouglas Gilbert static int sdebug_no_uld;
759773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
760773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
761773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
762773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
763773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76486e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
765b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
766773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
767773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
768fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
769773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
770773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
771773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
772773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
773773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
774773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
775773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
776773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
778773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
779773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
78009ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7810c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
78287c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
783773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
7842aad3cd8SDouglas Gilbert static bool sdebug_deflect_incoming;
785773642d9SDouglas Gilbert static bool sdebug_clustering;
786773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
787773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
788817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
7897109f370SDouglas Gilbert static bool sdebug_no_rwlock;
790773642d9SDouglas Gilbert static bool sdebug_verbose;
791f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7924f2c8bf6SDouglas Gilbert static bool write_since_sync;
793c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7949447b6ceSMartin K. Petersen static bool sdebug_wp;
7959267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7969267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7979267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7981da177e4SLinus Torvalds 
799ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
800ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
801ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
802ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
803ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
804ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
805ad0c7775SDouglas Gilbert 
806c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8071da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8101da177e4SLinus Torvalds    may still need them */
8111da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8121da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8131da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8161da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8171da177e4SLinus Torvalds 
81887c715dcSDouglas Gilbert static struct xarray per_store_arr;
81987c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
82087c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
82187c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
82287c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8231da177e4SLinus Torvalds 
82444d92694SMartin K. Petersen static unsigned long map_size;
825cbf67842SDouglas Gilbert static int num_aborts;
826cbf67842SDouglas Gilbert static int num_dev_resets;
827cbf67842SDouglas Gilbert static int num_target_resets;
828cbf67842SDouglas Gilbert static int num_bus_resets;
829cbf67842SDouglas Gilbert static int num_host_resets;
830c6a44287SMartin K. Petersen static int dix_writes;
831c6a44287SMartin K. Petersen static int dix_reads;
832c6a44287SMartin K. Petersen static int dif_errors;
8331da177e4SLinus Torvalds 
834f0d1cf93SDouglas Gilbert /* ZBC global data */
83564e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
83698e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
837380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
838aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
839f0d1cf93SDouglas Gilbert 
840c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
841c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
842c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
843fd32119bSDouglas Gilbert 
8441da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
84587c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84687c715dcSDouglas Gilbert 
84787c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8481da177e4SLinus Torvalds 
849cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
850cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8551da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8561da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8571da177e4SLinus Torvalds };
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds static const int check_condition_result =
860464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8611da177e4SLinus Torvalds 
862c6a44287SMartin K. Petersen static const int illegal_condition_result =
863464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
864c6a44287SMartin K. Petersen 
865cbf67842SDouglas Gilbert static const int device_qfull_result =
8667d5a129bSDouglas Gilbert 	(DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
867cbf67842SDouglas Gilbert 
868ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
869ed9f3e25SDouglas Gilbert 
870fd32119bSDouglas Gilbert 
871760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
872760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
873760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
874760f3b03SDouglas Gilbert  */
875760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
876fd32119bSDouglas Gilbert {
877fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
878fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
879fd32119bSDouglas Gilbert }
880c65b1445SDouglas Gilbert 
88187c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
88287c715dcSDouglas Gilbert 			    unsigned long long lba)
88314faa944SAkinobu Mita {
88487c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
88514faa944SAkinobu Mita 
88687c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88787c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88887c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
88987c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
89087c715dcSDouglas Gilbert 	}
89187c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
89214faa944SAkinobu Mita }
89314faa944SAkinobu Mita 
89487c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
89587c715dcSDouglas Gilbert 				      sector_t sector)
89614faa944SAkinobu Mita {
89749413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89814faa944SAkinobu Mita 
89987c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
90014faa944SAkinobu Mita }
90114faa944SAkinobu Mita 
9028dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9038dea0d02SFUJITA Tomonori {
9048dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9058dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9068dea0d02SFUJITA Tomonori 
9078dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9088dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9098dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9108dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
911773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
912773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9138dea0d02SFUJITA Tomonori 		else
914773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
915773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
916f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9178dea0d02SFUJITA Tomonori 	}
9188dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9198dea0d02SFUJITA Tomonori }
9208dea0d02SFUJITA Tomonori 
92122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
92222017ed2SDouglas Gilbert 
92322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
924fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
925fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92622017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92722017ed2SDouglas Gilbert {
92822017ed2SDouglas Gilbert 	unsigned char *sbuff;
92922017ed2SDouglas Gilbert 	u8 sks[4];
93022017ed2SDouglas Gilbert 	int sl, asc;
93122017ed2SDouglas Gilbert 
93222017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
93322017ed2SDouglas Gilbert 	if (!sbuff) {
93422017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
93522017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93622017ed2SDouglas Gilbert 		return;
93722017ed2SDouglas Gilbert 	}
93822017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
93922017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
940f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
94122017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
94222017ed2SDouglas Gilbert 	sks[0] = 0x80;
94322017ed2SDouglas Gilbert 	if (c_d)
94422017ed2SDouglas Gilbert 		sks[0] |= 0x40;
94522017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94622017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94722017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94822017ed2SDouglas Gilbert 	}
94922017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
950773642d9SDouglas Gilbert 	if (sdebug_dsense) {
95122017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
95222017ed2SDouglas Gilbert 		sbuff[7] = sl;
95322017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
95422017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
95522017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95622017ed2SDouglas Gilbert 	} else
95722017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
958773642d9SDouglas Gilbert 	if (sdebug_verbose)
95922017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
96022017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
96122017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
96222017ed2SDouglas Gilbert }
96322017ed2SDouglas Gilbert 
964cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9658dea0d02SFUJITA Tomonori {
966f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
967cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
968cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
969cbf67842SDouglas Gilbert 		return;
970cbf67842SDouglas Gilbert 	}
971f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9728dea0d02SFUJITA Tomonori 
973f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9748dea0d02SFUJITA Tomonori 
975773642d9SDouglas Gilbert 	if (sdebug_verbose)
976cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
977cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
978cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9798dea0d02SFUJITA Tomonori }
9801da177e4SLinus Torvalds 
981fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
98222017ed2SDouglas Gilbert {
98322017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98422017ed2SDouglas Gilbert }
98522017ed2SDouglas Gilbert 
9866f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9876f4e626fSNathan Chancellor 			    void __user *arg)
9881da177e4SLinus Torvalds {
989773642d9SDouglas Gilbert 	if (sdebug_verbose) {
990cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
991cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
992cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
993cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
994cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
995cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
996cbf67842SDouglas Gilbert 				    __func__);
997cbf67842SDouglas Gilbert 		else
998cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
999cbf67842SDouglas Gilbert 				    __func__, cmd);
10001da177e4SLinus Torvalds 	}
10011da177e4SLinus Torvalds 	return -EINVAL;
10021da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10031da177e4SLinus Torvalds }
10041da177e4SLinus Torvalds 
10059b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10069b760fd8SDouglas Gilbert {
10079b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10089b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10099b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10109b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10119b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10129b760fd8SDouglas Gilbert 		break;
10139b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10149b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10159b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10179b760fd8SDouglas Gilbert 		break;
10189b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10199b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10209b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10229b760fd8SDouglas Gilbert 		break;
10239b760fd8SDouglas Gilbert 	case 16:
10249b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10259b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10279b760fd8SDouglas Gilbert 		break;
10289b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10299b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10309b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10329b760fd8SDouglas Gilbert 		break;
10339b760fd8SDouglas Gilbert 	default:
10349b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10359b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10369b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10379b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10389b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10399b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10409b760fd8SDouglas Gilbert 		break;
10419b760fd8SDouglas Gilbert 	}
10429b760fd8SDouglas Gilbert }
10439b760fd8SDouglas Gilbert 
10449b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10459b760fd8SDouglas Gilbert {
10469b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10479b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10489b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10499b760fd8SDouglas Gilbert 
10509b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10519b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10529b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10539b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10549b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10559b760fd8SDouglas Gilbert 		}
10569b760fd8SDouglas Gilbert 	}
10579b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10589b760fd8SDouglas Gilbert }
10599b760fd8SDouglas Gilbert 
106019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
106119c8ead7SEwan D. Milne {
106219c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106319c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106419c8ead7SEwan D. Milne 
106519c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
106619c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106719c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
106819c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
106919c8ead7SEwan D. Milne 			    (devip->target == dp->target))
107019c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
107119c8ead7SEwan D. Milne 		}
107219c8ead7SEwan D. Milne 	}
107319c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107419c8ead7SEwan D. Milne }
107519c8ead7SEwan D. Milne 
1076f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10771da177e4SLinus Torvalds {
1078cbf67842SDouglas Gilbert 	int k;
1079cbf67842SDouglas Gilbert 
1080cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1081cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1082cbf67842SDouglas Gilbert 		const char *cp = NULL;
1083cbf67842SDouglas Gilbert 
1084cbf67842SDouglas Gilbert 		switch (k) {
1085cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1086f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1087f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1088773642d9SDouglas Gilbert 			if (sdebug_verbose)
1089cbf67842SDouglas Gilbert 				cp = "power on reset";
1090cbf67842SDouglas Gilbert 			break;
1091500d0d24SDouglas Gilbert 		case SDEBUG_UA_POOCCUR:
1092500d0d24SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1093500d0d24SDouglas Gilbert 					POWER_ON_OCCURRED_ASCQ);
1094500d0d24SDouglas Gilbert 			if (sdebug_verbose)
1095500d0d24SDouglas Gilbert 				cp = "power on occurred";
1096500d0d24SDouglas Gilbert 			break;
1097cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1098f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1099f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1100773642d9SDouglas Gilbert 			if (sdebug_verbose)
1101cbf67842SDouglas Gilbert 				cp = "bus reset";
1102cbf67842SDouglas Gilbert 			break;
1103cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1104f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1105f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1106773642d9SDouglas Gilbert 			if (sdebug_verbose)
1107cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1108cbf67842SDouglas Gilbert 			break;
11090d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1110f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1111f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1112773642d9SDouglas Gilbert 			if (sdebug_verbose)
11130d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1114f49accf1SEwan D. Milne 			break;
1115acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1116f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1117b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1118b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1119773642d9SDouglas Gilbert 			if (sdebug_verbose)
1120acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1121acafd0b9SEwan D. Milne 			break;
1122acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1123f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1124acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1125acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1126773642d9SDouglas Gilbert 			if (sdebug_verbose)
1127acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1128acafd0b9SEwan D. Milne 			break;
112919c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
113019c8ead7SEwan D. Milne 			/*
113119c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
113219c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
113319c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
113419c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1135773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
113619c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
113719c8ead7SEwan D. Milne 			 */
1138773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
113919c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1140f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
114119c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
114219c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1143773642d9SDouglas Gilbert 			if (sdebug_verbose)
114419c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
114519c8ead7SEwan D. Milne 			break;
1146cbf67842SDouglas Gilbert 		default:
1147773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1148773642d9SDouglas Gilbert 			if (sdebug_verbose)
1149cbf67842SDouglas Gilbert 				cp = "unknown";
1150cbf67842SDouglas Gilbert 			break;
1151cbf67842SDouglas Gilbert 		}
1152cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1153773642d9SDouglas Gilbert 		if (sdebug_verbose)
1154f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1155cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1156cbf67842SDouglas Gilbert 				   my_name, cp);
11571da177e4SLinus Torvalds 		return check_condition_result;
11581da177e4SLinus Torvalds 	}
11591da177e4SLinus Torvalds 	return 0;
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds 
1162fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11631da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11641da177e4SLinus Torvalds 				int arr_len)
11651da177e4SLinus Torvalds {
116621a61829SFUJITA Tomonori 	int act_len;
1167ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11681da177e4SLinus Torvalds 
1169072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11701da177e4SLinus Torvalds 		return 0;
1171ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1172773642d9SDouglas Gilbert 		return DID_ERROR << 16;
117321a61829SFUJITA Tomonori 
117421a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
117521a61829SFUJITA Tomonori 				      arr, arr_len);
117642d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
117721a61829SFUJITA Tomonori 
11781da177e4SLinus Torvalds 	return 0;
11791da177e4SLinus Torvalds }
11801da177e4SLinus Torvalds 
1181fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1182fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1183fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1184fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1185fb0cc8d1SDouglas Gilbert  */
1186fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1187fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1188fb0cc8d1SDouglas Gilbert {
11899237f04eSDamien Le Moal 	unsigned int act_len, n;
1190ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1191fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1192fb0cc8d1SDouglas Gilbert 
1193fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1194fb0cc8d1SDouglas Gilbert 		return 0;
1195ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1196fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1197fb0cc8d1SDouglas Gilbert 
1198fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1199fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1200fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
120142d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
120242d387beSBart Van Assche 		 scsi_get_resid(scp));
12039237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
120436e07d7eSGeorge Kennedy 	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
1205fb0cc8d1SDouglas Gilbert 	return 0;
1206fb0cc8d1SDouglas Gilbert }
1207fb0cc8d1SDouglas Gilbert 
1208fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1209fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1210fb0cc8d1SDouglas Gilbert  */
12111da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
121221a61829SFUJITA Tomonori 			       int arr_len)
12131da177e4SLinus Torvalds {
121421a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12151da177e4SLinus Torvalds 		return 0;
1216ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12171da177e4SLinus Torvalds 		return -1;
121821a61829SFUJITA Tomonori 
121921a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12201da177e4SLinus Torvalds }
12211da177e4SLinus Torvalds 
12221da177e4SLinus Torvalds 
1223e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1224e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12259b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12261b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12271b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12281b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12291b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12301da177e4SLinus Torvalds 
1231cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1232760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12335a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
123409ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1235bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12361da177e4SLinus Torvalds {
1237c65b1445SDouglas Gilbert 	int num, port_a;
1238c65b1445SDouglas Gilbert 	char b[32];
12391da177e4SLinus Torvalds 
1240c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12411da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12421da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12431da177e4SLinus Torvalds 	arr[1] = 0x1;
12441da177e4SLinus Torvalds 	arr[2] = 0x0;
1245e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1246e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12471da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12481da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12491da177e4SLinus Torvalds 	arr[3] = num;
12501da177e4SLinus Torvalds 	num += 4;
1251c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
125209ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
125309ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
125409ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
125509ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
125609ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125709ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
125809ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
125909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
126009ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
126109ba24c1SDouglas Gilbert 			num += 16;
126209ba24c1SDouglas Gilbert 		} else {
12631b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1264c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1265c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1266c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1267c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12681b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1269773642d9SDouglas Gilbert 			num += 8;
127009ba24c1SDouglas Gilbert 		}
1271c65b1445SDouglas Gilbert 		/* Target relative port number */
1272c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1273c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1274c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1275c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1276c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1277c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1278c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1279c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1280c65b1445SDouglas Gilbert 	}
12811b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1282c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1283c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1284c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1285c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12861b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1287773642d9SDouglas Gilbert 	num += 8;
12881b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12895a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12905a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12915a09e398SHannes Reinecke 	arr[num++] = 0x0;
12925a09e398SHannes Reinecke 	arr[num++] = 0x4;
12935a09e398SHannes Reinecke 	arr[num++] = 0;
12945a09e398SHannes Reinecke 	arr[num++] = 0;
1295773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1296773642d9SDouglas Gilbert 	num += 2;
12971b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1298c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1299c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1300c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1301c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
13021b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1303773642d9SDouglas Gilbert 	num += 8;
1304c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1305c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1306c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1307c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1308c65b1445SDouglas Gilbert 	arr[num++] = 24;
13091b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1310c65b1445SDouglas Gilbert 	num += 12;
1311c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1312c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1313c65b1445SDouglas Gilbert 	num += 8;
1314c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1315c65b1445SDouglas Gilbert 	num += 4;
1316c65b1445SDouglas Gilbert 	return num;
1317c65b1445SDouglas Gilbert }
1318c65b1445SDouglas Gilbert 
1319c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1320c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1321c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1322c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1323c65b1445SDouglas Gilbert };
1324c65b1445SDouglas Gilbert 
1325cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1326760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1327c65b1445SDouglas Gilbert {
1328c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1329c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1330c65b1445SDouglas Gilbert }
1331c65b1445SDouglas Gilbert 
1332cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1333760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1334c65b1445SDouglas Gilbert {
1335c65b1445SDouglas Gilbert 	int num = 0;
1336c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1337c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1338c65b1445SDouglas Gilbert 	int plen, olen;
1339c65b1445SDouglas Gilbert 
1340c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1341c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1342c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1343c65b1445SDouglas Gilbert 	olen = strlen(na1);
1344c65b1445SDouglas Gilbert 	plen = olen + 1;
1345c65b1445SDouglas Gilbert 	if (plen % 4)
1346c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1347c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1348c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1349c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1350c65b1445SDouglas Gilbert 	num += plen;
1351c65b1445SDouglas Gilbert 
1352c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1353c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1354c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1355c65b1445SDouglas Gilbert 	olen = strlen(na2);
1356c65b1445SDouglas Gilbert 	plen = olen + 1;
1357c65b1445SDouglas Gilbert 	if (plen % 4)
1358c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1359c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1360c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1361c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1362c65b1445SDouglas Gilbert 	num += plen;
1363c65b1445SDouglas Gilbert 
1364c65b1445SDouglas Gilbert 	return num;
1365c65b1445SDouglas Gilbert }
1366c65b1445SDouglas Gilbert 
1367c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1368760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1369c65b1445SDouglas Gilbert {
1370c65b1445SDouglas Gilbert 	int num = 0;
1371c65b1445SDouglas Gilbert 	int port_a, port_b;
1372c65b1445SDouglas Gilbert 
1373c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1374c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1375c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1376c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1379c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1380c65b1445SDouglas Gilbert 	num += 6;
1381c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1382c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1383c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1385c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1386c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1387c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13881b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1389773642d9SDouglas Gilbert 	num += 8;
1390c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1393c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1394c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1395c65b1445SDouglas Gilbert 	num += 6;
1396c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1397c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1398c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1399c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1400c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1401c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1402c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
14031b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1404773642d9SDouglas Gilbert 	num += 8;
1405c65b1445SDouglas Gilbert 
1406c65b1445SDouglas Gilbert 	return num;
1407c65b1445SDouglas Gilbert }
1408c65b1445SDouglas Gilbert 
1409c65b1445SDouglas Gilbert 
1410c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1411c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1412c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1413c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1414c65b1445SDouglas Gilbert '1','2','3','4',
1415c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1416c65b1445SDouglas Gilbert 0xec,0,0,0,
1417c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1418c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1419c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1420c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1421c65b1445SDouglas Gilbert 0x53,0x41,
1422c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1423c65b1445SDouglas Gilbert 0x20,0x20,
1424c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1425c65b1445SDouglas Gilbert 0x10,0x80,
1426c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1427c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1428c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1429c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1430c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1431c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1436c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1437c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1438c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1439c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1441c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1442c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1443c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1444c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1445c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1446c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1448c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1449c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1452c65b1445SDouglas Gilbert };
1453c65b1445SDouglas Gilbert 
1454cbf67842SDouglas Gilbert /* ATA Information VPD page */
1455760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1456c65b1445SDouglas Gilbert {
1457c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1458c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1459c65b1445SDouglas Gilbert }
1460c65b1445SDouglas Gilbert 
1461c65b1445SDouglas Gilbert 
1462c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14631e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14641e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14651e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14661e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1467c65b1445SDouglas Gilbert };
1468c65b1445SDouglas Gilbert 
1469cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1470760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1471c65b1445SDouglas Gilbert {
1472ea61fca5SMartin K. Petersen 	unsigned int gran;
1473ea61fca5SMartin K. Petersen 
1474c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1475e308b3d1SMartin K. Petersen 
1476e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
147786e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
147886e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
147986e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
148086e6828aSLukas Herbolt 	else
1481773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1482773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1483e308b3d1SMartin K. Petersen 
1484e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1485773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1486773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
148744d92694SMartin K. Petersen 
1488e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1489773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1490e308b3d1SMartin K. Petersen 
1491773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1492e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1493773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1494e308b3d1SMartin K. Petersen 
1495e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1496773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
149744d92694SMartin K. Petersen 	}
149844d92694SMartin K. Petersen 
1499e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1500773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1501773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
150244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
150344d92694SMartin K. Petersen 	}
150444d92694SMartin K. Petersen 
1505e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1506773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
15076014759cSMartin K. Petersen 
15085b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1509773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15105b94e232SMartin K. Petersen 
15115b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
151244d92694SMartin K. Petersen 
1513c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15141da177e4SLinus Torvalds }
15151da177e4SLinus Torvalds 
15161e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
151764e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1518eac6e8e4SMatthew Wilcox {
1519eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1520eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15211e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15221e49f785SDouglas Gilbert 	arr[2] = 0;
15231e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
152464e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
152564e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1526eac6e8e4SMatthew Wilcox 
1527eac6e8e4SMatthew Wilcox 	return 0x3c;
1528eac6e8e4SMatthew Wilcox }
15291da177e4SLinus Torvalds 
1530760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1531760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15326014759cSMartin K. Petersen {
15333f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15346014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1535773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15366014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1537773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15386014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1539773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15405b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1541760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1542760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1543760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1544760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1545760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15463f0bc3b3SMartin K. Petersen 	return 0x4;
15476014759cSMartin K. Petersen }
15486014759cSMartin K. Petersen 
1549d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1550f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1551d36da305SDouglas Gilbert {
1552d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1553d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1554d36da305SDouglas Gilbert 	/*
1555d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1556d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1557f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1558f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1559d36da305SDouglas Gilbert 	 */
1560d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1561d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
156264e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1563f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1564f0d1cf93SDouglas Gilbert 	else
1565d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1566d36da305SDouglas Gilbert 	return 0x3c;
1567d36da305SDouglas Gilbert }
1568d36da305SDouglas Gilbert 
15691da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1570c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15711da177e4SLinus Torvalds 
1572c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15731da177e4SLinus Torvalds {
15741da177e4SLinus Torvalds 	unsigned char pq_pdt;
15755a09e398SHannes Reinecke 	unsigned char *arr;
157601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
157736e07d7eSGeorge Kennedy 	u32 alloc_len, n;
157836e07d7eSGeorge Kennedy 	int ret;
1579d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15801da177e4SLinus Torvalds 
1581773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15826f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15836f3cbf55SDouglas Gilbert 	if (! arr)
15846f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1585760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
158664e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1587d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1588b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1589c2248fc9SDouglas Gilbert 	if (have_wlun)
1590b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1591b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1592b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1593c65b1445SDouglas Gilbert 	else
1594773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15951da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15961da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
159722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15985a09e398SHannes Reinecke 		kfree(arr);
15991da177e4SLinus Torvalds 		return check_condition_result;
16001da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
160136e07d7eSGeorge Kennedy 		int lu_id_num, port_group_id, target_dev_id;
160236e07d7eSGeorge Kennedy 		u32 len;
1603c65b1445SDouglas Gilbert 		char lu_id_str[6];
1604c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
16051da177e4SLinus Torvalds 
16065a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16075a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1608b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
160923183910SDouglas Gilbert 			host_no = 0;
1610c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1611c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1612c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1613c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1614c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16151da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1616c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1617c65b1445SDouglas Gilbert 			n = 4;
1618c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1619c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1620c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1621c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1622c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1623c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1624c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1625c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1626d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1627c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1628760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1629760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1630d36da305SDouglas Gilbert 				if (is_disk)
1631d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
163264e14eceSDamien Le Moal 				if (is_zbc)
1633d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1634760f3b03SDouglas Gilbert 			}
1635c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16361da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1637c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16381da177e4SLinus Torvalds 			arr[3] = len;
1639c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16401da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1641c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1642760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16435a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
164409ba24c1SDouglas Gilbert 						lu_id_str, len,
164509ba24c1SDouglas Gilbert 						&devip->lu_name);
1646c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1647c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1648760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1649c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1650c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1651760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1652c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1653c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1654c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16558475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1656c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1657760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1658c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1659c6a44287SMartin K. Petersen 			else
1660c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1661c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1662c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1663c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1664c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1665c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1666c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1667c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1668c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1669c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1670c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1671760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1672d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1673c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1674760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1675773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1676d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1677c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1678760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1679d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1680eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
168164e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1682760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16836014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1684760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1685d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1686d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1687f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16881da177e4SLinus Torvalds 		} else {
168922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16905a09e398SHannes Reinecke 			kfree(arr);
16911da177e4SLinus Torvalds 			return check_condition_result;
16921da177e4SLinus Torvalds 		}
169336e07d7eSGeorge Kennedy 		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
16945a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
169536e07d7eSGeorge Kennedy 			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
16965a09e398SHannes Reinecke 		kfree(arr);
16975a09e398SHannes Reinecke 		return ret;
16981da177e4SLinus Torvalds 	}
16991da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1700773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1701773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
17021da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
17031da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1704f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1705b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
170670bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1707c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17081da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1709c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1710e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1711e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1712e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17139b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17149b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17151da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1716760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1717760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1718c65b1445SDouglas Gilbert 	n = 62;
1719760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1720760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1721760f3b03SDouglas Gilbert 		n += 2;
1722760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1723760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1724760f3b03SDouglas Gilbert 		n += 2;
1725d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1726d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1727d36da305SDouglas Gilbert 		n += 2;
17281da177e4SLinus Torvalds 	}
1729760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17305a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
173136e07d7eSGeorge Kennedy 			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17325a09e398SHannes Reinecke 	kfree(arr);
17335a09e398SHannes Reinecke 	return ret;
17341da177e4SLinus Torvalds }
17351da177e4SLinus Torvalds 
173684905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1737fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1738fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1739fd32119bSDouglas Gilbert 
17401da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17411da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17421da177e4SLinus Torvalds {
174301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
174484905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
174584905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
174636e07d7eSGeorge Kennedy 	u32 alloc_len = cmd[4];
174736e07d7eSGeorge Kennedy 	u32 len = 18;
174884905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17491da177e4SLinus Torvalds 
1750c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
175184905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
175284905d34SDouglas Gilbert 		if (dsense) {
175384905d34SDouglas Gilbert 			arr[0] = 0x72;
175484905d34SDouglas Gilbert 			arr[1] = NOT_READY;
175584905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
175684905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
175784905d34SDouglas Gilbert 			len = 8;
175884905d34SDouglas Gilbert 		} else {
175984905d34SDouglas Gilbert 			arr[0] = 0x70;
176084905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
176184905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
176284905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
176384905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
176484905d34SDouglas Gilbert 		}
176584905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
176684905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1767c2248fc9SDouglas Gilbert 		if (dsense) {
1768c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1769c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1770c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
177184905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1772c2248fc9SDouglas Gilbert 			len = 8;
1773c65b1445SDouglas Gilbert 		} else {
1774c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1775c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1776c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1777c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
177884905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1779c65b1445SDouglas Gilbert 		}
178084905d34SDouglas Gilbert 	} else {	/* nothing to report */
1781c2248fc9SDouglas Gilbert 		if (dsense) {
1782c2248fc9SDouglas Gilbert 			len = 8;
178384905d34SDouglas Gilbert 			memset(arr, 0, len);
178484905d34SDouglas Gilbert 			arr[0] = 0x72;
1785c2248fc9SDouglas Gilbert 		} else {
178684905d34SDouglas Gilbert 			memset(arr, 0, len);
1787c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1788c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1789c2248fc9SDouglas Gilbert 		}
1790c65b1445SDouglas Gilbert 	}
179136e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
1794fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1795c65b1445SDouglas Gilbert {
179601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1797fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
17984f2c8bf6SDouglas Gilbert 	bool changing;
1799c65b1445SDouglas Gilbert 
1800c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1801c65b1445SDouglas Gilbert 	if (power_cond) {
180222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1803c65b1445SDouglas Gilbert 		return check_condition_result;
1804c65b1445SDouglas Gilbert 	}
1805fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1806fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1807fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1808fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1809fc13638aSDouglas Gilbert 
1810fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1811fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1812fc13638aSDouglas Gilbert 
1813fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1814fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1815fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1816fc13638aSDouglas Gilbert 				stopped_state = 0;
1817fc13638aSDouglas Gilbert 			}
1818fc13638aSDouglas Gilbert 		}
1819fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1820fc13638aSDouglas Gilbert 			if (want_stop) {
1821fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1822fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1823fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1824fc13638aSDouglas Gilbert 				return check_condition_result;
1825fc13638aSDouglas Gilbert 			}
1826fc13638aSDouglas Gilbert 		}
1827fc13638aSDouglas Gilbert 	}
1828fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1829fc13638aSDouglas Gilbert 	if (changing)
1830fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1831fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18324f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18334f2c8bf6SDouglas Gilbert 	else
18344f2c8bf6SDouglas Gilbert 		return 0;
1835c65b1445SDouglas Gilbert }
1836c65b1445SDouglas Gilbert 
183728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
183828898873SFUJITA Tomonori {
1839773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1840773642d9SDouglas Gilbert 
1841773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1842773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1843773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
184428898873SFUJITA Tomonori 	else
184528898873SFUJITA Tomonori 		return sdebug_store_sectors;
184628898873SFUJITA Tomonori }
184728898873SFUJITA Tomonori 
18481da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18491da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18501da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18511da177e4SLinus Torvalds {
18521da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1853c65b1445SDouglas Gilbert 	unsigned int capac;
18541da177e4SLinus Torvalds 
1855c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
185628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18571da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1858c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1859c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1860773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1861773642d9SDouglas Gilbert 	} else
1862773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1863773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18641da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18651da177e4SLinus Torvalds }
18661da177e4SLinus Torvalds 
1867c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1868c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1869c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1870c65b1445SDouglas Gilbert {
187101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1872c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18734e3ace00SYe Bin 	u32 alloc_len;
1874c65b1445SDouglas Gilbert 
1875773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1876c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
187728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1878c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1879773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1880773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1881773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1882773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
188344d92694SMartin K. Petersen 
1884be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18855b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1886760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1887760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1888760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1889760f3b03SDouglas Gilbert 		 */
1890760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1891760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1892be1dd78dSEric Sandeen 	}
189344d92694SMartin K. Petersen 
1894773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1895c6a44287SMartin K. Petersen 
1896760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1897773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1898c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1899c6a44287SMartin K. Petersen 	}
1900c6a44287SMartin K. Petersen 
1901c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
19024e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1903c65b1445SDouglas Gilbert }
1904c65b1445SDouglas Gilbert 
19055a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19065a09e398SHannes Reinecke 
19075a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19085a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19095a09e398SHannes Reinecke {
191001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19115a09e398SHannes Reinecke 	unsigned char *arr;
19125a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19135a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1914f347c268SYe Bin 	u32 alen, n, rlen;
1915f347c268SYe Bin 	int ret;
19165a09e398SHannes Reinecke 
1917773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19186f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19196f3cbf55SDouglas Gilbert 	if (! arr)
19206f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19215a09e398SHannes Reinecke 	/*
19225a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19235a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19245a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19255a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19265a09e398SHannes Reinecke 	 */
19275a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19285a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19295a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19305a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19315a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19325a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19335a09e398SHannes Reinecke 
19345a09e398SHannes Reinecke 	/*
19355a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19365a09e398SHannes Reinecke 	 */
19375a09e398SHannes Reinecke 	n = 4;
1938b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19395a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19405a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19415a09e398SHannes Reinecke 	} else {
19425a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1943773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19445a09e398SHannes Reinecke 	}
1945773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1946773642d9SDouglas Gilbert 	n += 2;
19475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19505a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1953773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1954773642d9SDouglas Gilbert 	n += 2;
19555a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19565a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1957773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1958773642d9SDouglas Gilbert 	n += 2;
19595a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19605a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19615a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19625a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19645a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1965773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1966773642d9SDouglas Gilbert 	n += 2;
19675a09e398SHannes Reinecke 
19685a09e398SHannes Reinecke 	rlen = n - 4;
1969773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19705a09e398SHannes Reinecke 
19715a09e398SHannes Reinecke 	/*
19725a09e398SHannes Reinecke 	 * Return the smallest value of either
19735a09e398SHannes Reinecke 	 * - The allocated length
19745a09e398SHannes Reinecke 	 * - The constructed command length
19755a09e398SHannes Reinecke 	 * - The maximum array size
19765a09e398SHannes Reinecke 	 */
1977f347c268SYe Bin 	rlen = min(alen, n);
19785a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1979f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19805a09e398SHannes Reinecke 	kfree(arr);
19815a09e398SHannes Reinecke 	return ret;
19825a09e398SHannes Reinecke }
19835a09e398SHannes Reinecke 
1984fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1985fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
198638d5c833SDouglas Gilbert {
198738d5c833SDouglas Gilbert 	bool rctd;
198838d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
198938d5c833SDouglas Gilbert 	u16 req_sa, u;
199038d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
199138d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
199238d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
199338d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
199438d5c833SDouglas Gilbert 	u8 *arr;
199538d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
199638d5c833SDouglas Gilbert 
199738d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
199838d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
199938d5c833SDouglas Gilbert 	req_opcode = cmd[3];
200038d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
200138d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
20026d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
200338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
200438d5c833SDouglas Gilbert 		return check_condition_result;
200538d5c833SDouglas Gilbert 	}
200638d5c833SDouglas Gilbert 	if (alloc_len > 8192)
200738d5c833SDouglas Gilbert 		a_len = 8192;
200838d5c833SDouglas Gilbert 	else
200938d5c833SDouglas Gilbert 		a_len = alloc_len;
201099531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
201138d5c833SDouglas Gilbert 	if (NULL == arr) {
201238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
201338d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
201438d5c833SDouglas Gilbert 		return check_condition_result;
201538d5c833SDouglas Gilbert 	}
201638d5c833SDouglas Gilbert 	switch (reporting_opts) {
201738d5c833SDouglas Gilbert 	case 0:	/* all commands */
201838d5c833SDouglas Gilbert 		/* count number of commands */
201938d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
202038d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
202138d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
202238d5c833SDouglas Gilbert 				continue;
202338d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
202438d5c833SDouglas Gilbert 		}
202538d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
202638d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
202738d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
202838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
202938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
203038d5c833SDouglas Gilbert 				continue;
203138d5c833SDouglas Gilbert 			na = oip->num_attached;
203238d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
203338d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
203438d5c833SDouglas Gilbert 			if (rctd)
203538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
203638d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
203738d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
203838d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
203938d5c833SDouglas Gilbert 			if (rctd)
204038d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
204138d5c833SDouglas Gilbert 			r_oip = oip;
204238d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
204338d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
204438d5c833SDouglas Gilbert 					continue;
204538d5c833SDouglas Gilbert 				offset += bump;
204638d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
204738d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
204838d5c833SDouglas Gilbert 				if (rctd)
204938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
205038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
205138d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
205238d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
205338d5c833SDouglas Gilbert 						   arr + offset + 6);
205438d5c833SDouglas Gilbert 				if (rctd)
205538d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
205638d5c833SDouglas Gilbert 							   arr + offset + 8);
205738d5c833SDouglas Gilbert 			}
205838d5c833SDouglas Gilbert 			oip = r_oip;
205938d5c833SDouglas Gilbert 			offset += bump;
206038d5c833SDouglas Gilbert 		}
206138d5c833SDouglas Gilbert 		break;
206238d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
206338d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
206438d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
206538d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
206638d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
206738d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
206838d5c833SDouglas Gilbert 			supp = 1;
206938d5c833SDouglas Gilbert 			offset = 4;
207038d5c833SDouglas Gilbert 		} else {
207138d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
207238d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
207338d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
207438d5c833SDouglas Gilbert 							     2, 2);
207538d5c833SDouglas Gilbert 					kfree(arr);
207638d5c833SDouglas Gilbert 					return check_condition_result;
207738d5c833SDouglas Gilbert 				}
207838d5c833SDouglas Gilbert 				req_sa = 0;
207938d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
208038d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
208138d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
208238d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
208338d5c833SDouglas Gilbert 				return check_condition_result;
208438d5c833SDouglas Gilbert 			}
208538d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
208638d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
208738d5c833SDouglas Gilbert 				supp = 3;
208838d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
208938d5c833SDouglas Gilbert 				na = oip->num_attached;
209038d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
209138d5c833SDouglas Gilbert 				     ++k, ++oip) {
209238d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
209338d5c833SDouglas Gilbert 						break;
209438d5c833SDouglas Gilbert 				}
209538d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
209638d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
209738d5c833SDouglas Gilbert 				na = oip->num_attached;
209838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
209938d5c833SDouglas Gilbert 				     ++k, ++oip) {
210038d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
210138d5c833SDouglas Gilbert 						break;
210238d5c833SDouglas Gilbert 				}
210338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
210438d5c833SDouglas Gilbert 			} else
210538d5c833SDouglas Gilbert 				supp = 3;
210638d5c833SDouglas Gilbert 			if (3 == supp) {
210738d5c833SDouglas Gilbert 				u = oip->len_mask[0];
210838d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
210938d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
211038d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
211138d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
211238d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
211338d5c833SDouglas Gilbert 				offset = 4 + u;
211438d5c833SDouglas Gilbert 			} else
211538d5c833SDouglas Gilbert 				offset = 4;
211638d5c833SDouglas Gilbert 		}
211738d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
211838d5c833SDouglas Gilbert 		if (rctd) {
211938d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
212038d5c833SDouglas Gilbert 			offset += 12;
212138d5c833SDouglas Gilbert 		}
212238d5c833SDouglas Gilbert 		break;
212338d5c833SDouglas Gilbert 	default:
212438d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
212538d5c833SDouglas Gilbert 		kfree(arr);
212638d5c833SDouglas Gilbert 		return check_condition_result;
212738d5c833SDouglas Gilbert 	}
212838d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
212938d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
213038d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
213138d5c833SDouglas Gilbert 	kfree(arr);
213238d5c833SDouglas Gilbert 	return errsts;
213338d5c833SDouglas Gilbert }
213438d5c833SDouglas Gilbert 
2135fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2136fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
213738d5c833SDouglas Gilbert {
213838d5c833SDouglas Gilbert 	bool repd;
213938d5c833SDouglas Gilbert 	u32 alloc_len, len;
214038d5c833SDouglas Gilbert 	u8 arr[16];
214138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
214238d5c833SDouglas Gilbert 
214338d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
214438d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
214538d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
214638d5c833SDouglas Gilbert 	if (alloc_len < 4) {
214738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
214838d5c833SDouglas Gilbert 		return check_condition_result;
214938d5c833SDouglas Gilbert 	}
215038d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
215138d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
215238d5c833SDouglas Gilbert 	if (repd) {
215338d5c833SDouglas Gilbert 		arr[3] = 0xc;
215438d5c833SDouglas Gilbert 		len = 16;
215538d5c833SDouglas Gilbert 	} else
215638d5c833SDouglas Gilbert 		len = 4;
215738d5c833SDouglas Gilbert 
215838d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
215938d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
216038d5c833SDouglas Gilbert }
216138d5c833SDouglas Gilbert 
21621da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21651da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21661da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21671da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21681da177e4SLinus Torvalds 
21691da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21701da177e4SLinus Torvalds 	if (1 == pcontrol)
21711da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21721da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21731da177e4SLinus Torvalds }
21741da177e4SLinus Torvalds 
21751da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21761da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21771da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21781da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21791da177e4SLinus Torvalds 
21801da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21811da177e4SLinus Torvalds 	if (1 == pcontrol)
21821da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21831da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21841da177e4SLinus Torvalds }
21851da177e4SLinus Torvalds 
21861da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21871da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21881da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21891da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21901da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21911da177e4SLinus Torvalds 
21921da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2193773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2194773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2195773642d9SDouglas Gilbert 	if (sdebug_removable)
21961da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21971da177e4SLinus Torvalds 	if (1 == pcontrol)
21981da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21991da177e4SLinus Torvalds 	return sizeof(format_pg);
22001da177e4SLinus Torvalds }
22011da177e4SLinus Torvalds 
2202fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2203fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2204fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2205fd32119bSDouglas Gilbert 
22061da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22071da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2208cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2209cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2210cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22111da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22121da177e4SLinus Torvalds 
2213773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2214cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22151da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22161da177e4SLinus Torvalds 	if (1 == pcontrol)
2217cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2218cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2219cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22201da177e4SLinus Torvalds 	return sizeof(caching_pg);
22211da177e4SLinus Torvalds }
22221da177e4SLinus Torvalds 
2223fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2224fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2225fd32119bSDouglas Gilbert 
22261da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22271da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2228c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2229c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2230c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22311da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22321da177e4SLinus Torvalds 
2233773642d9SDouglas Gilbert 	if (sdebug_dsense)
22341da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2235c65b1445SDouglas Gilbert 	else
2236c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2237c6a44287SMartin K. Petersen 
2238773642d9SDouglas Gilbert 	if (sdebug_ato)
2239c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2240c6a44287SMartin K. Petersen 
22411da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22421da177e4SLinus Torvalds 	if (1 == pcontrol)
2243c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2244c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2245c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22461da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22471da177e4SLinus Torvalds }
22481da177e4SLinus Torvalds 
2249c65b1445SDouglas Gilbert 
22501da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22511da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2252c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22531da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2254c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2255c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2256c65b1445SDouglas Gilbert 
22571da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22581da177e4SLinus Torvalds 	if (1 == pcontrol)
2259c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2260c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2261c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22621da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22631da177e4SLinus Torvalds }
22641da177e4SLinus Torvalds 
2265c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2266c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2267c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2268c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2269c65b1445SDouglas Gilbert 
2270c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2271c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2272c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2273c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2274c65b1445SDouglas Gilbert }
2275c65b1445SDouglas Gilbert 
2276c65b1445SDouglas Gilbert 
2277c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2278c65b1445SDouglas Gilbert 			      int target_dev_id)
2279c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2280c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2281c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2282773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2283773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2284c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2285c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2286c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2287c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2288773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2289773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2290c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2291c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2292c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2293c65b1445SDouglas Gilbert 		};
2294c65b1445SDouglas Gilbert 	int port_a, port_b;
2295c65b1445SDouglas Gilbert 
22961b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22971b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22981b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22991b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2300c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2301c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2302c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2303773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2304773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2305c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2306c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2307c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2308c65b1445SDouglas Gilbert }
2309c65b1445SDouglas Gilbert 
2310c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2311c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2312c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2313c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2314c65b1445SDouglas Gilbert 		};
2315c65b1445SDouglas Gilbert 
2316c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2317c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2318c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2319c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2320c65b1445SDouglas Gilbert }
2321c65b1445SDouglas Gilbert 
23221da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23231da177e4SLinus Torvalds 
2324fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2325fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23261da177e4SLinus Torvalds {
232723183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23281da177e4SLinus Torvalds 	unsigned char dev_spec;
232936e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
233036e07d7eSGeorge Kennedy 	int target_dev_id;
2331c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23321da177e4SLinus Torvalds 	unsigned char *ap;
23331da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
233401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2335d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23361da177e4SLinus Torvalds 
2337760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23381da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23391da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23401da177e4SLinus Torvalds 	subpcode = cmd[3];
23411da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2342760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2343760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
234464e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2345d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
234623183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
234723183910SDouglas Gilbert 	else
234823183910SDouglas Gilbert 		bd_len = 0;
2349773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23501da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23511da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2352cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23531da177e4SLinus Torvalds 		return check_condition_result;
23541da177e4SLinus Torvalds 	}
2355c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2356c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2357d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2358d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2359b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23609447b6ceSMartin K. Petersen 		if (sdebug_wp)
23619447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23629447b6ceSMartin K. Petersen 	} else
236323183910SDouglas Gilbert 		dev_spec = 0x0;
23641da177e4SLinus Torvalds 	if (msense_6) {
23651da177e4SLinus Torvalds 		arr[2] = dev_spec;
236623183910SDouglas Gilbert 		arr[3] = bd_len;
23671da177e4SLinus Torvalds 		offset = 4;
23681da177e4SLinus Torvalds 	} else {
23691da177e4SLinus Torvalds 		arr[3] = dev_spec;
237023183910SDouglas Gilbert 		if (16 == bd_len)
237123183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
237223183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23731da177e4SLinus Torvalds 		offset = 8;
23741da177e4SLinus Torvalds 	}
23751da177e4SLinus Torvalds 	ap = arr + offset;
237628898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
237728898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
237828898873SFUJITA Tomonori 
237923183910SDouglas Gilbert 	if (8 == bd_len) {
2380773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2381773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2382773642d9SDouglas Gilbert 		else
2383773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2384773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
238523183910SDouglas Gilbert 		offset += bd_len;
238623183910SDouglas Gilbert 		ap = arr + offset;
238723183910SDouglas Gilbert 	} else if (16 == bd_len) {
2388773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2389773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
239023183910SDouglas Gilbert 		offset += bd_len;
239123183910SDouglas Gilbert 		ap = arr + offset;
239223183910SDouglas Gilbert 	}
23931da177e4SLinus Torvalds 
2394c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2395c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
239622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23971da177e4SLinus Torvalds 		return check_condition_result;
23981da177e4SLinus Torvalds 	}
2399760f3b03SDouglas Gilbert 	bad_pcode = false;
2400760f3b03SDouglas Gilbert 
24011da177e4SLinus Torvalds 	switch (pcode) {
24021da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
24031da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
24041da177e4SLinus Torvalds 		offset += len;
24051da177e4SLinus Torvalds 		break;
24061da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
24071da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24081da177e4SLinus Torvalds 		offset += len;
24091da177e4SLinus Torvalds 		break;
24101da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2411760f3b03SDouglas Gilbert 		if (is_disk) {
24121da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24131da177e4SLinus Torvalds 			offset += len;
2414760f3b03SDouglas Gilbert 		} else
2415760f3b03SDouglas Gilbert 			bad_pcode = true;
24161da177e4SLinus Torvalds 		break;
24171da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2418d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24191da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24201da177e4SLinus Torvalds 			offset += len;
2421760f3b03SDouglas Gilbert 		} else
2422760f3b03SDouglas Gilbert 			bad_pcode = true;
24231da177e4SLinus Torvalds 		break;
24241da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24251da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24261da177e4SLinus Torvalds 		offset += len;
24271da177e4SLinus Torvalds 		break;
2428c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2429c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
243022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2431c65b1445SDouglas Gilbert 			return check_condition_result;
2432c65b1445SDouglas Gilbert 		}
2433c65b1445SDouglas Gilbert 		len = 0;
2434c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2435c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2436c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2437c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2438c65b1445SDouglas Gilbert 						  target_dev_id);
2439c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2440c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2441c65b1445SDouglas Gilbert 		offset += len;
2442c65b1445SDouglas Gilbert 		break;
24431da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24441da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24451da177e4SLinus Torvalds 		offset += len;
24461da177e4SLinus Torvalds 		break;
24471da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2448c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24491da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24501da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2451760f3b03SDouglas Gilbert 			if (is_disk) {
2452760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2453760f3b03SDouglas Gilbert 						      target);
2454760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2455760f3b03SDouglas Gilbert 						       target);
2456d36da305SDouglas Gilbert 			} else if (is_zbc) {
2457d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2458d36da305SDouglas Gilbert 						       target);
2459760f3b03SDouglas Gilbert 			}
24601da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2461c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2462c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2463c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2464c65b1445SDouglas Gilbert 						  target, target_dev_id);
2465c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2466c65b1445SDouglas Gilbert 			}
24671da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2468760f3b03SDouglas Gilbert 			offset += len;
2469c65b1445SDouglas Gilbert 		} else {
247022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2471c65b1445SDouglas Gilbert 			return check_condition_result;
2472c65b1445SDouglas Gilbert 		}
24731da177e4SLinus Torvalds 		break;
24741da177e4SLinus Torvalds 	default:
2475760f3b03SDouglas Gilbert 		bad_pcode = true;
2476760f3b03SDouglas Gilbert 		break;
2477760f3b03SDouglas Gilbert 	}
2478760f3b03SDouglas Gilbert 	if (bad_pcode) {
247922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24801da177e4SLinus Torvalds 		return check_condition_result;
24811da177e4SLinus Torvalds 	}
24821da177e4SLinus Torvalds 	if (msense_6)
24831da177e4SLinus Torvalds 		arr[0] = offset - 1;
2484773642d9SDouglas Gilbert 	else
2485773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
248636e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
24871da177e4SLinus Torvalds }
24881da177e4SLinus Torvalds 
2489c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2490c65b1445SDouglas Gilbert 
2491fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2492fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2493c65b1445SDouglas Gilbert {
2494c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2495c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2496c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
249701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2498c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2499c65b1445SDouglas Gilbert 
2500c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2501c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2502c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2503773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2504c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
250522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2506c65b1445SDouglas Gilbert 		return check_condition_result;
2507c65b1445SDouglas Gilbert 	}
2508c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2509c65b1445SDouglas Gilbert 	if (-1 == res)
2510773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2511773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2512cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2513cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2514cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2515773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2516773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2517e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2518e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
251922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2520c65b1445SDouglas Gilbert 		return check_condition_result;
2521c65b1445SDouglas Gilbert 	}
2522c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2523c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2524c65b1445SDouglas Gilbert 	if (ps) {
252522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2526c65b1445SDouglas Gilbert 		return check_condition_result;
2527c65b1445SDouglas Gilbert 	}
2528c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2529773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2530c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2531c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2532cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2533c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2534c65b1445SDouglas Gilbert 		return check_condition_result;
2535c65b1445SDouglas Gilbert 	}
2536c65b1445SDouglas Gilbert 	switch (mpage) {
2537cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2538cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2539cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2540cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2541cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2542cbf67842SDouglas Gilbert 		}
2543cbf67842SDouglas Gilbert 		break;
2544c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2545c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2546c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2547c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25489447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25499447b6ceSMartin K. Petersen 				sdebug_wp = true;
25509447b6ceSMartin K. Petersen 			else
25519447b6ceSMartin K. Petersen 				sdebug_wp = false;
2552773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2553cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2554c65b1445SDouglas Gilbert 		}
2555c65b1445SDouglas Gilbert 		break;
2556c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2557c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2558c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2559c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2560cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2561c65b1445SDouglas Gilbert 		}
2562c65b1445SDouglas Gilbert 		break;
2563c65b1445SDouglas Gilbert 	default:
2564c65b1445SDouglas Gilbert 		break;
2565c65b1445SDouglas Gilbert 	}
256622017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2567c65b1445SDouglas Gilbert 	return check_condition_result;
2568cbf67842SDouglas Gilbert set_mode_changed_ua:
2569cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2570cbf67842SDouglas Gilbert 	return 0;
2571c65b1445SDouglas Gilbert }
2572c65b1445SDouglas Gilbert 
2573c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2574c65b1445SDouglas Gilbert {
2575c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2576c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2577c65b1445SDouglas Gilbert 		};
2578c65b1445SDouglas Gilbert 
2579c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2580c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2581c65b1445SDouglas Gilbert }
2582c65b1445SDouglas Gilbert 
2583c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2584c65b1445SDouglas Gilbert {
2585c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2586c65b1445SDouglas Gilbert 		};
2587c65b1445SDouglas Gilbert 
2588c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2589c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2590c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2591c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2592c65b1445SDouglas Gilbert 	}
2593c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2594c65b1445SDouglas Gilbert }
2595c65b1445SDouglas Gilbert 
25960790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr)
25970790797aSDouglas Gilbert {
25980790797aSDouglas Gilbert 	unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
25990790797aSDouglas Gilbert 					 0x0, 40, 72, 0xff, 45, 18, 0, 0,
26000790797aSDouglas Gilbert 					 0x1, 0x0, 0x23, 0x8,
26010790797aSDouglas Gilbert 					 0x0, 55, 72, 35, 55, 45, 0, 0,
26020790797aSDouglas Gilbert 		};
26030790797aSDouglas Gilbert 
26040790797aSDouglas Gilbert 	memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
26050790797aSDouglas Gilbert 	return sizeof(env_rep_l_spg);
26060790797aSDouglas Gilbert }
26070790797aSDouglas Gilbert 
2608c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2609c65b1445SDouglas Gilbert 
2610c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2611c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2612c65b1445SDouglas Gilbert {
261336e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
261436e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2615c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
261601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2617c65b1445SDouglas Gilbert 
2618c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2619c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2620c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2621c65b1445SDouglas Gilbert 	if (ppc || sp) {
262222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2623c65b1445SDouglas Gilbert 		return check_condition_result;
2624c65b1445SDouglas Gilbert 	}
2625c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
262623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2627773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2628c65b1445SDouglas Gilbert 	arr[0] = pcode;
262923183910SDouglas Gilbert 	if (0 == subpcode) {
2630c65b1445SDouglas Gilbert 		switch (pcode) {
2631c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2632c65b1445SDouglas Gilbert 			n = 4;
2633c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2634c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2635c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2636c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2637c65b1445SDouglas Gilbert 			break;
2638c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2639c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2640c65b1445SDouglas Gilbert 			break;
2641c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2642c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2643c65b1445SDouglas Gilbert 			break;
2644c65b1445SDouglas Gilbert 		default:
264522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2646c65b1445SDouglas Gilbert 			return check_condition_result;
2647c65b1445SDouglas Gilbert 		}
264823183910SDouglas Gilbert 	} else if (0xff == subpcode) {
264923183910SDouglas Gilbert 		arr[0] |= 0x40;
265023183910SDouglas Gilbert 		arr[1] = subpcode;
265123183910SDouglas Gilbert 		switch (pcode) {
265223183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
265323183910SDouglas Gilbert 			n = 4;
265423183910SDouglas Gilbert 			arr[n++] = 0x0;
265523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
265623183910SDouglas Gilbert 			arr[n++] = 0x0;
265723183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
265823183910SDouglas Gilbert 			arr[n++] = 0xd;
265923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26600790797aSDouglas Gilbert 			arr[n++] = 0xd;
26610790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26620790797aSDouglas Gilbert 			arr[n++] = 0xd;
26630790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0xd subpages */
266423183910SDouglas Gilbert 			arr[n++] = 0x2f;
266523183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
26660790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26670790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0x2f subpages */
266823183910SDouglas Gilbert 			arr[3] = n - 4;
266923183910SDouglas Gilbert 			break;
267023183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
267123183910SDouglas Gilbert 			n = 4;
267223183910SDouglas Gilbert 			arr[n++] = 0xd;
267323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26740790797aSDouglas Gilbert 			arr[n++] = 0xd;
26750790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26760790797aSDouglas Gilbert 			arr[n++] = 0xd;
26770790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
267823183910SDouglas Gilbert 			arr[3] = n - 4;
267923183910SDouglas Gilbert 			break;
268023183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
268123183910SDouglas Gilbert 			n = 4;
268223183910SDouglas Gilbert 			arr[n++] = 0x2f;
268323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
26840790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26850790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
268623183910SDouglas Gilbert 			arr[3] = n - 4;
268723183910SDouglas Gilbert 			break;
268823183910SDouglas Gilbert 		default:
268922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
269023183910SDouglas Gilbert 			return check_condition_result;
269123183910SDouglas Gilbert 		}
26920790797aSDouglas Gilbert 	} else if (subpcode > 0) {
26930790797aSDouglas Gilbert 		arr[0] |= 0x40;
26940790797aSDouglas Gilbert 		arr[1] = subpcode;
26950790797aSDouglas Gilbert 		if (pcode == 0xd && subpcode == 1)
26960790797aSDouglas Gilbert 			arr[3] = resp_env_rep_l_spg(arr + 4);
26970790797aSDouglas Gilbert 		else {
26980790797aSDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
26990790797aSDouglas Gilbert 			return check_condition_result;
27000790797aSDouglas Gilbert 		}
270123183910SDouglas Gilbert 	} else {
270222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
270323183910SDouglas Gilbert 		return check_condition_result;
270423183910SDouglas Gilbert 	}
270536e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2706c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
270736e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2708c65b1445SDouglas Gilbert }
2709c65b1445SDouglas Gilbert 
2710f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2711f0d1cf93SDouglas Gilbert {
2712f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2713f0d1cf93SDouglas Gilbert }
2714f0d1cf93SDouglas Gilbert 
2715f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2716f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2717f0d1cf93SDouglas Gilbert {
2718108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2719f0d1cf93SDouglas Gilbert }
2720f0d1cf93SDouglas Gilbert 
2721f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2722f0d1cf93SDouglas Gilbert {
272364e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2724f0d1cf93SDouglas Gilbert }
2725f0d1cf93SDouglas Gilbert 
2726f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2727f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2728f0d1cf93SDouglas Gilbert {
2729f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2730f0d1cf93SDouglas Gilbert 
2731f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2732f0d1cf93SDouglas Gilbert 		return;
2733f0d1cf93SDouglas Gilbert 
2734f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2735f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2736f0d1cf93SDouglas Gilbert 		return;
2737f0d1cf93SDouglas Gilbert 
2738f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2739f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2740f0d1cf93SDouglas Gilbert 	else
2741f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2742f0d1cf93SDouglas Gilbert 
2743f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2744f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2745f0d1cf93SDouglas Gilbert 	} else {
2746f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2747f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2748f0d1cf93SDouglas Gilbert 	}
2749f0d1cf93SDouglas Gilbert }
2750f0d1cf93SDouglas Gilbert 
2751f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2752f0d1cf93SDouglas Gilbert {
2753f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2754f0d1cf93SDouglas Gilbert 	unsigned int i;
2755f0d1cf93SDouglas Gilbert 
2756f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2757f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2758f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2759f0d1cf93SDouglas Gilbert 			return;
2760f0d1cf93SDouglas Gilbert 		}
2761f0d1cf93SDouglas Gilbert 	}
2762f0d1cf93SDouglas Gilbert }
2763f0d1cf93SDouglas Gilbert 
2764f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2765f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2766f0d1cf93SDouglas Gilbert {
2767f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2768f0d1cf93SDouglas Gilbert 
2769f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2770f0d1cf93SDouglas Gilbert 		return;
2771f0d1cf93SDouglas Gilbert 
2772f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2773f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2774f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2775f0d1cf93SDouglas Gilbert 		return;
2776f0d1cf93SDouglas Gilbert 
2777f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2778f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2779f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2780f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2781f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2782f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2783f0d1cf93SDouglas Gilbert 
2784f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2785f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2786f0d1cf93SDouglas Gilbert 	if (explicit) {
2787f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2788f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2789f0d1cf93SDouglas Gilbert 	} else {
2790f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2791f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2792f0d1cf93SDouglas Gilbert 	}
2793f0d1cf93SDouglas Gilbert }
2794f0d1cf93SDouglas Gilbert 
2795f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2796f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2797f0d1cf93SDouglas Gilbert {
2798f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
279964e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2800f0d1cf93SDouglas Gilbert 
2801f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2802f0d1cf93SDouglas Gilbert 		return;
2803f0d1cf93SDouglas Gilbert 
280464e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2805f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
280664e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2807f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
280864e14eceSDamien Le Moal 		return;
280964e14eceSDamien Le Moal 	}
281064e14eceSDamien Le Moal 
281164e14eceSDamien Le Moal 	while (num) {
281264e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
281364e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
281464e14eceSDamien Le Moal 
281564e14eceSDamien Le Moal 		end = lba + num;
281664e14eceSDamien Le Moal 		if (end >= zend) {
281764e14eceSDamien Le Moal 			n = zend - lba;
281864e14eceSDamien Le Moal 			zsp->z_wp = zend;
281964e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
282064e14eceSDamien Le Moal 			n = num;
282164e14eceSDamien Le Moal 			zsp->z_wp = end;
282264e14eceSDamien Le Moal 		} else {
282364e14eceSDamien Le Moal 			n = num;
282464e14eceSDamien Le Moal 		}
282564e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
282664e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
282764e14eceSDamien Le Moal 
282864e14eceSDamien Le Moal 		num -= n;
282964e14eceSDamien Le Moal 		lba += n;
283064e14eceSDamien Le Moal 		if (num) {
283164e14eceSDamien Le Moal 			zsp++;
283264e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
283364e14eceSDamien Le Moal 		}
283464e14eceSDamien Le Moal 	}
2835f0d1cf93SDouglas Gilbert }
2836f0d1cf93SDouglas Gilbert 
2837f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
28389447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
28391da177e4SLinus Torvalds {
2840f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2841f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2842f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2843f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2844f0d1cf93SDouglas Gilbert 
2845f0d1cf93SDouglas Gilbert 	if (!write) {
284664e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
284764e14eceSDamien Le Moal 			return 0;
284864e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2849f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2850f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2851f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2852f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2853f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2854f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2855f0d1cf93SDouglas Gilbert 			return check_condition_result;
2856f0d1cf93SDouglas Gilbert 		}
2857f0d1cf93SDouglas Gilbert 		return 0;
2858f0d1cf93SDouglas Gilbert 	}
2859f0d1cf93SDouglas Gilbert 
2860f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2861f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2862f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2863f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2864f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2865f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2866f0d1cf93SDouglas Gilbert 			return check_condition_result;
2867f0d1cf93SDouglas Gilbert 		}
2868f0d1cf93SDouglas Gilbert 		return 0;
2869f0d1cf93SDouglas Gilbert 	}
2870f0d1cf93SDouglas Gilbert 
287164e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2872f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2873f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2874f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2875f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2876f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2877f0d1cf93SDouglas Gilbert 			return check_condition_result;
2878f0d1cf93SDouglas Gilbert 		}
2879f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2880f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2881f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2882f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2883f0d1cf93SDouglas Gilbert 			return check_condition_result;
2884f0d1cf93SDouglas Gilbert 		}
2885f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2886f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2887f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2888f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2889f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2890f0d1cf93SDouglas Gilbert 			return check_condition_result;
2891f0d1cf93SDouglas Gilbert 		}
289264e14eceSDamien Le Moal 	}
2893f0d1cf93SDouglas Gilbert 
2894f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2895f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2896f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2897f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2898f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2899f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2900f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2901f0d1cf93SDouglas Gilbert 			return check_condition_result;
2902f0d1cf93SDouglas Gilbert 		}
2903f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2904f0d1cf93SDouglas Gilbert 	}
2905f0d1cf93SDouglas Gilbert 
2906f0d1cf93SDouglas Gilbert 	return 0;
2907f0d1cf93SDouglas Gilbert }
2908f0d1cf93SDouglas Gilbert 
2909f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2910f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2911f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2912f0d1cf93SDouglas Gilbert {
2913f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2914f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2915f0d1cf93SDouglas Gilbert 
2916c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
291722017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
29181da177e4SLinus Torvalds 		return check_condition_result;
29191da177e4SLinus Torvalds 	}
2920c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2921c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
292222017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2923cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2924c65b1445SDouglas Gilbert 		return check_condition_result;
2925c65b1445SDouglas Gilbert 	}
29269447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
29279447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29289447b6ceSMartin K. Petersen 		return check_condition_result;
29299447b6ceSMartin K. Petersen 	}
2930f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2931f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2932f0d1cf93SDouglas Gilbert 
293319789100SFUJITA Tomonori 	return 0;
293419789100SFUJITA Tomonori }
293519789100SFUJITA Tomonori 
2936b6ff8ca7SDouglas Gilbert /*
2937b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2938b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2939b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2940b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2941b6ff8ca7SDouglas Gilbert  */
2942b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2943b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
294487c715dcSDouglas Gilbert {
2945b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2946b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2947b6ff8ca7SDouglas Gilbert 		return NULL;
2948b6ff8ca7SDouglas Gilbert 	}
2949b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
295087c715dcSDouglas Gilbert }
295187c715dcSDouglas Gilbert 
2952a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
295387c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
295487c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
295519789100SFUJITA Tomonori {
295619789100SFUJITA Tomonori 	int ret;
2957c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2958a4517511SAkinobu Mita 	enum dma_data_direction dir;
295987c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
296087c715dcSDouglas Gilbert 	u8 *fsp;
296119789100SFUJITA Tomonori 
2962c2248fc9SDouglas Gilbert 	if (do_write) {
2963a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
29644f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2965a4517511SAkinobu Mita 	} else {
2966a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2967a4517511SAkinobu Mita 	}
2968a4517511SAkinobu Mita 
296987c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2970a4517511SAkinobu Mita 		return 0;
297187c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2972a4517511SAkinobu Mita 		return -1;
297387c715dcSDouglas Gilbert 	fsp = sip->storep;
297419789100SFUJITA Tomonori 
297519789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
297619789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
297719789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
297819789100SFUJITA Tomonori 
2979386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
298087c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29810a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2982773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2983a4517511SAkinobu Mita 		return ret;
2984a4517511SAkinobu Mita 
2985a4517511SAkinobu Mita 	if (rest) {
2986386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
298787c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29880a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29890a7e69c7SDouglas Gilbert 			    do_write);
2990a4517511SAkinobu Mita 	}
299119789100SFUJITA Tomonori 
299219789100SFUJITA Tomonori 	return ret;
299319789100SFUJITA Tomonori }
299419789100SFUJITA Tomonori 
299587c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
299687c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
299787c715dcSDouglas Gilbert {
299887c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
299987c715dcSDouglas Gilbert 
300087c715dcSDouglas Gilbert 	if (!sdb->length)
300187c715dcSDouglas Gilbert 		return 0;
300287c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
300387c715dcSDouglas Gilbert 		return -1;
300487c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
300587c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
300687c715dcSDouglas Gilbert }
300787c715dcSDouglas Gilbert 
300887c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
300987c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
301038d5c833SDouglas Gilbert  * return false. */
301187c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
3012c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
301338d5c833SDouglas Gilbert {
301438d5c833SDouglas Gilbert 	bool res;
301538d5c833SDouglas Gilbert 	u64 block, rest = 0;
301638d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
3017773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
301887c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
301938d5c833SDouglas Gilbert 
302038d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
302138d5c833SDouglas Gilbert 	if (block + num > store_blks)
302238d5c833SDouglas Gilbert 		rest = block + num - store_blks;
302338d5c833SDouglas Gilbert 
302487c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
302538d5c833SDouglas Gilbert 	if (!res)
302638d5c833SDouglas Gilbert 		return res;
302738d5c833SDouglas Gilbert 	if (rest)
302887c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
302938d5c833SDouglas Gilbert 			     rest * lb_size);
303038d5c833SDouglas Gilbert 	if (!res)
303138d5c833SDouglas Gilbert 		return res;
3032c3e2fe92SDouglas Gilbert 	if (compare_only)
3033c3e2fe92SDouglas Gilbert 		return true;
303438d5c833SDouglas Gilbert 	arr += num * lb_size;
303587c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
303638d5c833SDouglas Gilbert 	if (rest)
303787c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
303838d5c833SDouglas Gilbert 	return res;
303938d5c833SDouglas Gilbert }
304038d5c833SDouglas Gilbert 
304151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3042beb40ea4SAkinobu Mita {
304351d648afSAkinobu Mita 	__be16 csum;
3044beb40ea4SAkinobu Mita 
3045773642d9SDouglas Gilbert 	if (sdebug_guard)
304651d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
304751d648afSAkinobu Mita 	else
3048beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
304951d648afSAkinobu Mita 
3050beb40ea4SAkinobu Mita 	return csum;
3051beb40ea4SAkinobu Mita }
3052beb40ea4SAkinobu Mita 
30536ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3054beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3055beb40ea4SAkinobu Mita {
3056773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3057beb40ea4SAkinobu Mita 
3058beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3059c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3060beb40ea4SAkinobu Mita 			(unsigned long)sector,
3061beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3062beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3063beb40ea4SAkinobu Mita 		return 0x01;
3064beb40ea4SAkinobu Mita 	}
30658475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3066beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3067c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3068c1287970STomas Winkler 			(unsigned long)sector);
3069beb40ea4SAkinobu Mita 		return 0x03;
3070beb40ea4SAkinobu Mita 	}
30718475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3072beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3073c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3074c1287970STomas Winkler 			(unsigned long)sector);
3075beb40ea4SAkinobu Mita 		return 0x03;
3076beb40ea4SAkinobu Mita 	}
3077beb40ea4SAkinobu Mita 	return 0;
3078beb40ea4SAkinobu Mita }
3079beb40ea4SAkinobu Mita 
308087c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
308165f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3082c6a44287SMartin K. Petersen {
3083be4e11beSAkinobu Mita 	size_t resid;
3084c6a44287SMartin K. Petersen 	void *paddr;
308587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3086b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
308787c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
308814faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3089be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3090c6a44287SMartin K. Petersen 
3091e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3092e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3093c6a44287SMartin K. Petersen 
309487c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
309587c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3096be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3097be4e11beSAkinobu Mita 
3098be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
309987c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
310087c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3101be4e11beSAkinobu Mita 		size_t rest = 0;
310214faa944SAkinobu Mita 
310314faa944SAkinobu Mita 		if (dif_store_end < start + len)
310414faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3105c6a44287SMartin K. Petersen 
3106be4e11beSAkinobu Mita 		paddr = miter.addr;
310714faa944SAkinobu Mita 
310865f72f2aSAkinobu Mita 		if (read)
310965f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
311065f72f2aSAkinobu Mita 		else
311165f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
311265f72f2aSAkinobu Mita 
311365f72f2aSAkinobu Mita 		if (rest) {
311465f72f2aSAkinobu Mita 			if (read)
311514faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
311665f72f2aSAkinobu Mita 			else
311765f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
311865f72f2aSAkinobu Mita 		}
3119c6a44287SMartin K. Petersen 
3120e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3121c6a44287SMartin K. Petersen 		resid -= len;
3122c6a44287SMartin K. Petersen 	}
3123be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3124bb8c063cSAkinobu Mita }
3125c6a44287SMartin K. Petersen 
312687c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3127bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3128bb8c063cSAkinobu Mita {
3129f7be6772SMartin K. Petersen 	int ret = 0;
3130bb8c063cSAkinobu Mita 	unsigned int i;
3131bb8c063cSAkinobu Mita 	sector_t sector;
313287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3133b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
313487c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3135bb8c063cSAkinobu Mita 
3136c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3137bb8c063cSAkinobu Mita 		sector = start_sec + i;
313887c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3139bb8c063cSAkinobu Mita 
314051d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3141bb8c063cSAkinobu Mita 			continue;
3142bb8c063cSAkinobu Mita 
3143f7be6772SMartin K. Petersen 		/*
3144f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3145f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3146f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3147f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3148f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3149f7be6772SMartin K. Petersen 		 */
3150f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3151f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3152f7be6772SMartin K. Petersen 					 sector, ei_lba);
3153bb8c063cSAkinobu Mita 			if (ret) {
3154bb8c063cSAkinobu Mita 				dif_errors++;
3155f7be6772SMartin K. Petersen 				break;
3156f7be6772SMartin K. Petersen 			}
3157bb8c063cSAkinobu Mita 		}
3158bb8c063cSAkinobu Mita 	}
3159bb8c063cSAkinobu Mita 
316087c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3161c6a44287SMartin K. Petersen 	dix_reads++;
3162c6a44287SMartin K. Petersen 
3163f7be6772SMartin K. Petersen 	return ret;
3164c6a44287SMartin K. Petersen }
3165c6a44287SMartin K. Petersen 
31667109f370SDouglas Gilbert static inline void
31677109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip)
31687109f370SDouglas Gilbert {
3169e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3170e9c47801SDamien Le Moal 		if (sip)
3171e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3172e9c47801SDamien Le Moal 		else
3173e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3174e9c47801SDamien Le Moal 	} else {
31757109f370SDouglas Gilbert 		if (sip)
31767109f370SDouglas Gilbert 			read_lock(&sip->macc_lck);
31777109f370SDouglas Gilbert 		else
31787109f370SDouglas Gilbert 			read_lock(&sdeb_fake_rw_lck);
31797109f370SDouglas Gilbert 	}
3180e9c47801SDamien Le Moal }
31817109f370SDouglas Gilbert 
31827109f370SDouglas Gilbert static inline void
31837109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip)
31847109f370SDouglas Gilbert {
3185e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3186e9c47801SDamien Le Moal 		if (sip)
3187e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3188e9c47801SDamien Le Moal 		else
3189e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3190e9c47801SDamien Le Moal 	} else {
31917109f370SDouglas Gilbert 		if (sip)
31927109f370SDouglas Gilbert 			read_unlock(&sip->macc_lck);
31937109f370SDouglas Gilbert 		else
31947109f370SDouglas Gilbert 			read_unlock(&sdeb_fake_rw_lck);
31957109f370SDouglas Gilbert 	}
3196e9c47801SDamien Le Moal }
31977109f370SDouglas Gilbert 
31987109f370SDouglas Gilbert static inline void
31997109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip)
32007109f370SDouglas Gilbert {
3201e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3202e9c47801SDamien Le Moal 		if (sip)
3203e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3204e9c47801SDamien Le Moal 		else
3205e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3206e9c47801SDamien Le Moal 	} else {
32077109f370SDouglas Gilbert 		if (sip)
32087109f370SDouglas Gilbert 			write_lock(&sip->macc_lck);
32097109f370SDouglas Gilbert 		else
32107109f370SDouglas Gilbert 			write_lock(&sdeb_fake_rw_lck);
32117109f370SDouglas Gilbert 	}
3212e9c47801SDamien Le Moal }
32137109f370SDouglas Gilbert 
32147109f370SDouglas Gilbert static inline void
32157109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip)
32167109f370SDouglas Gilbert {
3217e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3218e9c47801SDamien Le Moal 		if (sip)
3219e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3220e9c47801SDamien Le Moal 		else
3221e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3222e9c47801SDamien Le Moal 	} else {
32237109f370SDouglas Gilbert 		if (sip)
32247109f370SDouglas Gilbert 			write_unlock(&sip->macc_lck);
32257109f370SDouglas Gilbert 		else
32267109f370SDouglas Gilbert 			write_unlock(&sdeb_fake_rw_lck);
32277109f370SDouglas Gilbert 	}
3228e9c47801SDamien Le Moal }
32297109f370SDouglas Gilbert 
3230fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
323119789100SFUJITA Tomonori {
323287c715dcSDouglas Gilbert 	bool check_prot;
3233c2248fc9SDouglas Gilbert 	u32 num;
3234c2248fc9SDouglas Gilbert 	u32 ei_lba;
323519789100SFUJITA Tomonori 	int ret;
323687c715dcSDouglas Gilbert 	u64 lba;
3237b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
323887c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
323919789100SFUJITA Tomonori 
3240c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3241c2248fc9SDouglas Gilbert 	case READ_16:
3242c2248fc9SDouglas Gilbert 		ei_lba = 0;
3243c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3244c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3245c2248fc9SDouglas Gilbert 		check_prot = true;
3246c2248fc9SDouglas Gilbert 		break;
3247c2248fc9SDouglas Gilbert 	case READ_10:
3248c2248fc9SDouglas Gilbert 		ei_lba = 0;
3249c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3250c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3251c2248fc9SDouglas Gilbert 		check_prot = true;
3252c2248fc9SDouglas Gilbert 		break;
3253c2248fc9SDouglas Gilbert 	case READ_6:
3254c2248fc9SDouglas Gilbert 		ei_lba = 0;
3255c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3256c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3257c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3258c2248fc9SDouglas Gilbert 		check_prot = true;
3259c2248fc9SDouglas Gilbert 		break;
3260c2248fc9SDouglas Gilbert 	case READ_12:
3261c2248fc9SDouglas Gilbert 		ei_lba = 0;
3262c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3263c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3264c2248fc9SDouglas Gilbert 		check_prot = true;
3265c2248fc9SDouglas Gilbert 		break;
3266c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3267c2248fc9SDouglas Gilbert 		ei_lba = 0;
3268c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3269c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3270c2248fc9SDouglas Gilbert 		check_prot = false;
3271c2248fc9SDouglas Gilbert 		break;
3272c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3273c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3274c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3275c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3276c2248fc9SDouglas Gilbert 		check_prot = false;
3277c2248fc9SDouglas Gilbert 		break;
3278c2248fc9SDouglas Gilbert 	}
3279f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
32808475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3281c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3282c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3283c2248fc9SDouglas Gilbert 			return check_condition_result;
3284c2248fc9SDouglas Gilbert 		}
32858475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
32868475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3287c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3288c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3289c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3290c2248fc9SDouglas Gilbert 	}
32913a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
32923a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3293c2248fc9SDouglas Gilbert 		num /= 2;
32943a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3295c2248fc9SDouglas Gilbert 	}
3296c2248fc9SDouglas Gilbert 
32979447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
32989447b6ceSMartin K. Petersen 	if (ret)
32999447b6ceSMartin K. Petersen 		return ret;
3300f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3301d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3302d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3303c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3304c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3305c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3306c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3307c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
330832f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
330932f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3310c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3311c65b1445SDouglas Gilbert 		}
3312c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
33131da177e4SLinus Torvalds 		return check_condition_result;
33141da177e4SLinus Torvalds 	}
3315c6a44287SMartin K. Petersen 
33167109f370SDouglas Gilbert 	sdeb_read_lock(sip);
33176c78cc06SAkinobu Mita 
3318c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3319f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3320f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3321f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3322f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33237109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3324f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3325f7be6772SMartin K. Petersen 				return check_condition_result;
3326f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
33277109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3328f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3329c6a44287SMartin K. Petersen 				return illegal_condition_result;
3330c6a44287SMartin K. Petersen 			}
3331f7be6772SMartin K. Petersen 			break;
3332f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3333f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33347109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3335f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3336f7be6772SMartin K. Petersen 				return check_condition_result;
3337f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
33387109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3339f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3340f7be6772SMartin K. Petersen 				return illegal_condition_result;
3341f7be6772SMartin K. Petersen 			}
3342f7be6772SMartin K. Petersen 			break;
3343f7be6772SMartin K. Petersen 		}
3344c6a44287SMartin K. Petersen 	}
3345c6a44287SMartin K. Petersen 
334687c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
33477109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
3348f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3349a4517511SAkinobu Mita 		return DID_ERROR << 16;
3350a4517511SAkinobu Mita 
335142d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3352a4517511SAkinobu Mita 
33533a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
33543a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
33553a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
33563a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
33573a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3358c2248fc9SDouglas Gilbert 			return check_condition_result;
33593a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3360c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3361c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
33623a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3363c2248fc9SDouglas Gilbert 			return illegal_condition_result;
33643a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3365c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
33663a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3367c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3368c2248fc9SDouglas Gilbert 		}
3369c2248fc9SDouglas Gilbert 	}
3370a4517511SAkinobu Mita 	return 0;
33711da177e4SLinus Torvalds }
33721da177e4SLinus Torvalds 
3373c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3374395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3375c6a44287SMartin K. Petersen {
3376be4e11beSAkinobu Mita 	int ret;
33776ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3378be4e11beSAkinobu Mita 	void *daddr;
337965f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3380c6a44287SMartin K. Petersen 	int ppage_offset;
3381be4e11beSAkinobu Mita 	int dpage_offset;
3382be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3383be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3384c6a44287SMartin K. Petersen 
3385c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3386c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3387c6a44287SMartin K. Petersen 
3388be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3389be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3390be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3391be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3392be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3393c6a44287SMartin K. Petersen 
3394be4e11beSAkinobu Mita 	/* For each protection page */
3395be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3396be4e11beSAkinobu Mita 		dpage_offset = 0;
3397be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3398be4e11beSAkinobu Mita 			ret = 0x01;
3399be4e11beSAkinobu Mita 			goto out;
3400c6a44287SMartin K. Petersen 		}
3401c6a44287SMartin K. Petersen 
3402be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
34036ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3404be4e11beSAkinobu Mita 			/* If we're at the end of the current
3405be4e11beSAkinobu Mita 			 * data page advance to the next one
3406be4e11beSAkinobu Mita 			 */
3407be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3408be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3409be4e11beSAkinobu Mita 					ret = 0x01;
3410be4e11beSAkinobu Mita 					goto out;
3411be4e11beSAkinobu Mita 				}
3412be4e11beSAkinobu Mita 				dpage_offset = 0;
3413be4e11beSAkinobu Mita 			}
3414c6a44287SMartin K. Petersen 
3415be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3416be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3417be4e11beSAkinobu Mita 
3418f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3419be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3420c78be80dSMartin K. Petersen 				if (ret)
3421395cef03SMartin K. Petersen 					goto out;
3422395cef03SMartin K. Petersen 			}
3423395cef03SMartin K. Petersen 
3424c6a44287SMartin K. Petersen 			sector++;
3425395cef03SMartin K. Petersen 			ei_lba++;
3426773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3427c6a44287SMartin K. Petersen 		}
3428be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3429be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3430c6a44287SMartin K. Petersen 	}
3431be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3432c6a44287SMartin K. Petersen 
343365f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3434c6a44287SMartin K. Petersen 	dix_writes++;
3435c6a44287SMartin K. Petersen 
3436c6a44287SMartin K. Petersen 	return 0;
3437c6a44287SMartin K. Petersen 
3438c6a44287SMartin K. Petersen out:
3439c6a44287SMartin K. Petersen 	dif_errors++;
3440be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3441be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3442c6a44287SMartin K. Petersen 	return ret;
3443c6a44287SMartin K. Petersen }
3444c6a44287SMartin K. Petersen 
3445b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3446b90ebc3dSAkinobu Mita {
3447773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3448773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3449773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3450b90ebc3dSAkinobu Mita 	return lba;
3451b90ebc3dSAkinobu Mita }
3452b90ebc3dSAkinobu Mita 
3453b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3454b90ebc3dSAkinobu Mita {
3455773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3456a027b5b9SAkinobu Mita 
3457773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3458773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3459a027b5b9SAkinobu Mita 	return lba;
3460a027b5b9SAkinobu Mita }
3461a027b5b9SAkinobu Mita 
346287c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
346387c715dcSDouglas Gilbert 			      unsigned int *num)
346444d92694SMartin K. Petersen {
3465b90ebc3dSAkinobu Mita 	sector_t end;
3466b90ebc3dSAkinobu Mita 	unsigned int mapped;
3467b90ebc3dSAkinobu Mita 	unsigned long index;
3468b90ebc3dSAkinobu Mita 	unsigned long next;
346944d92694SMartin K. Petersen 
3470b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
347187c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
347244d92694SMartin K. Petersen 
347344d92694SMartin K. Petersen 	if (mapped)
347487c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
347544d92694SMartin K. Petersen 	else
347687c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
347744d92694SMartin K. Petersen 
3478b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
347944d92694SMartin K. Petersen 	*num = end - lba;
348044d92694SMartin K. Petersen 	return mapped;
348144d92694SMartin K. Petersen }
348244d92694SMartin K. Petersen 
348387c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
348487c715dcSDouglas Gilbert 		       unsigned int len)
348544d92694SMartin K. Petersen {
348644d92694SMartin K. Petersen 	sector_t end = lba + len;
348744d92694SMartin K. Petersen 
348844d92694SMartin K. Petersen 	while (lba < end) {
3489b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
349044d92694SMartin K. Petersen 
3491b90ebc3dSAkinobu Mita 		if (index < map_size)
349287c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
349344d92694SMartin K. Petersen 
3494b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
349544d92694SMartin K. Petersen 	}
349644d92694SMartin K. Petersen }
349744d92694SMartin K. Petersen 
349887c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
349987c715dcSDouglas Gilbert 			 unsigned int len)
350044d92694SMartin K. Petersen {
350144d92694SMartin K. Petersen 	sector_t end = lba + len;
350287c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
350344d92694SMartin K. Petersen 
350444d92694SMartin K. Petersen 	while (lba < end) {
3505b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
350644d92694SMartin K. Petersen 
3507b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3508773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3509b90ebc3dSAkinobu Mita 		    index < map_size) {
351087c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3511760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
351287c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3513760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3514773642d9SDouglas Gilbert 				       sdebug_sector_size *
3515773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3516be1dd78dSEric Sandeen 			}
351787c715dcSDouglas Gilbert 			if (sip->dif_storep) {
351887c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
351987c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3520773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3521e9926b43SAkinobu Mita 			}
3522b90ebc3dSAkinobu Mita 		}
3523b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
352444d92694SMartin K. Petersen 	}
352544d92694SMartin K. Petersen }
352644d92694SMartin K. Petersen 
3527fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
35281da177e4SLinus Torvalds {
352987c715dcSDouglas Gilbert 	bool check_prot;
3530c2248fc9SDouglas Gilbert 	u32 num;
3531c2248fc9SDouglas Gilbert 	u32 ei_lba;
353219789100SFUJITA Tomonori 	int ret;
353387c715dcSDouglas Gilbert 	u64 lba;
3534b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
353587c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
35361da177e4SLinus Torvalds 
3537c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3538c2248fc9SDouglas Gilbert 	case WRITE_16:
3539c2248fc9SDouglas Gilbert 		ei_lba = 0;
3540c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3541c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3542c2248fc9SDouglas Gilbert 		check_prot = true;
3543c2248fc9SDouglas Gilbert 		break;
3544c2248fc9SDouglas Gilbert 	case WRITE_10:
3545c2248fc9SDouglas Gilbert 		ei_lba = 0;
3546c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3547c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3548c2248fc9SDouglas Gilbert 		check_prot = true;
3549c2248fc9SDouglas Gilbert 		break;
3550c2248fc9SDouglas Gilbert 	case WRITE_6:
3551c2248fc9SDouglas Gilbert 		ei_lba = 0;
3552c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3553c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3554c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3555c2248fc9SDouglas Gilbert 		check_prot = true;
3556c2248fc9SDouglas Gilbert 		break;
3557c2248fc9SDouglas Gilbert 	case WRITE_12:
3558c2248fc9SDouglas Gilbert 		ei_lba = 0;
3559c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3560c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3561c2248fc9SDouglas Gilbert 		check_prot = true;
3562c2248fc9SDouglas Gilbert 		break;
3563c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3564c2248fc9SDouglas Gilbert 		ei_lba = 0;
3565c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3566c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3567c2248fc9SDouglas Gilbert 		check_prot = false;
3568c2248fc9SDouglas Gilbert 		break;
3569c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3570c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3571c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3572c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3573c2248fc9SDouglas Gilbert 		check_prot = false;
3574c2248fc9SDouglas Gilbert 		break;
3575c2248fc9SDouglas Gilbert 	}
3576f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
35778475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3578c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3579c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3580c2248fc9SDouglas Gilbert 			return check_condition_result;
3581c2248fc9SDouglas Gilbert 		}
35828475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
35838475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3584c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3585c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3586c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3587c2248fc9SDouglas Gilbert 	}
3588f0d1cf93SDouglas Gilbert 
35897109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3590f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3591f0d1cf93SDouglas Gilbert 	if (ret) {
35927109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3593f0d1cf93SDouglas Gilbert 		return ret;
3594f0d1cf93SDouglas Gilbert 	}
35956c78cc06SAkinobu Mita 
3596c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3597f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3598f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3599f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3600f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
36017109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3602f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3603c6a44287SMartin K. Petersen 				return illegal_condition_result;
3604f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36057109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3606f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3607f7be6772SMartin K. Petersen 				return check_condition_result;
3608f7be6772SMartin K. Petersen 			}
3609f7be6772SMartin K. Petersen 			break;
3610f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3611f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
36127109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3613f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3614f7be6772SMartin K. Petersen 				return illegal_condition_result;
3615f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36167109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3617f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3618f7be6772SMartin K. Petersen 				return check_condition_result;
3619f7be6772SMartin K. Petersen 			}
3620f7be6772SMartin K. Petersen 			break;
3621c6a44287SMartin K. Petersen 		}
3622c6a44287SMartin K. Petersen 	}
3623c6a44287SMartin K. Petersen 
362487c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3625f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
362687c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3627f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3628f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3629f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
36307109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3631f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3632773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3633c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3634c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3635c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3636cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3637773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
363844d92694SMartin K. Petersen 
36393a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36403a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
36413a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36423a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36433a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3644c2248fc9SDouglas Gilbert 			return check_condition_result;
36453a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3646c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3647c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
36483a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3649c2248fc9SDouglas Gilbert 			return illegal_condition_result;
36503a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3651c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
36523a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3653c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3654c2248fc9SDouglas Gilbert 		}
3655c2248fc9SDouglas Gilbert 	}
36561da177e4SLinus Torvalds 	return 0;
36571da177e4SLinus Torvalds }
36581da177e4SLinus Torvalds 
3659481b5e5cSDouglas Gilbert /*
3660481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3661481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3662481b5e5cSDouglas Gilbert  */
3663481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3664481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3665481b5e5cSDouglas Gilbert {
3666481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3667481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3668481b5e5cSDouglas Gilbert 	u8 *up;
3669b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3670481b5e5cSDouglas Gilbert 	u8 wrprotect;
3671481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3672481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3673481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3674481b5e5cSDouglas Gilbert 	u32 ei_lba;
3675481b5e5cSDouglas Gilbert 	u64 lba;
3676481b5e5cSDouglas Gilbert 	int ret, res;
3677481b5e5cSDouglas Gilbert 	bool is_16;
3678481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3679481b5e5cSDouglas Gilbert 
3680481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3681481b5e5cSDouglas Gilbert 		is_16 = false;
3682481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3683481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3684481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3685481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3686481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3687481b5e5cSDouglas Gilbert 		is_16 = true;
3688481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3689481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3690481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3691481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3692481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3693481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3694481b5e5cSDouglas Gilbert 			    wrprotect) {
3695481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3696481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3697481b5e5cSDouglas Gilbert 			}
3698481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3699481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3700481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3701481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3702481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3703481b5e5cSDouglas Gilbert 		}
3704481b5e5cSDouglas Gilbert 	}
3705481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3706481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3707481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3708481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3709481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3710481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3711481b5e5cSDouglas Gilbert 				my_name, __func__);
3712481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3713481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3714481b5e5cSDouglas Gilbert 	}
3715481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3716481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3717481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3718481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3719481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3720481b5e5cSDouglas Gilbert 				my_name, __func__);
3721481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3722481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3723481b5e5cSDouglas Gilbert 	}
3724481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3725481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3726481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3727481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3728481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3729481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3730481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3731481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3732481b5e5cSDouglas Gilbert 	if (res == -1) {
3733481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3734481b5e5cSDouglas Gilbert 		goto err_out;
3735481b5e5cSDouglas Gilbert 	}
3736481b5e5cSDouglas Gilbert 
37377109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3738481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3739481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3740481b5e5cSDouglas Gilbert 	cum_lb = 0;
3741481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3742481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3743481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3744481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3745481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3746481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3747481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3748481b5e5cSDouglas Gilbert 		if (num == 0)
3749481b5e5cSDouglas Gilbert 			continue;
37509447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3751481b5e5cSDouglas Gilbert 		if (ret)
3752481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3753481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3754481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3755481b5e5cSDouglas Gilbert 
3756481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3757481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3758481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3759481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3760481b5e5cSDouglas Gilbert 				    my_name, __func__);
3761481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3762481b5e5cSDouglas Gilbert 					0);
3763481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3764481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3765481b5e5cSDouglas Gilbert 		}
3766481b5e5cSDouglas Gilbert 
3767481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3768481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3769481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3770481b5e5cSDouglas Gilbert 							 ei_lba);
3771481b5e5cSDouglas Gilbert 
3772481b5e5cSDouglas Gilbert 			if (prot_ret) {
3773481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3774481b5e5cSDouglas Gilbert 						prot_ret);
3775481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3776481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3777481b5e5cSDouglas Gilbert 			}
3778481b5e5cSDouglas Gilbert 		}
3779481b5e5cSDouglas Gilbert 
378087c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3781f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3782f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3783f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3784481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
378587c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3786481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3787481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3788481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3789481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3790481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3791481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3792481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3793481b5e5cSDouglas Gilbert 
37943a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
37953a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
37963a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
37973a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
37983a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
37993a90a63dSDouglas Gilbert 				ret = check_condition_result;
3800481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38013a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3802481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
38033a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
38043a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3805481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3806481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38073a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
38083a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
38093a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3810481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3811481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3812481b5e5cSDouglas Gilbert 			}
3813481b5e5cSDouglas Gilbert 		}
3814481b5e5cSDouglas Gilbert 		sg_off += num_by;
3815481b5e5cSDouglas Gilbert 		cum_lb += num;
3816481b5e5cSDouglas Gilbert 	}
3817481b5e5cSDouglas Gilbert 	ret = 0;
3818481b5e5cSDouglas Gilbert err_out_unlock:
38197109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3820481b5e5cSDouglas Gilbert err_out:
3821481b5e5cSDouglas Gilbert 	kfree(lrdp);
3822481b5e5cSDouglas Gilbert 	return ret;
3823481b5e5cSDouglas Gilbert }
3824481b5e5cSDouglas Gilbert 
3825fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3826fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
382744d92694SMartin K. Petersen {
3828f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3829f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
383044d92694SMartin K. Petersen 	unsigned long long i;
383140d07b52SDouglas Gilbert 	u64 block, lbaa;
383287c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
383387c715dcSDouglas Gilbert 	int ret;
383487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3835b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
383640d07b52SDouglas Gilbert 	u8 *fs1p;
383787c715dcSDouglas Gilbert 	u8 *fsp;
383844d92694SMartin K. Petersen 
38397109f370SDouglas Gilbert 	sdeb_write_lock(sip);
384044d92694SMartin K. Petersen 
3841f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3842f0d1cf93SDouglas Gilbert 	if (ret) {
38437109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3844f0d1cf93SDouglas Gilbert 		return ret;
3845f0d1cf93SDouglas Gilbert 	}
3846f0d1cf93SDouglas Gilbert 
38479ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
384887c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
384944d92694SMartin K. Petersen 		goto out;
385044d92694SMartin K. Petersen 	}
385140d07b52SDouglas Gilbert 	lbaa = lba;
385240d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3853c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
385487c715dcSDouglas Gilbert 	fsp = sip->storep;
385587c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3856c2248fc9SDouglas Gilbert 	if (ndob) {
385740d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3858c2248fc9SDouglas Gilbert 		ret = 0;
3859c2248fc9SDouglas Gilbert 	} else
386040d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
386144d92694SMartin K. Petersen 
386244d92694SMartin K. Petersen 	if (-1 == ret) {
38637109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3864773642d9SDouglas Gilbert 		return DID_ERROR << 16;
386540d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3866c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3867e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
386840d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
386944d92694SMartin K. Petersen 
387044d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
387140d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
387240d07b52SDouglas Gilbert 		lbaa = lba + i;
387340d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
387487c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
387540d07b52SDouglas Gilbert 	}
38769ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
387787c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3878f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3879f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3880f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
388144d92694SMartin K. Petersen out:
38827109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
388344d92694SMartin K. Petersen 
388444d92694SMartin K. Petersen 	return 0;
388544d92694SMartin K. Petersen }
388644d92694SMartin K. Petersen 
3887fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3888fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3889c2248fc9SDouglas Gilbert {
3890c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3891c2248fc9SDouglas Gilbert 	u32 lba;
3892c2248fc9SDouglas Gilbert 	u16 num;
3893c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3894c2248fc9SDouglas Gilbert 	bool unmap = false;
3895c2248fc9SDouglas Gilbert 
3896c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3897773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3898c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3899c2248fc9SDouglas Gilbert 			return check_condition_result;
3900c2248fc9SDouglas Gilbert 		} else
3901c2248fc9SDouglas Gilbert 			unmap = true;
3902c2248fc9SDouglas Gilbert 	}
3903c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3904c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3905773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3906c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3907c2248fc9SDouglas Gilbert 		return check_condition_result;
3908c2248fc9SDouglas Gilbert 	}
3909c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3910c2248fc9SDouglas Gilbert }
3911c2248fc9SDouglas Gilbert 
3912fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3913fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3914c2248fc9SDouglas Gilbert {
3915c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3916c2248fc9SDouglas Gilbert 	u64 lba;
3917c2248fc9SDouglas Gilbert 	u32 num;
3918c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3919c2248fc9SDouglas Gilbert 	bool unmap = false;
3920c2248fc9SDouglas Gilbert 	bool ndob = false;
3921c2248fc9SDouglas Gilbert 
3922c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3923773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3924c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3925c2248fc9SDouglas Gilbert 			return check_condition_result;
3926c2248fc9SDouglas Gilbert 		} else
3927c2248fc9SDouglas Gilbert 			unmap = true;
3928c2248fc9SDouglas Gilbert 	}
3929c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3930c2248fc9SDouglas Gilbert 		ndob = true;
3931c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3932c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3933773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3934c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3935c2248fc9SDouglas Gilbert 		return check_condition_result;
3936c2248fc9SDouglas Gilbert 	}
3937c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3938c2248fc9SDouglas Gilbert }
3939c2248fc9SDouglas Gilbert 
3940acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3941acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3942acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3943fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3944fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3945acafd0b9SEwan D. Milne {
3946acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3947acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3948acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3949acafd0b9SEwan D. Milne 	u8 mode;
3950acafd0b9SEwan D. Milne 
3951acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3952acafd0b9SEwan D. Milne 	switch (mode) {
3953acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3954acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3955acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3956acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3957acafd0b9SEwan D. Milne 		break;
3958acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3959acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3960acafd0b9SEwan D. Milne 		break;
3961acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3962acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3963acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3964acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3965acafd0b9SEwan D. Milne 				    dev_list)
3966acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3967acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3968acafd0b9SEwan D. Milne 				if (devip != dp)
3969acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3970acafd0b9SEwan D. Milne 						dp->uas_bm);
3971acafd0b9SEwan D. Milne 			}
3972acafd0b9SEwan D. Milne 		break;
3973acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3974acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3975acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3976acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3977acafd0b9SEwan D. Milne 				    dev_list)
3978acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3979acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3980acafd0b9SEwan D. Milne 					dp->uas_bm);
3981acafd0b9SEwan D. Milne 		break;
3982acafd0b9SEwan D. Milne 	default:
3983acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3984acafd0b9SEwan D. Milne 		break;
3985acafd0b9SEwan D. Milne 	}
3986acafd0b9SEwan D. Milne 	return 0;
3987acafd0b9SEwan D. Milne }
3988acafd0b9SEwan D. Milne 
3989fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3990fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
399138d5c833SDouglas Gilbert {
399238d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
399338d5c833SDouglas Gilbert 	u8 *arr;
3994b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
399538d5c833SDouglas Gilbert 	u64 lba;
399638d5c833SDouglas Gilbert 	u32 dnum;
3997773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
399838d5c833SDouglas Gilbert 	u8 num;
399938d5c833SDouglas Gilbert 	int ret;
4000d467d31fSDouglas Gilbert 	int retval = 0;
400138d5c833SDouglas Gilbert 
4002d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
400338d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
400438d5c833SDouglas Gilbert 	if (0 == num)
400538d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
40068475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
400738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
400838d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
400938d5c833SDouglas Gilbert 		return check_condition_result;
401038d5c833SDouglas Gilbert 	}
40118475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
40128475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
401338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
401438d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
401538d5c833SDouglas Gilbert 			    "to DIF device\n");
40169447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
40179447b6ceSMartin K. Petersen 	if (ret)
40189447b6ceSMartin K. Petersen 		return ret;
4019d467d31fSDouglas Gilbert 	dnum = 2 * num;
40206396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
4021d467d31fSDouglas Gilbert 	if (NULL == arr) {
4022d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4023d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
4024d467d31fSDouglas Gilbert 		return check_condition_result;
4025d467d31fSDouglas Gilbert 	}
402638d5c833SDouglas Gilbert 
40277109f370SDouglas Gilbert 	sdeb_write_lock(sip);
402838d5c833SDouglas Gilbert 
402987c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
403038d5c833SDouglas Gilbert 	if (ret == -1) {
4031d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
4032d467d31fSDouglas Gilbert 		goto cleanup;
4033773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
403438d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
403538d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
403638d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
4037c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
403838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4039d467d31fSDouglas Gilbert 		retval = check_condition_result;
4040d467d31fSDouglas Gilbert 		goto cleanup;
404138d5c833SDouglas Gilbert 	}
404238d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
404387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
4044d467d31fSDouglas Gilbert cleanup:
40457109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4046d467d31fSDouglas Gilbert 	kfree(arr);
4047d467d31fSDouglas Gilbert 	return retval;
404838d5c833SDouglas Gilbert }
404938d5c833SDouglas Gilbert 
405044d92694SMartin K. Petersen struct unmap_block_desc {
405144d92694SMartin K. Petersen 	__be64	lba;
405244d92694SMartin K. Petersen 	__be32	blocks;
405344d92694SMartin K. Petersen 	__be32	__reserved;
405444d92694SMartin K. Petersen };
405544d92694SMartin K. Petersen 
4056fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
405744d92694SMartin K. Petersen {
405844d92694SMartin K. Petersen 	unsigned char *buf;
405944d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
4060b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
406144d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
406244d92694SMartin K. Petersen 	int ret;
406344d92694SMartin K. Petersen 
4064c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
4065c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
4066c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
4067c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
406844d92694SMartin K. Petersen 
406944d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
4070773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
4071c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
407244d92694SMartin K. Petersen 		return check_condition_result;
4073c2248fc9SDouglas Gilbert 	}
407444d92694SMartin K. Petersen 
4075b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
4076c2248fc9SDouglas Gilbert 	if (!buf) {
4077c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4078c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
4079c2248fc9SDouglas Gilbert 		return check_condition_result;
4080c2248fc9SDouglas Gilbert 	}
4081c2248fc9SDouglas Gilbert 
4082c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
408344d92694SMartin K. Petersen 
408444d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
408544d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
408644d92694SMartin K. Petersen 
408744d92694SMartin K. Petersen 	desc = (void *)&buf[8];
408844d92694SMartin K. Petersen 
40897109f370SDouglas Gilbert 	sdeb_write_lock(sip);
40906c78cc06SAkinobu Mita 
409144d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
409244d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
409344d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
409444d92694SMartin K. Petersen 
40959447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
409644d92694SMartin K. Petersen 		if (ret)
409744d92694SMartin K. Petersen 			goto out;
409844d92694SMartin K. Petersen 
409987c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
410044d92694SMartin K. Petersen 	}
410144d92694SMartin K. Petersen 
410244d92694SMartin K. Petersen 	ret = 0;
410344d92694SMartin K. Petersen 
410444d92694SMartin K. Petersen out:
41057109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
410644d92694SMartin K. Petersen 	kfree(buf);
410744d92694SMartin K. Petersen 
410844d92694SMartin K. Petersen 	return ret;
410944d92694SMartin K. Petersen }
411044d92694SMartin K. Petersen 
411144d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
411244d92694SMartin K. Petersen 
4113fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4114fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
411544d92694SMartin K. Petersen {
4116c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4117c2248fc9SDouglas Gilbert 	u64 lba;
4118c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
411944d92694SMartin K. Petersen 	int ret;
412087c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
412144d92694SMartin K. Petersen 
4122c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4123c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
412444d92694SMartin K. Petersen 
412544d92694SMartin K. Petersen 	if (alloc_len < 24)
412644d92694SMartin K. Petersen 		return 0;
412744d92694SMartin K. Petersen 
41289447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
412944d92694SMartin K. Petersen 	if (ret)
413044d92694SMartin K. Petersen 		return ret;
413144d92694SMartin K. Petersen 
4132b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4133b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4134b6ff8ca7SDouglas Gilbert 
413587c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4136b6ff8ca7SDouglas Gilbert 	} else {
4137c2248fc9SDouglas Gilbert 		mapped = 1;
4138c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4139c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4140c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4141c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4142c2248fc9SDouglas Gilbert 		else
4143c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4144c2248fc9SDouglas Gilbert 	}
414544d92694SMartin K. Petersen 
414644d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4147c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4148c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4149c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4150c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
415144d92694SMartin K. Petersen 
4152c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
415344d92694SMartin K. Petersen }
415444d92694SMartin K. Petersen 
415580c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
415680c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
415780c49563SDouglas Gilbert {
41584f2c8bf6SDouglas Gilbert 	int res = 0;
415980c49563SDouglas Gilbert 	u64 lba;
416080c49563SDouglas Gilbert 	u32 num_blocks;
416180c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
416280c49563SDouglas Gilbert 
416380c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
416480c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
416580c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
416680c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
416780c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
416880c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
416980c49563SDouglas Gilbert 	}
417080c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
417180c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
417280c49563SDouglas Gilbert 		return check_condition_result;
417380c49563SDouglas Gilbert 	}
4174fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
41754f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
41764f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
41774f2c8bf6SDouglas Gilbert 		write_since_sync = false;
41784f2c8bf6SDouglas Gilbert 	return res;
417980c49563SDouglas Gilbert }
418080c49563SDouglas Gilbert 
4181ed9f3e25SDouglas Gilbert /*
4182ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4183ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4184ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4185ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4186ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4187ed9f3e25SDouglas Gilbert  */
4188ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4189ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4190ed9f3e25SDouglas Gilbert {
4191ed9f3e25SDouglas Gilbert 	int res = 0;
4192ed9f3e25SDouglas Gilbert 	u64 lba;
4193ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4194ed9f3e25SDouglas Gilbert 	u32 nblks;
4195ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4196b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4197b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4198ed9f3e25SDouglas Gilbert 
4199ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4200ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4201ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4202ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4203ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4204ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4205ed9f3e25SDouglas Gilbert 	}
4206ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4207ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4208ed9f3e25SDouglas Gilbert 		return check_condition_result;
4209ed9f3e25SDouglas Gilbert 	}
4210ed9f3e25SDouglas Gilbert 	if (!fsp)
4211ed9f3e25SDouglas Gilbert 		goto fini;
4212ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4213ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4214ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4215ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4216ed9f3e25SDouglas Gilbert 
4217ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
42187109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4219ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4220ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4221ed9f3e25SDouglas Gilbert 	if (rest)
4222ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
42237109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4224ed9f3e25SDouglas Gilbert fini:
4225ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4226ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4227ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4228ed9f3e25SDouglas Gilbert }
4229ed9f3e25SDouglas Gilbert 
4230fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4231fb0cc8d1SDouglas Gilbert 
42328d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
42338d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
42348d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
42358d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
42368d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
42378d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
42388d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
42398d039e22SDouglas Gilbert  */
42401da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
42411da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
42421da177e4SLinus Torvalds {
424301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
42448d039e22SDouglas Gilbert 	unsigned int alloc_len;
42458d039e22SDouglas Gilbert 	unsigned char select_report;
42468d039e22SDouglas Gilbert 	u64 lun;
42478d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4248fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
42498d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
42508d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
42518d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
42528d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4253fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4254fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4255fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
42561da177e4SLinus Torvalds 
425719c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
42588d039e22SDouglas Gilbert 
42598d039e22SDouglas Gilbert 	select_report = cmd[2];
42608d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
42618d039e22SDouglas Gilbert 
42628d039e22SDouglas Gilbert 	if (alloc_len < 4) {
42638d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
42648d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
42651da177e4SLinus Torvalds 		return check_condition_result;
42661da177e4SLinus Torvalds 	}
42678d039e22SDouglas Gilbert 
42688d039e22SDouglas Gilbert 	switch (select_report) {
42698d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4270773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
42718d039e22SDouglas Gilbert 		wlun_cnt = 0;
42728d039e22SDouglas Gilbert 		break;
42738d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4274c65b1445SDouglas Gilbert 		lun_cnt = 0;
42758d039e22SDouglas Gilbert 		wlun_cnt = 1;
42768d039e22SDouglas Gilbert 		break;
42778d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
42788d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
42798d039e22SDouglas Gilbert 		wlun_cnt = 1;
42808d039e22SDouglas Gilbert 		break;
42818d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
42828d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
42838d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
42848d039e22SDouglas Gilbert 	default:
42858d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
42868d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
42878d039e22SDouglas Gilbert 		return check_condition_result;
42888d039e22SDouglas Gilbert 	}
42898d039e22SDouglas Gilbert 
42908d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4291c65b1445SDouglas Gilbert 		--lun_cnt;
42928d039e22SDouglas Gilbert 
42938d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4294fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4295fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
42968d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
42978d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
42988d039e22SDouglas Gilbert 
4299fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
43008d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4301fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4302fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4303fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4304fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4305fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4306fb0cc8d1SDouglas Gilbert 			++lun_p;
4307fb0cc8d1SDouglas Gilbert 			j = 1;
4308fb0cc8d1SDouglas Gilbert 		}
4309fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4310fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4311fb0cc8d1SDouglas Gilbert 				break;
4312fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4313ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4314ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4315fb0cc8d1SDouglas Gilbert 		}
4316fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4317fb0cc8d1SDouglas Gilbert 			break;
4318fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4319fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4320fb0cc8d1SDouglas Gilbert 		if (res)
4321fb0cc8d1SDouglas Gilbert 			return res;
4322fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4323fb0cc8d1SDouglas Gilbert 	}
4324fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4325fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4326fb0cc8d1SDouglas Gilbert 		++j;
4327fb0cc8d1SDouglas Gilbert 	}
4328fb0cc8d1SDouglas Gilbert 	if (j > 0)
4329fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
43308d039e22SDouglas Gilbert 	return res;
43311da177e4SLinus Torvalds }
43321da177e4SLinus Torvalds 
4333c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4334c3e2fe92SDouglas Gilbert {
4335c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4336c3e2fe92SDouglas Gilbert 	u8 bytchk;
4337c3e2fe92SDouglas Gilbert 	int ret, j;
4338c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4339c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4340c3e2fe92SDouglas Gilbert 	u64 lba;
4341c3e2fe92SDouglas Gilbert 	u8 *arr;
4342c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4343b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4344c3e2fe92SDouglas Gilbert 
4345c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4346c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4347c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4348c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4349c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4350c3e2fe92SDouglas Gilbert 		return check_condition_result;
4351c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4352c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4353c3e2fe92SDouglas Gilbert 	}
4354c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4355c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4356c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4357c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4358c3e2fe92SDouglas Gilbert 		break;
4359c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4360c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4361c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4362c3e2fe92SDouglas Gilbert 		break;
4363c3e2fe92SDouglas Gilbert 	default:
4364c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4365c3e2fe92SDouglas Gilbert 		return check_condition_result;
4366c3e2fe92SDouglas Gilbert 	}
43673344b58bSGeorge Kennedy 	if (vnum == 0)
43683344b58bSGeorge Kennedy 		return 0;	/* not an error */
4369c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4370c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4371c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4372c3e2fe92SDouglas Gilbert 	if (ret)
4373c3e2fe92SDouglas Gilbert 		return ret;
4374c3e2fe92SDouglas Gilbert 
4375c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4376c3e2fe92SDouglas Gilbert 	if (!arr) {
4377c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4378c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4379c3e2fe92SDouglas Gilbert 		return check_condition_result;
4380c3e2fe92SDouglas Gilbert 	}
4381c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
43827109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4383c3e2fe92SDouglas Gilbert 
4384c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4385c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4386c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4387c3e2fe92SDouglas Gilbert 		goto cleanup;
4388c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4389c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4390c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4391c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4392c3e2fe92SDouglas Gilbert 	}
4393c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4394c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4395c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4396c3e2fe92SDouglas Gilbert 	}
4397c3e2fe92SDouglas Gilbert 	ret = 0;
4398c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4399c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4400c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4401c3e2fe92SDouglas Gilbert 		goto cleanup;
4402c3e2fe92SDouglas Gilbert 	}
4403c3e2fe92SDouglas Gilbert cleanup:
44047109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4405c3e2fe92SDouglas Gilbert 	kfree(arr);
4406c3e2fe92SDouglas Gilbert 	return ret;
4407c3e2fe92SDouglas Gilbert }
4408c3e2fe92SDouglas Gilbert 
4409f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4410f0d1cf93SDouglas Gilbert 
4411f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4412f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4413f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4414f0d1cf93SDouglas Gilbert {
4415f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4416f0d1cf93SDouglas Gilbert 	int ret = 0;
4417f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4418f0d1cf93SDouglas Gilbert 	bool partial;
4419f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4420f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4421f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4422f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4423b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4424f0d1cf93SDouglas Gilbert 
4425f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4426f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4427f0d1cf93SDouglas Gilbert 		return check_condition_result;
4428f0d1cf93SDouglas Gilbert 	}
4429f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4430f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
44313344b58bSGeorge Kennedy 	if (alloc_len == 0)
44323344b58bSGeorge Kennedy 		return 0;	/* not an error */
4433f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4434f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4435f0d1cf93SDouglas Gilbert 
4436f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4437f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4438f0d1cf93SDouglas Gilbert 		return check_condition_result;
4439f0d1cf93SDouglas Gilbert 	}
4440f0d1cf93SDouglas Gilbert 
4441108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4442f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4443f0d1cf93SDouglas Gilbert 			    max_zones);
4444f0d1cf93SDouglas Gilbert 
44457db0e0c8SShin'ichiro Kawasaki 	arr = kzalloc(alloc_len, GFP_ATOMIC);
4446f0d1cf93SDouglas Gilbert 	if (!arr) {
4447f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4448f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4449f0d1cf93SDouglas Gilbert 		return check_condition_result;
4450f0d1cf93SDouglas Gilbert 	}
4451f0d1cf93SDouglas Gilbert 
44527109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4453f0d1cf93SDouglas Gilbert 
4454f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4455f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4456f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4457f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4458f0d1cf93SDouglas Gilbert 			break;
4459f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4460f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4461f0d1cf93SDouglas Gilbert 		case 0x00:
4462f0d1cf93SDouglas Gilbert 			/* All zones */
4463f0d1cf93SDouglas Gilbert 			break;
4464f0d1cf93SDouglas Gilbert 		case 0x01:
4465f0d1cf93SDouglas Gilbert 			/* Empty zones */
4466f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4467f0d1cf93SDouglas Gilbert 				continue;
4468f0d1cf93SDouglas Gilbert 			break;
4469f0d1cf93SDouglas Gilbert 		case 0x02:
4470f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4471f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4472f0d1cf93SDouglas Gilbert 				continue;
4473f0d1cf93SDouglas Gilbert 			break;
4474f0d1cf93SDouglas Gilbert 		case 0x03:
4475f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4476f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4477f0d1cf93SDouglas Gilbert 				continue;
4478f0d1cf93SDouglas Gilbert 			break;
4479f0d1cf93SDouglas Gilbert 		case 0x04:
4480f0d1cf93SDouglas Gilbert 			/* Closed zones */
4481f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4482f0d1cf93SDouglas Gilbert 				continue;
4483f0d1cf93SDouglas Gilbert 			break;
4484f0d1cf93SDouglas Gilbert 		case 0x05:
4485f0d1cf93SDouglas Gilbert 			/* Full zones */
4486f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4487f0d1cf93SDouglas Gilbert 				continue;
4488f0d1cf93SDouglas Gilbert 			break;
4489f0d1cf93SDouglas Gilbert 		case 0x06:
4490f0d1cf93SDouglas Gilbert 		case 0x07:
4491f0d1cf93SDouglas Gilbert 		case 0x10:
4492f0d1cf93SDouglas Gilbert 			/*
449364e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
449464e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4495f0d1cf93SDouglas Gilbert 			 */
4496f0d1cf93SDouglas Gilbert 			continue;
449764e14eceSDamien Le Moal 		case 0x11:
449864e14eceSDamien Le Moal 			/* non-seq-resource set */
449964e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
450064e14eceSDamien Le Moal 				continue;
450164e14eceSDamien Le Moal 			break;
4502f0d1cf93SDouglas Gilbert 		case 0x3f:
4503f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4504f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4505f0d1cf93SDouglas Gilbert 				continue;
4506f0d1cf93SDouglas Gilbert 			break;
4507f0d1cf93SDouglas Gilbert 		default:
4508f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4509f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4510f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4511f0d1cf93SDouglas Gilbert 			goto fini;
4512f0d1cf93SDouglas Gilbert 		}
4513f0d1cf93SDouglas Gilbert 
4514f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4515f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
451664e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4517f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
451864e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
451964e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4520f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4521f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4522f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4523f0d1cf93SDouglas Gilbert 			desc += 64;
4524f0d1cf93SDouglas Gilbert 		}
4525f0d1cf93SDouglas Gilbert 
4526f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4527f0d1cf93SDouglas Gilbert 			break;
4528f0d1cf93SDouglas Gilbert 
4529f0d1cf93SDouglas Gilbert 		nrz++;
4530f0d1cf93SDouglas Gilbert 	}
4531f0d1cf93SDouglas Gilbert 
4532f0d1cf93SDouglas Gilbert 	/* Report header */
4533f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4534f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4535f0d1cf93SDouglas Gilbert 
4536f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
453736e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4538f0d1cf93SDouglas Gilbert 
4539f0d1cf93SDouglas Gilbert fini:
45407109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4541f0d1cf93SDouglas Gilbert 	kfree(arr);
4542f0d1cf93SDouglas Gilbert 	return ret;
4543f0d1cf93SDouglas Gilbert }
4544f0d1cf93SDouglas Gilbert 
4545f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4546f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4547f0d1cf93SDouglas Gilbert {
4548f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4549f0d1cf93SDouglas Gilbert 	unsigned int i;
4550f0d1cf93SDouglas Gilbert 
4551f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4552f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4553f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4554f0d1cf93SDouglas Gilbert 	}
4555f0d1cf93SDouglas Gilbert }
4556f0d1cf93SDouglas Gilbert 
4557f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4558f0d1cf93SDouglas Gilbert {
4559f0d1cf93SDouglas Gilbert 	int res = 0;
4560f0d1cf93SDouglas Gilbert 	u64 z_id;
4561f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4562f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4563f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4564f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4565b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4566f0d1cf93SDouglas Gilbert 
4567f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4568f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4569f0d1cf93SDouglas Gilbert 		return check_condition_result;
4570f0d1cf93SDouglas Gilbert 	}
4571f0d1cf93SDouglas Gilbert 
45727109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4573f0d1cf93SDouglas Gilbert 
4574f0d1cf93SDouglas Gilbert 	if (all) {
4575f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4576f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4577f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4578f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4579f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4580f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4581f0d1cf93SDouglas Gilbert 			goto fini;
4582f0d1cf93SDouglas Gilbert 		}
4583f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4584f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4585f0d1cf93SDouglas Gilbert 		goto fini;
4586f0d1cf93SDouglas Gilbert 	}
4587f0d1cf93SDouglas Gilbert 
4588f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4589f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4590f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4591f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4592f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4593f0d1cf93SDouglas Gilbert 		goto fini;
4594f0d1cf93SDouglas Gilbert 	}
4595f0d1cf93SDouglas Gilbert 
4596f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4597f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4598f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4599f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4600f0d1cf93SDouglas Gilbert 		goto fini;
4601f0d1cf93SDouglas Gilbert 	}
4602f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4603f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4604f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4605f0d1cf93SDouglas Gilbert 		goto fini;
4606f0d1cf93SDouglas Gilbert 	}
4607f0d1cf93SDouglas Gilbert 
4608f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4609f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4610f0d1cf93SDouglas Gilbert 		goto fini;
4611f0d1cf93SDouglas Gilbert 
4612f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4613f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4614f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4615f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4616f0d1cf93SDouglas Gilbert 		goto fini;
4617f0d1cf93SDouglas Gilbert 	}
4618f0d1cf93SDouglas Gilbert 
4619f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4620f0d1cf93SDouglas Gilbert fini:
46217109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4622f0d1cf93SDouglas Gilbert 	return res;
4623f0d1cf93SDouglas Gilbert }
4624f0d1cf93SDouglas Gilbert 
4625f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4626f0d1cf93SDouglas Gilbert {
4627f0d1cf93SDouglas Gilbert 	unsigned int i;
4628f0d1cf93SDouglas Gilbert 
4629f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4630f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4631f0d1cf93SDouglas Gilbert }
4632f0d1cf93SDouglas Gilbert 
4633f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4634f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4635f0d1cf93SDouglas Gilbert {
4636f0d1cf93SDouglas Gilbert 	int res = 0;
4637f0d1cf93SDouglas Gilbert 	u64 z_id;
4638f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4639f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4640f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4641b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4642f0d1cf93SDouglas Gilbert 
4643f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4644f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4645f0d1cf93SDouglas Gilbert 		return check_condition_result;
4646f0d1cf93SDouglas Gilbert 	}
4647f0d1cf93SDouglas Gilbert 
46487109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4649f0d1cf93SDouglas Gilbert 
4650f0d1cf93SDouglas Gilbert 	if (all) {
4651f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4652f0d1cf93SDouglas Gilbert 		goto fini;
4653f0d1cf93SDouglas Gilbert 	}
4654f0d1cf93SDouglas Gilbert 
4655f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4656f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4657f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4658f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4659f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4660f0d1cf93SDouglas Gilbert 		goto fini;
4661f0d1cf93SDouglas Gilbert 	}
4662f0d1cf93SDouglas Gilbert 
4663f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4664f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4665f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4666f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4667f0d1cf93SDouglas Gilbert 		goto fini;
4668f0d1cf93SDouglas Gilbert 	}
4669f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4670f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4671f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4672f0d1cf93SDouglas Gilbert 		goto fini;
4673f0d1cf93SDouglas Gilbert 	}
4674f0d1cf93SDouglas Gilbert 
4675f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4676f0d1cf93SDouglas Gilbert fini:
46777109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4678f0d1cf93SDouglas Gilbert 	return res;
4679f0d1cf93SDouglas Gilbert }
4680f0d1cf93SDouglas Gilbert 
4681f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4682f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4683f0d1cf93SDouglas Gilbert {
4684f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4685f0d1cf93SDouglas Gilbert 
4686f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4687f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4688f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4689f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4690f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4691f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4692f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4693f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4694f0d1cf93SDouglas Gilbert 	}
4695f0d1cf93SDouglas Gilbert }
4696f0d1cf93SDouglas Gilbert 
4697f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4698f0d1cf93SDouglas Gilbert {
4699f0d1cf93SDouglas Gilbert 	unsigned int i;
4700f0d1cf93SDouglas Gilbert 
4701f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4702f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4703f0d1cf93SDouglas Gilbert }
4704f0d1cf93SDouglas Gilbert 
4705f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4706f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4707f0d1cf93SDouglas Gilbert {
4708f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4709f0d1cf93SDouglas Gilbert 	int res = 0;
4710f0d1cf93SDouglas Gilbert 	u64 z_id;
4711f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4712f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4713b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4714f0d1cf93SDouglas Gilbert 
4715f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4716f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4717f0d1cf93SDouglas Gilbert 		return check_condition_result;
4718f0d1cf93SDouglas Gilbert 	}
4719f0d1cf93SDouglas Gilbert 
47207109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4721f0d1cf93SDouglas Gilbert 
4722f0d1cf93SDouglas Gilbert 	if (all) {
4723f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4724f0d1cf93SDouglas Gilbert 		goto fini;
4725f0d1cf93SDouglas Gilbert 	}
4726f0d1cf93SDouglas Gilbert 
4727f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4728f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4729f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4730f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4731f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4732f0d1cf93SDouglas Gilbert 		goto fini;
4733f0d1cf93SDouglas Gilbert 	}
4734f0d1cf93SDouglas Gilbert 
4735f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4736f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4737f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4738f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4739f0d1cf93SDouglas Gilbert 		goto fini;
4740f0d1cf93SDouglas Gilbert 	}
4741f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4742f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4743f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4744f0d1cf93SDouglas Gilbert 		goto fini;
4745f0d1cf93SDouglas Gilbert 	}
4746f0d1cf93SDouglas Gilbert 
4747f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4748f0d1cf93SDouglas Gilbert fini:
47497109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4750f0d1cf93SDouglas Gilbert 	return res;
4751f0d1cf93SDouglas Gilbert }
4752f0d1cf93SDouglas Gilbert 
4753f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4754f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4755f0d1cf93SDouglas Gilbert {
4756f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
47572d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4758f0d1cf93SDouglas Gilbert 
4759f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4760f0d1cf93SDouglas Gilbert 		return;
4761f0d1cf93SDouglas Gilbert 
4762f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4763f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4764f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4765f0d1cf93SDouglas Gilbert 
4766f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4767f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4768f0d1cf93SDouglas Gilbert 
47692d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
47702d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
47712d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
47722d62253eSShin'ichiro Kawasaki 
477364e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4774f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4775f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4776f0d1cf93SDouglas Gilbert }
4777f0d1cf93SDouglas Gilbert 
4778f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4779f0d1cf93SDouglas Gilbert {
4780f0d1cf93SDouglas Gilbert 	unsigned int i;
4781f0d1cf93SDouglas Gilbert 
4782f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4783f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4784f0d1cf93SDouglas Gilbert }
4785f0d1cf93SDouglas Gilbert 
4786f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4787f0d1cf93SDouglas Gilbert {
4788f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4789f0d1cf93SDouglas Gilbert 	int res = 0;
4790f0d1cf93SDouglas Gilbert 	u64 z_id;
4791f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4792f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4793b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4794f0d1cf93SDouglas Gilbert 
4795f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4796f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4797f0d1cf93SDouglas Gilbert 		return check_condition_result;
4798f0d1cf93SDouglas Gilbert 	}
4799f0d1cf93SDouglas Gilbert 
48007109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4801f0d1cf93SDouglas Gilbert 
4802f0d1cf93SDouglas Gilbert 	if (all) {
4803f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4804f0d1cf93SDouglas Gilbert 		goto fini;
4805f0d1cf93SDouglas Gilbert 	}
4806f0d1cf93SDouglas Gilbert 
4807f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4808f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4809f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4810f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4811f0d1cf93SDouglas Gilbert 		goto fini;
4812f0d1cf93SDouglas Gilbert 	}
4813f0d1cf93SDouglas Gilbert 
4814f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4815f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4816f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4817f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4818f0d1cf93SDouglas Gilbert 		goto fini;
4819f0d1cf93SDouglas Gilbert 	}
4820f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4821f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4822f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4823f0d1cf93SDouglas Gilbert 		goto fini;
4824f0d1cf93SDouglas Gilbert 	}
4825f0d1cf93SDouglas Gilbert 
4826f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4827f0d1cf93SDouglas Gilbert fini:
48287109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4829f0d1cf93SDouglas Gilbert 	return res;
4830f0d1cf93SDouglas Gilbert }
4831f0d1cf93SDouglas Gilbert 
4832c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4833c4837394SDouglas Gilbert {
4834c10fa55fSJohn Garry 	u16 hwq;
4835a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4836c10fa55fSJohn Garry 
4837c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4838c4837394SDouglas Gilbert 
4839458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4840458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4841458df78bSBart Van Assche 		hwq = 0;
4842f7c4cdc7SJohn Garry 
4843458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4844c4837394SDouglas Gilbert }
4845c4837394SDouglas Gilbert 
4846c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4847c10fa55fSJohn Garry {
4848a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4849c10fa55fSJohn Garry }
4850c10fa55fSJohn Garry 
4851c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4852fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
48531da177e4SLinus Torvalds {
48547382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4855c4837394SDouglas Gilbert 	int qc_idx;
4856cbf67842SDouglas Gilbert 	int retiring = 0;
48571da177e4SLinus Torvalds 	unsigned long iflags;
4858c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4859cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4860cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4861cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
48621da177e4SLinus Torvalds 
48637382f9d8SDouglas Gilbert 	if (unlikely(aborted))
48647382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4865c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4866c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4867c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4868cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4869c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4870c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4871c4837394SDouglas Gilbert 	}
4872c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4873c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
48741da177e4SLinus Torvalds 		return;
48751da177e4SLinus Torvalds 	}
4876c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4877d9d23a5aSDouglas Gilbert 	WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
4878c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4879cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4880b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4881c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4882c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4883c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
48841da177e4SLinus Torvalds 		return;
48851da177e4SLinus Torvalds 	}
4886cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4887f46eb0e9SDouglas Gilbert 	if (likely(devip))
4888cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4889cbf67842SDouglas Gilbert 	else
4890c1287970STomas Winkler 		pr_err("devip=NULL\n");
4891f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4892cbf67842SDouglas Gilbert 		retiring = 1;
4893cbf67842SDouglas Gilbert 
4894cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4895c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4896c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4897c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4898cbf67842SDouglas Gilbert 		return;
48991da177e4SLinus Torvalds 	}
49001da177e4SLinus Torvalds 
4901cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4902cbf67842SDouglas Gilbert 		int k, retval;
4903cbf67842SDouglas Gilbert 
4904cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4905c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4906c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4907c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4908cbf67842SDouglas Gilbert 			return;
4909cbf67842SDouglas Gilbert 		}
4910c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4911773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4912cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4913cbf67842SDouglas Gilbert 		else
4914cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4915cbf67842SDouglas Gilbert 	}
4916c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
49177382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
49187382f9d8SDouglas Gilbert 		if (sdebug_verbose)
49197382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
49207382f9d8SDouglas Gilbert 		return;
49217382f9d8SDouglas Gilbert 	}
49226c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
4923cbf67842SDouglas Gilbert }
4924cbf67842SDouglas Gilbert 
4925cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4926fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4927cbf67842SDouglas Gilbert {
4928a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4929a10bc12aSDouglas Gilbert 						  hrt);
4930a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4931cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4932cbf67842SDouglas Gilbert }
49331da177e4SLinus Torvalds 
4934a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4935fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4936a10bc12aSDouglas Gilbert {
4937a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4938a10bc12aSDouglas Gilbert 						  ew.work);
4939a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4940a10bc12aSDouglas Gilbert }
4941a10bc12aSDouglas Gilbert 
494209ba24c1SDouglas Gilbert static bool got_shared_uuid;
4943bf476433SChristoph Hellwig static uuid_t shared_uuid;
494409ba24c1SDouglas Gilbert 
4945f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4946f0d1cf93SDouglas Gilbert {
4947f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4948f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4949f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4950f0d1cf93SDouglas Gilbert 	unsigned int i;
4951f0d1cf93SDouglas Gilbert 
4952f0d1cf93SDouglas Gilbert 	/*
495398e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
495498e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4955f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4956f0d1cf93SDouglas Gilbert 	 * created for the device.
4957f0d1cf93SDouglas Gilbert 	 */
495898e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4959f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4960f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4961f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4962f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4963f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4964f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4965f0d1cf93SDouglas Gilbert 			return -EINVAL;
4966f0d1cf93SDouglas Gilbert 		}
4967f0d1cf93SDouglas Gilbert 	} else {
4968108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4969108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4970108e36f0SDamien Le Moal 			return -EINVAL;
4971108e36f0SDamien Le Moal 		}
497298e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4973f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4974f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4975f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4976f0d1cf93SDouglas Gilbert 			return -EINVAL;
4977f0d1cf93SDouglas Gilbert 		}
4978f0d1cf93SDouglas Gilbert 	}
4979f0d1cf93SDouglas Gilbert 
4980f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4981f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4982f0d1cf93SDouglas Gilbert 
4983aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4984aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4985aa8fecf9SDamien Le Moal 		return -EINVAL;
4986aa8fecf9SDamien Le Moal 	}
4987aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4988aa8fecf9SDamien Le Moal 
498964e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
499064e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4991380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4992f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4993f0d1cf93SDouglas Gilbert 		else
4994380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
499564e14eceSDamien Le Moal 	}
4996f0d1cf93SDouglas Gilbert 
4997f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4998f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4999f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
5000f0d1cf93SDouglas Gilbert 		return -ENOMEM;
5001f0d1cf93SDouglas Gilbert 
5002f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
5003f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
5004f0d1cf93SDouglas Gilbert 
5005f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
5006f0d1cf93SDouglas Gilbert 
5007aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
500864e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
5009f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
5010f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
5011f0d1cf93SDouglas Gilbert 		} else {
501264e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
501364e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
501464e14eceSDamien Le Moal 			else
501564e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
5016f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
5017f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
5018f0d1cf93SDouglas Gilbert 		}
5019f0d1cf93SDouglas Gilbert 
5020f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
5021f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
5022f0d1cf93SDouglas Gilbert 		else
5023f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
5024f0d1cf93SDouglas Gilbert 
5025f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
5026f0d1cf93SDouglas Gilbert 	}
5027f0d1cf93SDouglas Gilbert 
5028f0d1cf93SDouglas Gilbert 	return 0;
5029f0d1cf93SDouglas Gilbert }
5030f0d1cf93SDouglas Gilbert 
5031fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
5032fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
50335cb2fc06SFUJITA Tomonori {
50345cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
50355cb2fc06SFUJITA Tomonori 
50365cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
50375cb2fc06SFUJITA Tomonori 	if (devip) {
503809ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
5039bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
504009ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
504109ba24c1SDouglas Gilbert 			if (got_shared_uuid)
504209ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
504309ba24c1SDouglas Gilbert 			else {
5044bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
504509ba24c1SDouglas Gilbert 				got_shared_uuid = true;
504609ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
504709ba24c1SDouglas Gilbert 			}
504809ba24c1SDouglas Gilbert 		}
50495cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
5050f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
505164e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
5052f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
5053f0d1cf93SDouglas Gilbert 				kfree(devip);
5054f0d1cf93SDouglas Gilbert 				return NULL;
5055f0d1cf93SDouglas Gilbert 			}
505664e14eceSDamien Le Moal 		} else {
505764e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
5058f0d1cf93SDouglas Gilbert 		}
5059f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
5060fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
5061fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
50625cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
50635cb2fc06SFUJITA Tomonori 	}
50645cb2fc06SFUJITA Tomonori 	return devip;
50655cb2fc06SFUJITA Tomonori }
50665cb2fc06SFUJITA Tomonori 
5067f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
50681da177e4SLinus Torvalds {
50691da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
50701da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
5071f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
50721da177e4SLinus Torvalds 
5073d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
50741da177e4SLinus Torvalds 	if (!sdbg_host) {
5075c1287970STomas Winkler 		pr_err("Host info NULL\n");
50761da177e4SLinus Torvalds 		return NULL;
50771da177e4SLinus Torvalds 	}
5078ad0c7775SDouglas Gilbert 
50791da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
50801da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
50811da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
50821da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
50831da177e4SLinus Torvalds 			return devip;
50841da177e4SLinus Torvalds 		else {
50851da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
50861da177e4SLinus Torvalds 				open_devip = devip;
50871da177e4SLinus Torvalds 		}
50881da177e4SLinus Torvalds 	}
50895cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
50905cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
50915cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5092c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
50931da177e4SLinus Torvalds 			return NULL;
50941da177e4SLinus Torvalds 		}
50951da177e4SLinus Torvalds 	}
5096a75869d1SFUJITA Tomonori 
50971da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
50981da177e4SLinus Torvalds 	open_devip->target = sdev->id;
50991da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
51001da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5101cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
5102500d0d24SDouglas Gilbert 	set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
5103c2248fc9SDouglas Gilbert 	open_devip->used = true;
51041da177e4SLinus Torvalds 	return open_devip;
51051da177e4SLinus Torvalds }
51061da177e4SLinus Torvalds 
51078dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
51081da177e4SLinus Torvalds {
5109773642d9SDouglas Gilbert 	if (sdebug_verbose)
5110c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
51118dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
51128dea0d02SFUJITA Tomonori 	return 0;
51138dea0d02SFUJITA Tomonori }
51141da177e4SLinus Torvalds 
51158dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
51168dea0d02SFUJITA Tomonori {
5117f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5118f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5119a34c4e98SFUJITA Tomonori 
5120773642d9SDouglas Gilbert 	if (sdebug_verbose)
5121c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
51228dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5123b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5124b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
51252aad3cd8SDouglas Gilbert 	if (smp_load_acquire(&sdebug_deflect_incoming)) {
51262aad3cd8SDouglas Gilbert 		pr_info("Exit early due to deflect_incoming\n");
51272aad3cd8SDouglas Gilbert 		return 1;
51282aad3cd8SDouglas Gilbert 	}
5129b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5130f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5131b01f6f83SDouglas Gilbert 		if (devip == NULL)
51328dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5133f46eb0e9SDouglas Gilbert 	}
5134c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5135773642d9SDouglas Gilbert 	if (sdebug_no_uld)
513678d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
51379b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
51388dea0d02SFUJITA Tomonori 	return 0;
51398dea0d02SFUJITA Tomonori }
51408dea0d02SFUJITA Tomonori 
51418dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
51428dea0d02SFUJITA Tomonori {
51438dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
51448dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
51458dea0d02SFUJITA Tomonori 
5146773642d9SDouglas Gilbert 	if (sdebug_verbose)
5147c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
51488dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
51498dea0d02SFUJITA Tomonori 	if (devip) {
515025985edcSLucas De Marchi 		/* make this slot available for re-use */
5151c2248fc9SDouglas Gilbert 		devip->used = false;
51528dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
51538dea0d02SFUJITA Tomonori 	}
51548dea0d02SFUJITA Tomonori }
51558dea0d02SFUJITA Tomonori 
515610bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
515710bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5158c4837394SDouglas Gilbert {
5159c4837394SDouglas Gilbert 	if (!sd_dp)
5160c4837394SDouglas Gilbert 		return;
516110bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5162c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
516310bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5164c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5165c4837394SDouglas Gilbert }
5166c4837394SDouglas Gilbert 
5167a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5168a10bc12aSDouglas Gilbert    returns false */
5169a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
51708dea0d02SFUJITA Tomonori {
51718dea0d02SFUJITA Tomonori 	unsigned long iflags;
5172c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
517310bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5174c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
51758dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5176cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5177a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
51788dea0d02SFUJITA Tomonori 
5179c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5180c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5181773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5182cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5183cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5184cbf67842SDouglas Gilbert 			qmax = r_qmax;
5185cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5186c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5187c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5188a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5189a10bc12aSDouglas Gilbert 					continue;
5190c4837394SDouglas Gilbert 				/* found */
5191db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5192db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5193db525fceSDouglas Gilbert 				if (devip)
5194db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5195db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5196a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
519710bde980SDouglas Gilbert 				if (sd_dp) {
5198d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5199d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
520010bde980SDouglas Gilbert 				} else
520110bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5202c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
520310bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5204c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5205a10bc12aSDouglas Gilbert 				return true;
52068dea0d02SFUJITA Tomonori 			}
5207cbf67842SDouglas Gilbert 		}
5208c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5209c4837394SDouglas Gilbert 	}
5210a10bc12aSDouglas Gilbert 	return false;
52118dea0d02SFUJITA Tomonori }
52128dea0d02SFUJITA Tomonori 
5213a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
52142aad3cd8SDouglas Gilbert static void stop_all_queued(bool done_with_no_conn)
52158dea0d02SFUJITA Tomonori {
52168dea0d02SFUJITA Tomonori 	unsigned long iflags;
5217c4837394SDouglas Gilbert 	int j, k;
521810bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5219c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
52208dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5221cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5222a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
52232aad3cd8SDouglas Gilbert 	struct scsi_cmnd *scp;
52248dea0d02SFUJITA Tomonori 
5225c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5226c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5227c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5228c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5229c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
52302aad3cd8SDouglas Gilbert 				scp = sqcp->a_cmnd;
52312aad3cd8SDouglas Gilbert 				if (!scp)
5232a10bc12aSDouglas Gilbert 					continue;
5233db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5234db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5235db525fceSDouglas Gilbert 				if (devip)
5236db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5237db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5238a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
523910bde980SDouglas Gilbert 				if (sd_dp) {
5240d9d23a5aSDouglas Gilbert 					l_defer_t = READ_ONCE(sd_dp->defer_t);
5241d9d23a5aSDouglas Gilbert 					WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
524210bde980SDouglas Gilbert 				} else
524310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5244c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
524510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
52462aad3cd8SDouglas Gilbert 				if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) {
52472aad3cd8SDouglas Gilbert 					scp->result = DID_NO_CONNECT << 16;
52482aad3cd8SDouglas Gilbert 					scsi_done(scp);
52492aad3cd8SDouglas Gilbert 				}
5250c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5251c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
52528dea0d02SFUJITA Tomonori 			}
52538dea0d02SFUJITA Tomonori 		}
5254c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5255c4837394SDouglas Gilbert 	}
5256cbf67842SDouglas Gilbert }
5257cbf67842SDouglas Gilbert 
5258cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5259cbf67842SDouglas Gilbert static void free_all_queued(void)
5260cbf67842SDouglas Gilbert {
5261c4837394SDouglas Gilbert 	int j, k;
5262c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5263cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5264cbf67842SDouglas Gilbert 
5265c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5266c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5267c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5268a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5269a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5270cbf67842SDouglas Gilbert 		}
52711da177e4SLinus Torvalds 	}
5272c4837394SDouglas Gilbert }
52731da177e4SLinus Torvalds 
52741da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
52751da177e4SLinus Torvalds {
5276a10bc12aSDouglas Gilbert 	bool ok;
5277a10bc12aSDouglas Gilbert 
52781da177e4SLinus Torvalds 	++num_aborts;
5279cbf67842SDouglas Gilbert 	if (SCpnt) {
5280a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5281a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5282a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5283a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5284a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5285cbf67842SDouglas Gilbert 	}
52861da177e4SLinus Torvalds 	return SUCCESS;
52871da177e4SLinus Torvalds }
52881da177e4SLinus Torvalds 
52891da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
52901da177e4SLinus Torvalds {
52911da177e4SLinus Torvalds 	++num_dev_resets;
5292cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5293cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5294f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5295f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5296cbf67842SDouglas Gilbert 
5297773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5298cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
52991da177e4SLinus Torvalds 		if (devip)
5300cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
53011da177e4SLinus Torvalds 	}
53021da177e4SLinus Torvalds 	return SUCCESS;
53031da177e4SLinus Torvalds }
53041da177e4SLinus Torvalds 
5305cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5306cbf67842SDouglas Gilbert {
5307cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5308cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5309cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5310cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5311cbf67842SDouglas Gilbert 	int k = 0;
5312cbf67842SDouglas Gilbert 
5313cbf67842SDouglas Gilbert 	++num_target_resets;
5314cbf67842SDouglas Gilbert 	if (!SCpnt)
5315cbf67842SDouglas Gilbert 		goto lie;
5316cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5317cbf67842SDouglas Gilbert 	if (!sdp)
5318cbf67842SDouglas Gilbert 		goto lie;
5319773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5320cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5321cbf67842SDouglas Gilbert 	hp = sdp->host;
5322cbf67842SDouglas Gilbert 	if (!hp)
5323cbf67842SDouglas Gilbert 		goto lie;
5324cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5325cbf67842SDouglas Gilbert 	if (sdbg_host) {
5326cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5327cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5328cbf67842SDouglas Gilbert 				    dev_list)
5329cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5330cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5331cbf67842SDouglas Gilbert 				++k;
5332cbf67842SDouglas Gilbert 			}
5333cbf67842SDouglas Gilbert 	}
5334773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5335cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5336cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5337cbf67842SDouglas Gilbert lie:
5338cbf67842SDouglas Gilbert 	return SUCCESS;
5339cbf67842SDouglas Gilbert }
5340cbf67842SDouglas Gilbert 
53411da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
53421da177e4SLinus Torvalds {
53431da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5344cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
53451da177e4SLinus Torvalds 	struct scsi_device *sdp;
53461da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5347cbf67842SDouglas Gilbert 	int k = 0;
53481da177e4SLinus Torvalds 
53491da177e4SLinus Torvalds 	++num_bus_resets;
5350cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5351cbf67842SDouglas Gilbert 		goto lie;
5352cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5353773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5354cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5355cbf67842SDouglas Gilbert 	hp = sdp->host;
5356cbf67842SDouglas Gilbert 	if (hp) {
5357d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
53581da177e4SLinus Torvalds 		if (sdbg_host) {
5359cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
53601da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5361cbf67842SDouglas Gilbert 					    dev_list) {
5362cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5363cbf67842SDouglas Gilbert 				++k;
53641da177e4SLinus Torvalds 			}
53651da177e4SLinus Torvalds 		}
5366cbf67842SDouglas Gilbert 	}
5367773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5368cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5369cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5370cbf67842SDouglas Gilbert lie:
53711da177e4SLinus Torvalds 	return SUCCESS;
53721da177e4SLinus Torvalds }
53731da177e4SLinus Torvalds 
53741da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
53751da177e4SLinus Torvalds {
53761da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5377cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5378cbf67842SDouglas Gilbert 	int k = 0;
53791da177e4SLinus Torvalds 
53801da177e4SLinus Torvalds 	++num_host_resets;
5381773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5382cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
53831da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
53841da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5385cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5386cbf67842SDouglas Gilbert 				    dev_list) {
5387cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5388cbf67842SDouglas Gilbert 			++k;
5389cbf67842SDouglas Gilbert 		}
53901da177e4SLinus Torvalds 	}
53911da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
53922aad3cd8SDouglas Gilbert 	stop_all_queued(false);
5393773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5394cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5395cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
53961da177e4SLinus Torvalds 	return SUCCESS;
53971da177e4SLinus Torvalds }
53981da177e4SLinus Torvalds 
539987c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
54001da177e4SLinus Torvalds {
54011442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5402979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
54031da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
54041da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
54051da177e4SLinus Torvalds 
54061da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5407773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
54081da177e4SLinus Torvalds 		return;
5409773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5410773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5411c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
54121da177e4SLinus Torvalds 	}
54138c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
54141da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5415773642d9SDouglas Gilbert 			   / sdebug_num_parts;
54161da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
54171da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5418979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5419979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
54201da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
54211da177e4SLinus Torvalds 			    * heads_by_sects;
5422979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5423979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5424979e0dc3SJohn Pittman 	}
5425773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5426773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
54271da177e4SLinus Torvalds 
54281da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
54291da177e4SLinus Torvalds 	ramp[511] = 0xAA;
54301442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
54311da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
54321da177e4SLinus Torvalds 		start_sec = starts[k];
5433979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
54341da177e4SLinus Torvalds 		pp->boot_ind = 0;
54351da177e4SLinus Torvalds 
54361da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
54371da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
54381da177e4SLinus Torvalds 			   / sdebug_sectors_per;
54391da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
54401da177e4SLinus Torvalds 
54411da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
54421da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
54431da177e4SLinus Torvalds 			       / sdebug_sectors_per;
54441da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
54451da177e4SLinus Torvalds 
5446150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5447150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
54481da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
54491da177e4SLinus Torvalds 	}
54501da177e4SLinus Torvalds }
54511da177e4SLinus Torvalds 
54522aad3cd8SDouglas Gilbert static void sdeb_block_all_queues(void)
5453c4837394SDouglas Gilbert {
5454c4837394SDouglas Gilbert 	int j;
5455c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5456c4837394SDouglas Gilbert 
5457c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
54582aad3cd8SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)true);
54592aad3cd8SDouglas Gilbert }
54602aad3cd8SDouglas Gilbert 
54612aad3cd8SDouglas Gilbert static void sdeb_unblock_all_queues(void)
54622aad3cd8SDouglas Gilbert {
54632aad3cd8SDouglas Gilbert 	int j;
54642aad3cd8SDouglas Gilbert 	struct sdebug_queue *sqp;
54652aad3cd8SDouglas Gilbert 
54662aad3cd8SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
54672aad3cd8SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)false);
54682aad3cd8SDouglas Gilbert }
54692aad3cd8SDouglas Gilbert 
54702aad3cd8SDouglas Gilbert static void
54712aad3cd8SDouglas Gilbert sdeb_add_n_hosts(int num_hosts)
54722aad3cd8SDouglas Gilbert {
54732aad3cd8SDouglas Gilbert 	if (num_hosts < 1)
54742aad3cd8SDouglas Gilbert 		return;
54752aad3cd8SDouglas Gilbert 	do {
54762aad3cd8SDouglas Gilbert 		bool found;
54772aad3cd8SDouglas Gilbert 		unsigned long idx;
54782aad3cd8SDouglas Gilbert 		struct sdeb_store_info *sip;
54792aad3cd8SDouglas Gilbert 		bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
54802aad3cd8SDouglas Gilbert 
54812aad3cd8SDouglas Gilbert 		found = false;
54822aad3cd8SDouglas Gilbert 		if (want_phs) {
54832aad3cd8SDouglas Gilbert 			xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) {
54842aad3cd8SDouglas Gilbert 				sdeb_most_recent_idx = (int)idx;
54852aad3cd8SDouglas Gilbert 				found = true;
54862aad3cd8SDouglas Gilbert 				break;
54872aad3cd8SDouglas Gilbert 			}
54882aad3cd8SDouglas Gilbert 			if (found)	/* re-use case */
54892aad3cd8SDouglas Gilbert 				sdebug_add_host_helper((int)idx);
54902aad3cd8SDouglas Gilbert 			else
54912aad3cd8SDouglas Gilbert 				sdebug_do_add_host(true	/* make new store */);
54922aad3cd8SDouglas Gilbert 		} else {
54932aad3cd8SDouglas Gilbert 			sdebug_do_add_host(false);
54942aad3cd8SDouglas Gilbert 		}
54952aad3cd8SDouglas Gilbert 	} while (--num_hosts);
5496c4837394SDouglas Gilbert }
5497c4837394SDouglas Gilbert 
5498c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5499c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5500c4837394SDouglas Gilbert  */
5501c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5502c4837394SDouglas Gilbert {
5503c4837394SDouglas Gilbert 	int count, modulo;
5504c4837394SDouglas Gilbert 
5505c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5506c4837394SDouglas Gilbert 	if (modulo < 2)
5507c4837394SDouglas Gilbert 		return;
55082aad3cd8SDouglas Gilbert 	sdeb_block_all_queues();
5509c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5510c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
55112aad3cd8SDouglas Gilbert 	sdeb_unblock_all_queues();
5512c4837394SDouglas Gilbert }
5513c4837394SDouglas Gilbert 
5514c4837394SDouglas Gilbert static void clear_queue_stats(void)
5515c4837394SDouglas Gilbert {
5516c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5517c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5518c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5519c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5520c4837394SDouglas Gilbert }
5521c4837394SDouglas Gilbert 
55223a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5523c4837394SDouglas Gilbert {
55243a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
55253a90a63dSDouglas Gilbert 		return false;
55263a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5527c4837394SDouglas Gilbert }
5528c4837394SDouglas Gilbert 
55292aad3cd8SDouglas Gilbert static int process_deflect_incoming(struct scsi_cmnd *scp)
55302aad3cd8SDouglas Gilbert {
55312aad3cd8SDouglas Gilbert 	u8 opcode = scp->cmnd[0];
55322aad3cd8SDouglas Gilbert 
55332aad3cd8SDouglas Gilbert 	if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16)
55342aad3cd8SDouglas Gilbert 		return 0;
55352aad3cd8SDouglas Gilbert 	return DID_NO_CONNECT << 16;
55362aad3cd8SDouglas Gilbert }
55372aad3cd8SDouglas Gilbert 
5538a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5539a2aede97SDouglas Gilbert 
5540c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5541c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5542c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5543c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5544c4837394SDouglas Gilbert  */
5545fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5546f66b8517SMartin Wilck 			 int scsi_result,
55472aad3cd8SDouglas Gilbert 			 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *),
5548f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
55491da177e4SLinus Torvalds {
5550a2aede97SDouglas Gilbert 	bool new_sd_dp;
55513a90a63dSDouglas Gilbert 	bool inject = false;
55526ce913feSChristoph Hellwig 	bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED;
55533a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5554a2aede97SDouglas Gilbert 	unsigned long iflags;
5555a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5556c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5557c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5558299b6c07STomas Winkler 	struct scsi_device *sdp;
5559a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
55601da177e4SLinus Torvalds 
5561b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5562b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5563f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5564f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
55651da177e4SLinus Torvalds 	}
5566299b6c07STomas Winkler 	sdp = cmnd->device;
5567299b6c07STomas Winkler 
55682aad3cd8SDouglas Gilbert 	if (delta_jiff == 0) {
55692aad3cd8SDouglas Gilbert 		sqp = get_queue(cmnd);
55702aad3cd8SDouglas Gilbert 		if (atomic_read(&sqp->blocked)) {
55712aad3cd8SDouglas Gilbert 			if (smp_load_acquire(&sdebug_deflect_incoming))
55722aad3cd8SDouglas Gilbert 				return process_deflect_incoming(cmnd);
55732aad3cd8SDouglas Gilbert 			else
55742aad3cd8SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
55752aad3cd8SDouglas Gilbert 		}
5576cd62b7daSDouglas Gilbert 		goto respond_in_thread;
55772aad3cd8SDouglas Gilbert 	}
55781da177e4SLinus Torvalds 
5579c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5580c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5581c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5582c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
55832aad3cd8SDouglas Gilbert 		if (smp_load_acquire(&sdebug_deflect_incoming)) {
55842aad3cd8SDouglas Gilbert 			scsi_result = process_deflect_incoming(cmnd);
55852aad3cd8SDouglas Gilbert 			goto respond_in_thread;
55862aad3cd8SDouglas Gilbert 		}
55872aad3cd8SDouglas Gilbert 		if (sdebug_verbose)
55882aad3cd8SDouglas Gilbert 			pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n");
5589c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5590c4837394SDouglas Gilbert 	}
5591cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5592cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5593f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5594cd62b7daSDouglas Gilbert 		if (scsi_result) {
5595c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5596cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5597cd62b7daSDouglas Gilbert 		} else
5598cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5599c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5600773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5601f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5602cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5603cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5604773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5605cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
56063a90a63dSDouglas Gilbert 			inject = true;
5607cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
56081da177e4SLinus Torvalds 		}
5609cbf67842SDouglas Gilbert 	}
5610cbf67842SDouglas Gilbert 
5611c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5612f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5613c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5614cd62b7daSDouglas Gilbert 		if (scsi_result)
5615cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5616cd62b7daSDouglas Gilbert 		scsi_result = device_qfull_result;
5617773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
56187d5a129bSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
56197d5a129bSDouglas Gilbert 				    __func__, sdebug_max_queue);
5620cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56211da177e4SLinus Torvalds 	}
562274595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5623cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5624c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
56251da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5626c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5627a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5628c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5629c4b57d89SKashyap Desai 
563074595c04SDouglas Gilbert 	if (!sd_dp) {
563110bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
563274595c04SDouglas Gilbert 		if (!sd_dp) {
563374595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
563474595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
563510bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
563674595c04SDouglas Gilbert 		}
5637a2aede97SDouglas Gilbert 		new_sd_dp = true;
5638a2aede97SDouglas Gilbert 	} else {
5639a2aede97SDouglas Gilbert 		new_sd_dp = false;
564010bde980SDouglas Gilbert 	}
5641f66b8517SMartin Wilck 
5642c10fa55fSJohn Garry 	/* Set the hostwide tag */
5643c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5644c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5645c10fa55fSJohn Garry 
56466ce913feSChristoph Hellwig 	if (polled)
5647a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5648a2aede97SDouglas Gilbert 
5649a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
56503a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5651f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5652f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5653f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5654f66b8517SMartin Wilck 	}
5655f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5656f66b8517SMartin Wilck 		cmnd->result = scsi_result;
56573a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
56583a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
56593a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
56603a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56613a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
56623a90a63dSDouglas Gilbert 		}
56633a90a63dSDouglas Gilbert 	}
5664f66b8517SMartin Wilck 
5665f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5666f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5667f66b8517SMartin Wilck 			    __func__, cmnd->result);
5668f66b8517SMartin Wilck 
566910bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5670b333a819SDouglas Gilbert 		ktime_t kt;
5671cbf67842SDouglas Gilbert 
5672b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
56730c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
56740c4bc91dSDouglas Gilbert 
56750c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
56760c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
56770c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
56780c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
56790c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
56800c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
56810c4bc91dSDouglas Gilbert 				ns <<= 12;
56820c4bc91dSDouglas Gilbert 			}
56830c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
56840c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
56850c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
56860c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5687a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5688a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5689a2aede97SDouglas Gilbert 
5690a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5691223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
5692a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5693a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5694a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5695223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5696a2aede97SDouglas Gilbert 					if (new_sd_dp)
5697a2aede97SDouglas Gilbert 						kfree(sd_dp);
5698a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
56996c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5700a2aede97SDouglas Gilbert 					return 0;
5701a2aede97SDouglas Gilbert 				}
5702a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5703a2aede97SDouglas Gilbert 				kt -= d;
5704a2aede97SDouglas Gilbert 			}
57050c4bc91dSDouglas Gilbert 		}
57066ce913feSChristoph Hellwig 		if (polled) {
57074a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
57084a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57094a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57104a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57114a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57124a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57134a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57144a0c6f43SDouglas Gilbert 			}
5715d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57164a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57174a0c6f43SDouglas Gilbert 		} else {
571810bde980SDouglas Gilbert 			if (!sd_dp->init_hrt) {
571910bde980SDouglas Gilbert 				sd_dp->init_hrt = true;
5720a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5721a10bc12aSDouglas Gilbert 				hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5722c4837394SDouglas Gilbert 					     HRTIMER_MODE_REL_PINNED);
5723a10bc12aSDouglas Gilbert 				sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5724c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5725c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5726cbf67842SDouglas Gilbert 			}
5727d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
5728a2aede97SDouglas Gilbert 			/* schedule the invocation of scsi_done() for a later time */
5729c4837394SDouglas Gilbert 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
57304a0c6f43SDouglas Gilbert 		}
57314a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
57324a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
5733c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
57344a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
57354a0c6f43SDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
57364a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
57376ce913feSChristoph Hellwig 		if (polled) {
57384a0c6f43SDouglas Gilbert 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
57394a0c6f43SDouglas Gilbert 			spin_lock_irqsave(&sqp->qc_lock, iflags);
57404a0c6f43SDouglas Gilbert 			if (!sd_dp->init_poll) {
57414a0c6f43SDouglas Gilbert 				sd_dp->init_poll = true;
57424a0c6f43SDouglas Gilbert 				sqcp->sd_dp = sd_dp;
57434a0c6f43SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
57444a0c6f43SDouglas Gilbert 				sd_dp->qc_idx = k;
57454a0c6f43SDouglas Gilbert 			}
5746d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57474a0c6f43SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
57484a0c6f43SDouglas Gilbert 		} else {
574910bde980SDouglas Gilbert 			if (!sd_dp->init_wq) {
575010bde980SDouglas Gilbert 				sd_dp->init_wq = true;
5751a10bc12aSDouglas Gilbert 				sqcp->sd_dp = sd_dp;
5752c4837394SDouglas Gilbert 				sd_dp->sqa_idx = sqp - sdebug_q_arr;
5753c4837394SDouglas Gilbert 				sd_dp->qc_idx = k;
5754a10bc12aSDouglas Gilbert 				INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5755cbf67842SDouglas Gilbert 			}
5756d9d23a5aSDouglas Gilbert 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
57574a0c6f43SDouglas Gilbert 			schedule_work(&sd_dp->ew.work);
57584a0c6f43SDouglas Gilbert 		}
5759c4837394SDouglas Gilbert 		if (sdebug_statistics)
5760c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
57614a0c6f43SDouglas Gilbert 		if (unlikely(sd_dp->aborted)) {
5762a6e76e6fSBart Van Assche 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5763a6e76e6fSBart Van Assche 				    scsi_cmd_to_rq(cmnd)->tag);
5764a6e76e6fSBart Van Assche 			blk_abort_request(scsi_cmd_to_rq(cmnd));
57653a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
57664a0c6f43SDouglas Gilbert 			sd_dp->aborted = false;
57677382f9d8SDouglas Gilbert 		}
5768cbf67842SDouglas Gilbert 	}
57693a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
57703a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
57713a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
57721da177e4SLinus Torvalds 	return 0;
5773cd62b7daSDouglas Gilbert 
5774cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5775f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5776f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
57772aad3cd8SDouglas Gilbert 	if (cmnd->result == 0 && scsi_result != 0) {
5778cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
57792aad3cd8SDouglas Gilbert 		if (sdebug_verbose)
57802aad3cd8SDouglas Gilbert 			pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n",
57812aad3cd8SDouglas Gilbert 				blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result);
57822aad3cd8SDouglas Gilbert 	}
57836c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5784cd62b7daSDouglas Gilbert 	return 0;
57851da177e4SLinus Torvalds }
5786cbf67842SDouglas Gilbert 
578723183910SDouglas Gilbert /* Note: The following macros create attribute files in the
578823183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
578923183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
579023183910SDouglas Gilbert    as it can when the corresponding attribute in the
579123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
579223183910SDouglas Gilbert  */
5793773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5794773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
57959b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5796773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5797c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5798773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5799773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5800773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5801773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5802773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5803773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5804773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5805773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5806c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5807e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5808e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5809e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5810e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
58115d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
58125d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
58135d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5814773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5815773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5816773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5817773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5818ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5819773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5820773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
58215d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
58225d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58235d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
58245d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5825773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5826773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
58277109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
5828773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5829773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5830773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5831773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
58325d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5833773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
583487c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
583587c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5836773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5837773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
58380c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5839773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5840773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5841773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5842c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5843773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5844c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5845c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5846fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5847773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5848773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5849773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5850773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
585109ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
58525d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5853773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
585423183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58559447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5856773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
58575b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
58589267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5859380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5860aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
586198e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
58621da177e4SLinus Torvalds 
58631da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
58641da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
58651da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5866b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
58671da177e4SLinus Torvalds 
58685d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
58695b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
58709b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
58710759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5872cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5873c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
58745b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
58755b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5876c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5877beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
587823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
58795b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5880185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5881c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5882c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5883e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
58849b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
58859b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
58865d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
58875d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
58885d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
58895b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
58905b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
58915b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
58925b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5893ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5894fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5895cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5896d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
58975d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5898cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5899c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
59007109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
590178d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
59021da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5903c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
590432c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
590586e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
59065d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
59075d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
59085d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5909fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
59101da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
59110c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5912d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5913760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5914ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5915c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5916c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5917c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5918fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
59195b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
59205b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
59216014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
59226014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
592309ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
592409ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5925c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
59265b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
59279447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
59285b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
59299267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5930380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5931aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
593298e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
59331da177e4SLinus Torvalds 
5934760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5935760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
59361da177e4SLinus Torvalds 
59371da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
59381da177e4SLinus Torvalds {
5939c4837394SDouglas Gilbert 	int k;
5940c4837394SDouglas Gilbert 
5941760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5942760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5943760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5944c4837394SDouglas Gilbert 		return sdebug_info;
5945760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5946760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5947760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5948760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
59491da177e4SLinus Torvalds 	return sdebug_info;
59501da177e4SLinus Torvalds }
59511da177e4SLinus Torvalds 
5952cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5953fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5954fd32119bSDouglas Gilbert 				 int length)
59551da177e4SLinus Torvalds {
59561da177e4SLinus Torvalds 	char arr[16];
5957c8ed555aSAl Viro 	int opts;
59581da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
59591da177e4SLinus Torvalds 
59601da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
59611da177e4SLinus Torvalds 		return -EACCES;
59621da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
59631da177e4SLinus Torvalds 	arr[minLen] = '\0';
5964c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
59651da177e4SLinus Torvalds 		return -EINVAL;
5966773642d9SDouglas Gilbert 	sdebug_opts = opts;
5967773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5968773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5969773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5970c4837394SDouglas Gilbert 		tweak_cmnd_count();
59711da177e4SLinus Torvalds 	return length;
59721da177e4SLinus Torvalds }
5973c8ed555aSAl Viro 
5974cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5975cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5976cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5977c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5978c8ed555aSAl Viro {
5979c4837394SDouglas Gilbert 	int f, j, l;
5980c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
598187c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5982cbf67842SDouglas Gilbert 
5983c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5984c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5985c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5986c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5987c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5988c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5989c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5990c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5991c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5992c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5993c4837394SDouglas Gilbert 		   num_aborts);
5994c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5995c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5996c4837394SDouglas Gilbert 		   num_host_resets);
5997c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5998c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5999458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
6000458df78bSBart Van Assche 		   sdebug_statistics);
60014a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
6002c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
6003c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
6004c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
60054a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
60064a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
6007cbf67842SDouglas Gilbert 
6008c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
6009c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
6010c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
6011c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
6012773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
6013c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
6014c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
6015c4837394SDouglas Gilbert 				   "first,last bits", f, l);
6016c4837394SDouglas Gilbert 		}
6017cbf67842SDouglas Gilbert 	}
601887c715dcSDouglas Gilbert 
601987c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
602087c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
602187c715dcSDouglas Gilbert 		bool niu;
602287c715dcSDouglas Gilbert 		int idx;
602387c715dcSDouglas Gilbert 		unsigned long l_idx;
602487c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
602587c715dcSDouglas Gilbert 
602687c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
602787c715dcSDouglas Gilbert 		j = 0;
602887c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
602987c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
603087c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
603187c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
603287c715dcSDouglas Gilbert 			++j;
603387c715dcSDouglas Gilbert 		}
603487c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
603587c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
603687c715dcSDouglas Gilbert 		j = 0;
603787c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
603887c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
603987c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
604087c715dcSDouglas Gilbert 			idx = (int)l_idx;
604187c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
604287c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
604387c715dcSDouglas Gilbert 			++j;
604487c715dcSDouglas Gilbert 		}
604587c715dcSDouglas Gilbert 	}
6046c8ed555aSAl Viro 	return 0;
60471da177e4SLinus Torvalds }
60481da177e4SLinus Torvalds 
604982069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
60501da177e4SLinus Torvalds {
6051c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
60521da177e4SLinus Torvalds }
6053c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
6054c4837394SDouglas Gilbert  * of delay is jiffies.
6055c4837394SDouglas Gilbert  */
605682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
605782069379SAkinobu Mita 			   size_t count)
60581da177e4SLinus Torvalds {
6059c2206098SDouglas Gilbert 	int jdelay, res;
60601da177e4SLinus Torvalds 
6061b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
6062cbf67842SDouglas Gilbert 		res = count;
6063c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
6064c4837394SDouglas Gilbert 			int j, k;
6065c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6066cbf67842SDouglas Gilbert 
60672aad3cd8SDouglas Gilbert 			sdeb_block_all_queues();
6068c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6069c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6070c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6071c4837394SDouglas Gilbert 						   sdebug_max_queue);
6072c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6073c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6074c4837394SDouglas Gilbert 					break;
6075c4837394SDouglas Gilbert 				}
6076c4837394SDouglas Gilbert 			}
6077c4837394SDouglas Gilbert 			if (res > 0) {
6078c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
6079773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
60801da177e4SLinus Torvalds 			}
60812aad3cd8SDouglas Gilbert 			sdeb_unblock_all_queues();
6082cbf67842SDouglas Gilbert 		}
6083cbf67842SDouglas Gilbert 		return res;
60841da177e4SLinus Torvalds 	}
60851da177e4SLinus Torvalds 	return -EINVAL;
60861da177e4SLinus Torvalds }
608782069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
60881da177e4SLinus Torvalds 
6089cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
6090cbf67842SDouglas Gilbert {
6091773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
6092cbf67842SDouglas Gilbert }
6093cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6094c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
6095cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6096cbf67842SDouglas Gilbert 			    size_t count)
6097cbf67842SDouglas Gilbert {
6098c4837394SDouglas Gilbert 	int ndelay, res;
6099cbf67842SDouglas Gilbert 
6100cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6101c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6102cbf67842SDouglas Gilbert 		res = count;
6103773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
6104c4837394SDouglas Gilbert 			int j, k;
6105c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6106c4837394SDouglas Gilbert 
61072aad3cd8SDouglas Gilbert 			sdeb_block_all_queues();
6108c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6109c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6110c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6111c4837394SDouglas Gilbert 						   sdebug_max_queue);
6112c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6113c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6114c4837394SDouglas Gilbert 					break;
6115c4837394SDouglas Gilbert 				}
6116c4837394SDouglas Gilbert 			}
6117c4837394SDouglas Gilbert 			if (res > 0) {
6118773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6119c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6120c2206098SDouglas Gilbert 							: DEF_JDELAY;
6121cbf67842SDouglas Gilbert 			}
61222aad3cd8SDouglas Gilbert 			sdeb_unblock_all_queues();
6123cbf67842SDouglas Gilbert 		}
6124cbf67842SDouglas Gilbert 		return res;
6125cbf67842SDouglas Gilbert 	}
6126cbf67842SDouglas Gilbert 	return -EINVAL;
6127cbf67842SDouglas Gilbert }
6128cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6129cbf67842SDouglas Gilbert 
613082069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
61311da177e4SLinus Torvalds {
6132773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
61331da177e4SLinus Torvalds }
61341da177e4SLinus Torvalds 
613582069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
613682069379SAkinobu Mita 			  size_t count)
61371da177e4SLinus Torvalds {
61381da177e4SLinus Torvalds 	int opts;
61391da177e4SLinus Torvalds 	char work[20];
61401da177e4SLinus Torvalds 
61419a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61429a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61439a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
61441da177e4SLinus Torvalds 				goto opts_done;
61451da177e4SLinus Torvalds 		} else {
61469a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
61471da177e4SLinus Torvalds 				goto opts_done;
61481da177e4SLinus Torvalds 		}
61491da177e4SLinus Torvalds 	}
61501da177e4SLinus Torvalds 	return -EINVAL;
61511da177e4SLinus Torvalds opts_done:
6152773642d9SDouglas Gilbert 	sdebug_opts = opts;
6153773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6154773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6155c4837394SDouglas Gilbert 	tweak_cmnd_count();
61561da177e4SLinus Torvalds 	return count;
61571da177e4SLinus Torvalds }
615882069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
61591da177e4SLinus Torvalds 
616082069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
61611da177e4SLinus Torvalds {
6162773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
61631da177e4SLinus Torvalds }
616482069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
616582069379SAkinobu Mita 			   size_t count)
61661da177e4SLinus Torvalds {
61671da177e4SLinus Torvalds 	int n;
61681da177e4SLinus Torvalds 
6169f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6170f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6171f0d1cf93SDouglas Gilbert 		return -EINVAL;
6172f0d1cf93SDouglas Gilbert 
61731da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6174f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6175f0d1cf93SDouglas Gilbert 			return -EINVAL;
6176773642d9SDouglas Gilbert 		sdebug_ptype = n;
61771da177e4SLinus Torvalds 		return count;
61781da177e4SLinus Torvalds 	}
61791da177e4SLinus Torvalds 	return -EINVAL;
61801da177e4SLinus Torvalds }
618182069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
61821da177e4SLinus Torvalds 
618382069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
61841da177e4SLinus Torvalds {
6185773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
61861da177e4SLinus Torvalds }
618782069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
618882069379SAkinobu Mita 			    size_t count)
61891da177e4SLinus Torvalds {
61901da177e4SLinus Torvalds 	int n;
61911da177e4SLinus Torvalds 
61921da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6193773642d9SDouglas Gilbert 		sdebug_dsense = n;
61941da177e4SLinus Torvalds 		return count;
61951da177e4SLinus Torvalds 	}
61961da177e4SLinus Torvalds 	return -EINVAL;
61971da177e4SLinus Torvalds }
619882069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
61991da177e4SLinus Torvalds 
620082069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
620123183910SDouglas Gilbert {
6202773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
620323183910SDouglas Gilbert }
620482069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
620582069379SAkinobu Mita 			     size_t count)
620623183910SDouglas Gilbert {
620787c715dcSDouglas Gilbert 	int n, idx;
620823183910SDouglas Gilbert 
620923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
621087c715dcSDouglas Gilbert 		bool want_store = (n == 0);
621187c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
621287c715dcSDouglas Gilbert 
6213cbf67842SDouglas Gilbert 		n = (n > 0);
6214773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
621587c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
621687c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6217cbf67842SDouglas Gilbert 
621887c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
621987c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
622087c715dcSDouglas Gilbert 				idx = sdebug_add_store();
622187c715dcSDouglas Gilbert 				if (idx < 0)
622287c715dcSDouglas Gilbert 					return idx;
622387c715dcSDouglas Gilbert 			} else {
622487c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
622587c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
622687c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6227cbf67842SDouglas Gilbert 			}
622887c715dcSDouglas Gilbert 			/* make all hosts use same store */
622987c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
623087c715dcSDouglas Gilbert 					    host_list) {
623187c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
623287c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
623387c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
623487c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
623587c715dcSDouglas Gilbert 				}
623687c715dcSDouglas Gilbert 			}
623787c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
623887c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
623987c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6240cbf67842SDouglas Gilbert 		}
6241773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
624223183910SDouglas Gilbert 		return count;
624323183910SDouglas Gilbert 	}
624423183910SDouglas Gilbert 	return -EINVAL;
624523183910SDouglas Gilbert }
624682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
624723183910SDouglas Gilbert 
624882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6249c65b1445SDouglas Gilbert {
6250773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6251c65b1445SDouglas Gilbert }
625282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
625382069379SAkinobu Mita 			      size_t count)
6254c65b1445SDouglas Gilbert {
6255c65b1445SDouglas Gilbert 	int n;
6256c65b1445SDouglas Gilbert 
6257c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6258773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6259c65b1445SDouglas Gilbert 		return count;
6260c65b1445SDouglas Gilbert 	}
6261c65b1445SDouglas Gilbert 	return -EINVAL;
6262c65b1445SDouglas Gilbert }
626382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6264c65b1445SDouglas Gilbert 
626582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
62661da177e4SLinus Torvalds {
6267773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
62681da177e4SLinus Torvalds }
626982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
627082069379SAkinobu Mita 			      size_t count)
62711da177e4SLinus Torvalds {
62721da177e4SLinus Torvalds 	int n;
62731da177e4SLinus Torvalds 
62741da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6275773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
62761da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
62771da177e4SLinus Torvalds 		return count;
62781da177e4SLinus Torvalds 	}
62791da177e4SLinus Torvalds 	return -EINVAL;
62801da177e4SLinus Torvalds }
628182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
62821da177e4SLinus Torvalds 
628382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
62841da177e4SLinus Torvalds {
6285773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
62861da177e4SLinus Torvalds }
628782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
62881da177e4SLinus Torvalds 
628987c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
629087c715dcSDouglas Gilbert {
629187c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
629287c715dcSDouglas Gilbert }
629387c715dcSDouglas Gilbert 
629487c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
629587c715dcSDouglas Gilbert 				    size_t count)
629687c715dcSDouglas Gilbert {
629787c715dcSDouglas Gilbert 	bool v;
629887c715dcSDouglas Gilbert 
629987c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
630087c715dcSDouglas Gilbert 		return -EINVAL;
630187c715dcSDouglas Gilbert 
630287c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
630387c715dcSDouglas Gilbert 	return count;
630487c715dcSDouglas Gilbert }
630587c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
630687c715dcSDouglas Gilbert 
630782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
63081da177e4SLinus Torvalds {
6309773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
63101da177e4SLinus Torvalds }
631182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
63121da177e4SLinus Torvalds 
631382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
63141da177e4SLinus Torvalds {
6315773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
63161da177e4SLinus Torvalds }
631782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
631882069379SAkinobu Mita 			       size_t count)
63191da177e4SLinus Torvalds {
63201da177e4SLinus Torvalds 	int nth;
63213a90a63dSDouglas Gilbert 	char work[20];
63221da177e4SLinus Torvalds 
63233a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
63243a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
63253a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
63263a90a63dSDouglas Gilbert 				goto every_nth_done;
63273a90a63dSDouglas Gilbert 		} else {
63283a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
63293a90a63dSDouglas Gilbert 				goto every_nth_done;
63303a90a63dSDouglas Gilbert 		}
63313a90a63dSDouglas Gilbert 	}
63323a90a63dSDouglas Gilbert 	return -EINVAL;
63333a90a63dSDouglas Gilbert 
63343a90a63dSDouglas Gilbert every_nth_done:
6335773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6336c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6337c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6338c4837394SDouglas Gilbert 		sdebug_statistics = true;
6339c4837394SDouglas Gilbert 	}
6340c4837394SDouglas Gilbert 	tweak_cmnd_count();
63411da177e4SLinus Torvalds 	return count;
63421da177e4SLinus Torvalds }
634382069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
63441da177e4SLinus Torvalds 
6345ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6346ad0c7775SDouglas Gilbert {
6347ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6348ad0c7775SDouglas Gilbert }
6349ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6350ad0c7775SDouglas Gilbert 				size_t count)
6351ad0c7775SDouglas Gilbert {
6352ad0c7775SDouglas Gilbert 	int n;
6353ad0c7775SDouglas Gilbert 	bool changed;
6354ad0c7775SDouglas Gilbert 
6355ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6356ad0c7775SDouglas Gilbert 		return -EINVAL;
6357ad0c7775SDouglas Gilbert 	if (n >= 0) {
6358ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6359ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6360ad0c7775SDouglas Gilbert 			return -EINVAL;
6361ad0c7775SDouglas Gilbert 		}
6362ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6363ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6364ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6365ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6366ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6367ad0c7775SDouglas Gilbert 
6368ad0c7775SDouglas Gilbert 			spin_lock(&sdebug_host_list_lock);
6369ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6370ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6371ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6372ad0c7775SDouglas Gilbert 				}
6373ad0c7775SDouglas Gilbert 			}
6374ad0c7775SDouglas Gilbert 			spin_unlock(&sdebug_host_list_lock);
6375ad0c7775SDouglas Gilbert 		}
6376ad0c7775SDouglas Gilbert 		return count;
6377ad0c7775SDouglas Gilbert 	}
6378ad0c7775SDouglas Gilbert 	return -EINVAL;
6379ad0c7775SDouglas Gilbert }
6380ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6381ad0c7775SDouglas Gilbert 
638282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
63831da177e4SLinus Torvalds {
6384773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
63851da177e4SLinus Torvalds }
638682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
638782069379SAkinobu Mita 			      size_t count)
63881da177e4SLinus Torvalds {
63891da177e4SLinus Torvalds 	int n;
639019c8ead7SEwan D. Milne 	bool changed;
63911da177e4SLinus Torvalds 
63921da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
63938d039e22SDouglas Gilbert 		if (n > 256) {
63948d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
63958d039e22SDouglas Gilbert 			return -EINVAL;
63968d039e22SDouglas Gilbert 		}
6397773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6398773642d9SDouglas Gilbert 		sdebug_max_luns = n;
63991da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6400773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
640119c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
640219c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
640319c8ead7SEwan D. Milne 
640419c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
640519c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
640619c8ead7SEwan D. Milne 					    host_list) {
640719c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
640819c8ead7SEwan D. Milne 						    dev_list) {
640919c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
641019c8ead7SEwan D. Milne 						dp->uas_bm);
641119c8ead7SEwan D. Milne 				}
641219c8ead7SEwan D. Milne 			}
641319c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
641419c8ead7SEwan D. Milne 		}
64151da177e4SLinus Torvalds 		return count;
64161da177e4SLinus Torvalds 	}
64171da177e4SLinus Torvalds 	return -EINVAL;
64181da177e4SLinus Torvalds }
641982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
64201da177e4SLinus Torvalds 
642182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
642278d4e5a0SDouglas Gilbert {
6423773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
642478d4e5a0SDouglas Gilbert }
6425cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6426cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
642782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
642882069379SAkinobu Mita 			       size_t count)
642978d4e5a0SDouglas Gilbert {
6430c4837394SDouglas Gilbert 	int j, n, k, a;
6431c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
643278d4e5a0SDouglas Gilbert 
643378d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6434c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6435c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
64362aad3cd8SDouglas Gilbert 		sdeb_block_all_queues();
6437c4837394SDouglas Gilbert 		k = 0;
6438c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6439c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6440c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6441c4837394SDouglas Gilbert 			if (a > k)
6442c4837394SDouglas Gilbert 				k = a;
6443c4837394SDouglas Gilbert 		}
6444773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6445c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6446cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6447cbf67842SDouglas Gilbert 		else if (k >= n)
6448cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6449cbf67842SDouglas Gilbert 		else
6450cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
64512aad3cd8SDouglas Gilbert 		sdeb_unblock_all_queues();
645278d4e5a0SDouglas Gilbert 		return count;
645378d4e5a0SDouglas Gilbert 	}
645478d4e5a0SDouglas Gilbert 	return -EINVAL;
645578d4e5a0SDouglas Gilbert }
645682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
645778d4e5a0SDouglas Gilbert 
6458c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6459c10fa55fSJohn Garry {
6460c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6461c10fa55fSJohn Garry }
6462c10fa55fSJohn Garry 
64637109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
64647109f370SDouglas Gilbert {
64657109f370SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
64667109f370SDouglas Gilbert }
64677109f370SDouglas Gilbert 
64687109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
64697109f370SDouglas Gilbert {
64707109f370SDouglas Gilbert 	bool v;
64717109f370SDouglas Gilbert 
64727109f370SDouglas Gilbert 	if (kstrtobool(buf, &v))
64737109f370SDouglas Gilbert 		return -EINVAL;
64747109f370SDouglas Gilbert 
64757109f370SDouglas Gilbert 	sdebug_no_rwlock = v;
64767109f370SDouglas Gilbert 	return count;
64777109f370SDouglas Gilbert }
64787109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock);
64797109f370SDouglas Gilbert 
6480c10fa55fSJohn Garry /*
6481c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6482c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6483c10fa55fSJohn Garry  */
6484c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6485c10fa55fSJohn Garry 
648682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
648778d4e5a0SDouglas Gilbert {
6488773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
648978d4e5a0SDouglas Gilbert }
649082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
649178d4e5a0SDouglas Gilbert 
649282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
64931da177e4SLinus Torvalds {
6494773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
64951da177e4SLinus Torvalds }
649682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
64971da177e4SLinus Torvalds 
649882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6499c65b1445SDouglas Gilbert {
6500773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6501c65b1445SDouglas Gilbert }
650282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
650382069379SAkinobu Mita 				size_t count)
6504c65b1445SDouglas Gilbert {
6505c65b1445SDouglas Gilbert 	int n;
65060d01c5dfSDouglas Gilbert 	bool changed;
6507c65b1445SDouglas Gilbert 
6508f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6509f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6510f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6511f0d1cf93SDouglas Gilbert 
6512c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6513773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6514773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
651528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
65160d01c5dfSDouglas Gilbert 		if (changed) {
65170d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
65180d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
651928898873SFUJITA Tomonori 
65204bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
65210d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
65220d01c5dfSDouglas Gilbert 					    host_list) {
65230d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
65240d01c5dfSDouglas Gilbert 						    dev_list) {
65250d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
65260d01c5dfSDouglas Gilbert 						dp->uas_bm);
65270d01c5dfSDouglas Gilbert 				}
65280d01c5dfSDouglas Gilbert 			}
65294bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
65300d01c5dfSDouglas Gilbert 		}
6531c65b1445SDouglas Gilbert 		return count;
6532c65b1445SDouglas Gilbert 	}
6533c65b1445SDouglas Gilbert 	return -EINVAL;
6534c65b1445SDouglas Gilbert }
653582069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6536c65b1445SDouglas Gilbert 
653782069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
65381da177e4SLinus Torvalds {
653987c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
65402aad3cd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts));
65411da177e4SLinus Torvalds }
65421da177e4SLinus Torvalds 
65432aad3cd8SDouglas Gilbert /*
65442aad3cd8SDouglas Gilbert  * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'.
65452aad3cd8SDouglas Gilbert  * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing.
65462aad3cd8SDouglas Gilbert  * Returns -EBUSY if another add_host sysfs invocation is active.
65472aad3cd8SDouglas Gilbert  */
654882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
654982069379SAkinobu Mita 			      size_t count)
65501da177e4SLinus Torvalds {
65511da177e4SLinus Torvalds 	int delta_hosts;
65521da177e4SLinus Torvalds 
65532aad3cd8SDouglas Gilbert 	if (count == 0 || kstrtoint(buf, 0, &delta_hosts))
65541da177e4SLinus Torvalds 		return -EINVAL;
65552aad3cd8SDouglas Gilbert 	if (sdebug_verbose)
65562aad3cd8SDouglas Gilbert 		pr_info("prior num_hosts=%d, num_to_add=%d\n",
65572aad3cd8SDouglas Gilbert 			atomic_read(&sdebug_num_hosts), delta_hosts);
65582aad3cd8SDouglas Gilbert 	if (delta_hosts == 0)
65592aad3cd8SDouglas Gilbert 		return count;
65602aad3cd8SDouglas Gilbert 	if (mutex_trylock(&add_host_mutex) == 0)
65612aad3cd8SDouglas Gilbert 		return -EBUSY;
65621da177e4SLinus Torvalds 	if (delta_hosts > 0) {
65632aad3cd8SDouglas Gilbert 		sdeb_add_n_hosts(delta_hosts);
65642aad3cd8SDouglas Gilbert 	} else if (delta_hosts < 0) {
65652aad3cd8SDouglas Gilbert 		smp_store_release(&sdebug_deflect_incoming, true);
65662aad3cd8SDouglas Gilbert 		sdeb_block_all_queues();
65672aad3cd8SDouglas Gilbert 		if (delta_hosts >= atomic_read(&sdebug_num_hosts))
65682aad3cd8SDouglas Gilbert 			stop_all_queued(true);
65691da177e4SLinus Torvalds 		do {
65702aad3cd8SDouglas Gilbert 			if (atomic_read(&sdebug_num_hosts) < 1) {
65712aad3cd8SDouglas Gilbert 				free_all_queued();
657287c715dcSDouglas Gilbert 				break;
657387c715dcSDouglas Gilbert 			}
657487c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
65751da177e4SLinus Torvalds 		} while (++delta_hosts);
65762aad3cd8SDouglas Gilbert 		sdeb_unblock_all_queues();
65772aad3cd8SDouglas Gilbert 		smp_store_release(&sdebug_deflect_incoming, false);
65781da177e4SLinus Torvalds 	}
65792aad3cd8SDouglas Gilbert 	mutex_unlock(&add_host_mutex);
65802aad3cd8SDouglas Gilbert 	if (sdebug_verbose)
65812aad3cd8SDouglas Gilbert 		pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts));
65821da177e4SLinus Torvalds 	return count;
65831da177e4SLinus Torvalds }
658482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
65851da177e4SLinus Torvalds 
658682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
658723183910SDouglas Gilbert {
6588773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
658923183910SDouglas Gilbert }
659082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
659182069379SAkinobu Mita 				    size_t count)
659223183910SDouglas Gilbert {
659323183910SDouglas Gilbert 	int n;
659423183910SDouglas Gilbert 
659523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6596773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
659723183910SDouglas Gilbert 		return count;
659823183910SDouglas Gilbert 	}
659923183910SDouglas Gilbert 	return -EINVAL;
660023183910SDouglas Gilbert }
660182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
660223183910SDouglas Gilbert 
6603c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6604c4837394SDouglas Gilbert {
6605c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6606c4837394SDouglas Gilbert }
6607c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6608c4837394SDouglas Gilbert 				size_t count)
6609c4837394SDouglas Gilbert {
6610c4837394SDouglas Gilbert 	int n;
6611c4837394SDouglas Gilbert 
6612c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6613c4837394SDouglas Gilbert 		if (n > 0)
6614c4837394SDouglas Gilbert 			sdebug_statistics = true;
6615c4837394SDouglas Gilbert 		else {
6616c4837394SDouglas Gilbert 			clear_queue_stats();
6617c4837394SDouglas Gilbert 			sdebug_statistics = false;
6618c4837394SDouglas Gilbert 		}
6619c4837394SDouglas Gilbert 		return count;
6620c4837394SDouglas Gilbert 	}
6621c4837394SDouglas Gilbert 	return -EINVAL;
6622c4837394SDouglas Gilbert }
6623c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6624c4837394SDouglas Gilbert 
662582069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6626597136abSMartin K. Petersen {
6627773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6628597136abSMartin K. Petersen }
662982069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6630597136abSMartin K. Petersen 
6631c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6632c4837394SDouglas Gilbert {
6633c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6634c4837394SDouglas Gilbert }
6635c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6636c4837394SDouglas Gilbert 
663782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6638c6a44287SMartin K. Petersen {
6639773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6640c6a44287SMartin K. Petersen }
664182069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6642c6a44287SMartin K. Petersen 
664382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6644c6a44287SMartin K. Petersen {
6645773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6646c6a44287SMartin K. Petersen }
664782069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6648c6a44287SMartin K. Petersen 
664982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6650c6a44287SMartin K. Petersen {
6651773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6652c6a44287SMartin K. Petersen }
665382069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6654c6a44287SMartin K. Petersen 
665582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6656c6a44287SMartin K. Petersen {
6657773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6658c6a44287SMartin K. Petersen }
665982069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6660c6a44287SMartin K. Petersen 
666182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
666244d92694SMartin K. Petersen {
666387c715dcSDouglas Gilbert 	ssize_t count = 0;
666444d92694SMartin K. Petersen 
66655b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
666644d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
666744d92694SMartin K. Petersen 				 sdebug_store_sectors);
666844d92694SMartin K. Petersen 
666987c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
667087c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
667187c715dcSDouglas Gilbert 
667287c715dcSDouglas Gilbert 		if (sip)
6673c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
667487c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
667587c715dcSDouglas Gilbert 	}
667644d92694SMartin K. Petersen 	buf[count++] = '\n';
6677c7badc90STejun Heo 	buf[count] = '\0';
667844d92694SMartin K. Petersen 
667944d92694SMartin K. Petersen 	return count;
668044d92694SMartin K. Petersen }
668182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
668244d92694SMartin K. Petersen 
66830c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
66840c4bc91dSDouglas Gilbert {
66850c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
66860c4bc91dSDouglas Gilbert }
66870c4bc91dSDouglas Gilbert 
66880c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
66890c4bc91dSDouglas Gilbert 			    size_t count)
66900c4bc91dSDouglas Gilbert {
66910c4bc91dSDouglas Gilbert 	bool v;
66920c4bc91dSDouglas Gilbert 
66930c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
66940c4bc91dSDouglas Gilbert 		return -EINVAL;
66950c4bc91dSDouglas Gilbert 
66960c4bc91dSDouglas Gilbert 	sdebug_random = v;
66970c4bc91dSDouglas Gilbert 	return count;
66980c4bc91dSDouglas Gilbert }
66990c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
67000c4bc91dSDouglas Gilbert 
670182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6702d986788bSMartin Pitt {
6703773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6704d986788bSMartin Pitt }
670582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
670682069379SAkinobu Mita 			       size_t count)
6707d986788bSMartin Pitt {
6708d986788bSMartin Pitt 	int n;
6709d986788bSMartin Pitt 
6710d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6711773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6712d986788bSMartin Pitt 		return count;
6713d986788bSMartin Pitt 	}
6714d986788bSMartin Pitt 	return -EINVAL;
6715d986788bSMartin Pitt }
671682069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6717d986788bSMartin Pitt 
6718cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6719cbf67842SDouglas Gilbert {
6720773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6721cbf67842SDouglas Gilbert }
6722185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6723cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6724cbf67842SDouglas Gilbert 			       size_t count)
6725cbf67842SDouglas Gilbert {
6726185dd232SDouglas Gilbert 	int n;
6727cbf67842SDouglas Gilbert 
6728cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6729185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6730185dd232SDouglas Gilbert 		return count;
6731cbf67842SDouglas Gilbert 	}
6732cbf67842SDouglas Gilbert 	return -EINVAL;
6733cbf67842SDouglas Gilbert }
6734cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6735cbf67842SDouglas Gilbert 
6736c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6737c2248fc9SDouglas Gilbert {
6738773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6739c2248fc9SDouglas Gilbert }
6740c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6741c2248fc9SDouglas Gilbert 			    size_t count)
6742c2248fc9SDouglas Gilbert {
6743c2248fc9SDouglas Gilbert 	int n;
6744c2248fc9SDouglas Gilbert 
6745c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6746773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6747c2248fc9SDouglas Gilbert 		return count;
6748c2248fc9SDouglas Gilbert 	}
6749c2248fc9SDouglas Gilbert 	return -EINVAL;
6750c2248fc9SDouglas Gilbert }
6751c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6752c2248fc9SDouglas Gilbert 
675309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
675409ba24c1SDouglas Gilbert {
675509ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
675609ba24c1SDouglas Gilbert }
675709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
675809ba24c1SDouglas Gilbert 
67599b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
67609b760fd8SDouglas Gilbert {
67619b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
67629b760fd8SDouglas Gilbert }
67639b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
67649b760fd8SDouglas Gilbert 			     size_t count)
67659b760fd8SDouglas Gilbert {
67669b760fd8SDouglas Gilbert 	int ret, n;
67679b760fd8SDouglas Gilbert 
67689b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
67699b760fd8SDouglas Gilbert 	if (ret)
67709b760fd8SDouglas Gilbert 		return ret;
67719b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
67729b760fd8SDouglas Gilbert 	all_config_cdb_len();
67739b760fd8SDouglas Gilbert 	return count;
67749b760fd8SDouglas Gilbert }
67759b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
67769b760fd8SDouglas Gilbert 
67779267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
67789267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
67799267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
67809267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
67819267e0ebSDouglas Gilbert };
67829267e0ebSDouglas Gilbert 
67839267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
67849267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
67859267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
67869267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
67879267e0ebSDouglas Gilbert };
67889267e0ebSDouglas Gilbert 
67899267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
67909267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
67919267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
67929267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
67939267e0ebSDouglas Gilbert };
67949267e0ebSDouglas Gilbert 
67959267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
67969267e0ebSDouglas Gilbert {
67979267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
67989267e0ebSDouglas Gilbert 
67999267e0ebSDouglas Gilbert 	if (res < 0) {
68009267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
68019267e0ebSDouglas Gilbert 		if (res < 0) {
68029267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
680347742bdeSDan Carpenter 			if (res < 0)
68049267e0ebSDouglas Gilbert 				return -EINVAL;
68059267e0ebSDouglas Gilbert 		}
68069267e0ebSDouglas Gilbert 	}
68079267e0ebSDouglas Gilbert 	return res;
68089267e0ebSDouglas Gilbert }
68099267e0ebSDouglas Gilbert 
68109267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
68119267e0ebSDouglas Gilbert {
68129267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
68139267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
68149267e0ebSDouglas Gilbert }
68159267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6816cbf67842SDouglas Gilbert 
6817fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6818fc13638aSDouglas Gilbert {
6819fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6820fc13638aSDouglas Gilbert }
6821fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6822fc13638aSDouglas Gilbert 
682382069379SAkinobu Mita /* Note: The following array creates attribute files in the
682423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
682523183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
682623183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
682787c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
682823183910SDouglas Gilbert  */
68296ecaff7fSRandy Dunlap 
683082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
683182069379SAkinobu Mita 	&driver_attr_delay.attr,
683282069379SAkinobu Mita 	&driver_attr_opts.attr,
683382069379SAkinobu Mita 	&driver_attr_ptype.attr,
683482069379SAkinobu Mita 	&driver_attr_dsense.attr,
683582069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6836c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
683782069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
683882069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
683982069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
684082069379SAkinobu Mita 	&driver_attr_num_parts.attr,
684182069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6842ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
684382069379SAkinobu Mita 	&driver_attr_max_luns.attr,
684482069379SAkinobu Mita 	&driver_attr_max_queue.attr,
68457109f370SDouglas Gilbert 	&driver_attr_no_rwlock.attr,
684682069379SAkinobu Mita 	&driver_attr_no_uld.attr,
684782069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
684882069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
684982069379SAkinobu Mita 	&driver_attr_add_host.attr,
685087c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
685182069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
685282069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6853c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6854c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
685582069379SAkinobu Mita 	&driver_attr_dix.attr,
685682069379SAkinobu Mita 	&driver_attr_dif.attr,
685782069379SAkinobu Mita 	&driver_attr_guard.attr,
685882069379SAkinobu Mita 	&driver_attr_ato.attr,
685982069379SAkinobu Mita 	&driver_attr_map.attr,
68600c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
686182069379SAkinobu Mita 	&driver_attr_removable.attr,
6862cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6863cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6864c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
686509ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
68669b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6867fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
68689267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
686982069379SAkinobu Mita 	NULL,
687082069379SAkinobu Mita };
687182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
68721da177e4SLinus Torvalds 
687311ddcecaSAkinobu Mita static struct device *pseudo_primary;
68748dea0d02SFUJITA Tomonori 
68751da177e4SLinus Torvalds static int __init scsi_debug_init(void)
68761da177e4SLinus Torvalds {
687787c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
68785f2578e5SFUJITA Tomonori 	unsigned long sz;
687987c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
688087c715dcSDouglas Gilbert 	int idx = -1;
68811da177e4SLinus Torvalds 
688287c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
688387c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6884cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6885cbf67842SDouglas Gilbert 
6886773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6887c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6888773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6889773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6890c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6891cbf67842SDouglas Gilbert 
6892773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6893597136abSMartin K. Petersen 	case  512:
6894597136abSMartin K. Petersen 	case 1024:
6895597136abSMartin K. Petersen 	case 2048:
6896597136abSMartin K. Petersen 	case 4096:
6897597136abSMartin K. Petersen 		break;
6898597136abSMartin K. Petersen 	default:
6899773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6900597136abSMartin K. Petersen 		return -EINVAL;
6901597136abSMartin K. Petersen 	}
6902597136abSMartin K. Petersen 
6903773642d9SDouglas Gilbert 	switch (sdebug_dif) {
69048475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6905f46eb0e9SDouglas Gilbert 		break;
69068475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
69078475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
69088475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6909f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6910c6a44287SMartin K. Petersen 		break;
6911c6a44287SMartin K. Petersen 
6912c6a44287SMartin K. Petersen 	default:
6913c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6914c6a44287SMartin K. Petersen 		return -EINVAL;
6915c6a44287SMartin K. Petersen 	}
6916c6a44287SMartin K. Petersen 
6917aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6918aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6919aa5334c4SMaurizio Lombardi 		return -EINVAL;
6920aa5334c4SMaurizio Lombardi 	}
6921aa5334c4SMaurizio Lombardi 
6922773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6923c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6924c6a44287SMartin K. Petersen 		return -EINVAL;
6925c6a44287SMartin K. Petersen 	}
6926c6a44287SMartin K. Petersen 
6927773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6928c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6929c6a44287SMartin K. Petersen 		return -EINVAL;
6930c6a44287SMartin K. Petersen 	}
6931c6a44287SMartin K. Petersen 
6932773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6933773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6934ea61fca5SMartin K. Petersen 		return -EINVAL;
6935ea61fca5SMartin K. Petersen 	}
6936ad0c7775SDouglas Gilbert 
6937ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6938ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6939ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6940ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6941ad0c7775SDouglas Gilbert 	}
6942ad0c7775SDouglas Gilbert 
69438d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6944ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6945ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
69468d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
69478d039e22SDouglas Gilbert 		}
6948ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6949ad0c7775SDouglas Gilbert 	}
6950ea61fca5SMartin K. Petersen 
6951773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6952773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6953ea61fca5SMartin K. Petersen 		return -EINVAL;
6954ea61fca5SMartin K. Petersen 	}
6955ea61fca5SMartin K. Petersen 
6956c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6957c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6958c4837394SDouglas Gilbert 		return -EINVAL;
6959c4837394SDouglas Gilbert 	}
6960c87bf24cSJohn Garry 
6961c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6962c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6963c87bf24cSJohn Garry 		return -EINVAL;
6964c87bf24cSJohn Garry 	}
6965c87bf24cSJohn Garry 
6966c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6967c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6968c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6969c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6970c10fa55fSJohn Garry 		return -EINVAL;
6971c10fa55fSJohn Garry 	}
6972c10fa55fSJohn Garry 
6973c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6974c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6975c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6976c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6977c10fa55fSJohn Garry 			sdebug_max_queue);
6978c10fa55fSJohn Garry 	}
6979c10fa55fSJohn Garry 
6980c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6981c4837394SDouglas Gilbert 			       GFP_KERNEL);
6982c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6983c4837394SDouglas Gilbert 		return -ENOMEM;
6984c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6985c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6986c4837394SDouglas Gilbert 
6987f0d1cf93SDouglas Gilbert 	/*
69889267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
69899267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6990f0d1cf93SDouglas Gilbert 	 */
69919267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
69929267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
69939267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
69949267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
69959267e0ebSDouglas Gilbert 		if (k < 0) {
69969267e0ebSDouglas Gilbert 			ret = k;
69973b01d7eaSDinghao Liu 			goto free_q_arr;
69989267e0ebSDouglas Gilbert 		}
69999267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
70009267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
70019267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
700264e14eceSDamien Le Moal 		case BLK_ZONED_HA:
70039267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
70049267e0ebSDouglas Gilbert 			break;
70059267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
70069267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
70079267e0ebSDouglas Gilbert 			break;
70089267e0ebSDouglas Gilbert 		default:
70099267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
70103b01d7eaSDinghao Liu 			ret = -EINVAL;
70113b01d7eaSDinghao Liu 			goto free_q_arr;
70129267e0ebSDouglas Gilbert 		}
70139267e0ebSDouglas Gilbert 	}
70149267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
7015f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
70169267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70179267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
70189267e0ebSDouglas Gilbert 	}
7019f0d1cf93SDouglas Gilbert 
70209267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70219267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
7022773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
7023773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
7024773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
7025773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
702628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
70271da177e4SLinus Torvalds 
70281da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
70291da177e4SLinus Torvalds 	sdebug_heads = 8;
70301da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
7031773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
70321da177e4SLinus Torvalds 		sdebug_heads = 64;
7033773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
7034fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
70351da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70361da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70371da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
70381da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
70391da177e4SLinus Torvalds 		sdebug_heads = 255;
70401da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
70411da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70421da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70431da177e4SLinus Torvalds 	}
70445b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
7045773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
7046773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
70476014759cSMartin K. Petersen 
7048773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
7049773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
70506014759cSMartin K. Petersen 
7051773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
7052773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
70536014759cSMartin K. Petersen 
7054773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
7055773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
7056773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
7057c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
7058c4837394SDouglas Gilbert 			ret = -EINVAL;
705987c715dcSDouglas Gilbert 			goto free_q_arr;
706044d92694SMartin K. Petersen 		}
706144d92694SMartin K. Petersen 	}
706287c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
706387c715dcSDouglas Gilbert 	if (want_store) {
706487c715dcSDouglas Gilbert 		idx = sdebug_add_store();
706587c715dcSDouglas Gilbert 		if (idx < 0) {
706687c715dcSDouglas Gilbert 			ret = idx;
706787c715dcSDouglas Gilbert 			goto free_q_arr;
706887c715dcSDouglas Gilbert 		}
706944d92694SMartin K. Petersen 	}
707044d92694SMartin K. Petersen 
70719b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
70729b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
7073c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
70749b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
70756ecaff7fSRandy Dunlap 		goto free_vm;
70766ecaff7fSRandy Dunlap 	}
70776ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
70786ecaff7fSRandy Dunlap 	if (ret < 0) {
7079c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
70806ecaff7fSRandy Dunlap 		goto dev_unreg;
70816ecaff7fSRandy Dunlap 	}
70826ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
70836ecaff7fSRandy Dunlap 	if (ret < 0) {
7084c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
70856ecaff7fSRandy Dunlap 		goto bus_unreg;
70866ecaff7fSRandy Dunlap 	}
70871da177e4SLinus Torvalds 
708887c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
7089773642d9SDouglas Gilbert 	sdebug_add_host = 0;
70901da177e4SLinus Torvalds 
709187c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
70922aad3cd8SDouglas Gilbert 		if (smp_load_acquire(&sdebug_deflect_incoming)) {
70932aad3cd8SDouglas Gilbert 			pr_info("exit early as sdebug_deflect_incoming is set\n");
70942aad3cd8SDouglas Gilbert 			return 0;
70952aad3cd8SDouglas Gilbert 		}
709687c715dcSDouglas Gilbert 		if (want_store && k == 0) {
709787c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
709887c715dcSDouglas Gilbert 			if (ret < 0) {
709987c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
710087c715dcSDouglas Gilbert 				       k, -ret);
710187c715dcSDouglas Gilbert 				break;
710287c715dcSDouglas Gilbert 			}
710387c715dcSDouglas Gilbert 		} else {
710487c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
710587c715dcSDouglas Gilbert 						 sdebug_per_host_store);
710687c715dcSDouglas Gilbert 			if (ret < 0) {
710787c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
71081da177e4SLinus Torvalds 				break;
71091da177e4SLinus Torvalds 			}
71101da177e4SLinus Torvalds 		}
711187c715dcSDouglas Gilbert 	}
7112773642d9SDouglas Gilbert 	if (sdebug_verbose)
71132aad3cd8SDouglas Gilbert 		pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts));
7114c1287970STomas Winkler 
71152aad3cd8SDouglas Gilbert 	/*
71162aad3cd8SDouglas Gilbert 	 * Even though all the hosts have been established, due to async device (LU) scanning
71172aad3cd8SDouglas Gilbert 	 * by the scsi mid-level, there may still be devices (LUs) being set up.
71182aad3cd8SDouglas Gilbert 	 */
71191da177e4SLinus Torvalds 	return 0;
71206ecaff7fSRandy Dunlap 
71216ecaff7fSRandy Dunlap bus_unreg:
71226ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
71236ecaff7fSRandy Dunlap dev_unreg:
71249b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71256ecaff7fSRandy Dunlap free_vm:
712687c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
7127c4837394SDouglas Gilbert free_q_arr:
7128c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
71296ecaff7fSRandy Dunlap 	return ret;
71301da177e4SLinus Torvalds }
71311da177e4SLinus Torvalds 
71321da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
71331da177e4SLinus Torvalds {
71342aad3cd8SDouglas Gilbert 	int k;
71351da177e4SLinus Torvalds 
71362aad3cd8SDouglas Gilbert 	/* Possible race with LUs still being set up; stop them asap */
71372aad3cd8SDouglas Gilbert 	sdeb_block_all_queues();
71382aad3cd8SDouglas Gilbert 	smp_store_release(&sdebug_deflect_incoming, true);
71392aad3cd8SDouglas Gilbert 	stop_all_queued(false);
71402aad3cd8SDouglas Gilbert 	for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++)
714187c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
714252ab9768SLuis Henriques 	free_all_queued();
71432aad3cd8SDouglas Gilbert 	if (sdebug_verbose)
71442aad3cd8SDouglas Gilbert 		pr_info("removed %d hosts\n", k);
71451da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
71461da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
71479b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71481da177e4SLinus Torvalds 
714987c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
715087c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
7151f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
71521da177e4SLinus Torvalds }
71531da177e4SLinus Torvalds 
71541da177e4SLinus Torvalds device_initcall(scsi_debug_init);
71551da177e4SLinus Torvalds module_exit(scsi_debug_exit);
71561da177e4SLinus Torvalds 
71571da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
71581da177e4SLinus Torvalds {
71591da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71601da177e4SLinus Torvalds 
71611da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
71621da177e4SLinus Torvalds 	kfree(sdbg_host);
71631da177e4SLinus Torvalds }
71641da177e4SLinus Torvalds 
716587c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
716687c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
71671da177e4SLinus Torvalds {
716887c715dcSDouglas Gilbert 	if (idx < 0)
716987c715dcSDouglas Gilbert 		return;
717087c715dcSDouglas Gilbert 	if (!sip) {
717187c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
717287c715dcSDouglas Gilbert 			return;
717387c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
717487c715dcSDouglas Gilbert 		if (!sip)
717587c715dcSDouglas Gilbert 			return;
717687c715dcSDouglas Gilbert 	}
717787c715dcSDouglas Gilbert 	vfree(sip->map_storep);
717887c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
717987c715dcSDouglas Gilbert 	vfree(sip->storep);
718087c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
718187c715dcSDouglas Gilbert 	kfree(sip);
718287c715dcSDouglas Gilbert }
718387c715dcSDouglas Gilbert 
718487c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
718587c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
718687c715dcSDouglas Gilbert {
718787c715dcSDouglas Gilbert 	unsigned long idx;
718887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
718987c715dcSDouglas Gilbert 
719087c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
719187c715dcSDouglas Gilbert 		if (apart_from_first)
719287c715dcSDouglas Gilbert 			apart_from_first = false;
719387c715dcSDouglas Gilbert 		else
719487c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
719587c715dcSDouglas Gilbert 	}
719687c715dcSDouglas Gilbert 	if (apart_from_first)
719787c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
719887c715dcSDouglas Gilbert }
719987c715dcSDouglas Gilbert 
720087c715dcSDouglas Gilbert /*
720187c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
720287c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
720387c715dcSDouglas Gilbert  */
720487c715dcSDouglas Gilbert static int sdebug_add_store(void)
720587c715dcSDouglas Gilbert {
720687c715dcSDouglas Gilbert 	int res;
720787c715dcSDouglas Gilbert 	u32 n_idx;
720887c715dcSDouglas Gilbert 	unsigned long iflags;
720987c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
721087c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
721187c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
721287c715dcSDouglas Gilbert 
721387c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
721487c715dcSDouglas Gilbert 	if (!sip)
721587c715dcSDouglas Gilbert 		return -ENOMEM;
721687c715dcSDouglas Gilbert 
721787c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
721887c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
721987c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
722087c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
722187c715dcSDouglas Gilbert 		kfree(sip);
722287c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
722387c715dcSDouglas Gilbert 		return res;
722487c715dcSDouglas Gilbert 	}
722587c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
722687c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
722787c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
722887c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
722987c715dcSDouglas Gilbert 
723087c715dcSDouglas Gilbert 	res = -ENOMEM;
723187c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
723287c715dcSDouglas Gilbert 	if (!sip->storep) {
723387c715dcSDouglas Gilbert 		pr_err("user data oom\n");
723487c715dcSDouglas Gilbert 		goto err;
723587c715dcSDouglas Gilbert 	}
723687c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
723787c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
723887c715dcSDouglas Gilbert 
723987c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
724087c715dcSDouglas Gilbert 	if (sdebug_dix) {
724187c715dcSDouglas Gilbert 		int dif_size;
724287c715dcSDouglas Gilbert 
724387c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
724487c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
724587c715dcSDouglas Gilbert 
724687c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
724787c715dcSDouglas Gilbert 			sip->dif_storep);
724887c715dcSDouglas Gilbert 
724987c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
725087c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
725187c715dcSDouglas Gilbert 			goto err;
725287c715dcSDouglas Gilbert 		}
725387c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
725487c715dcSDouglas Gilbert 	}
725587c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
725687c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
725787c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
725887c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
725987c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
726087c715dcSDouglas Gilbert 
726187c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
726287c715dcSDouglas Gilbert 
726387c715dcSDouglas Gilbert 		if (!sip->map_storep) {
726487c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
726587c715dcSDouglas Gilbert 			goto err;
726687c715dcSDouglas Gilbert 		}
726787c715dcSDouglas Gilbert 
726887c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
726987c715dcSDouglas Gilbert 
727087c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
727187c715dcSDouglas Gilbert 		if (sdebug_num_parts)
727287c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
727387c715dcSDouglas Gilbert 	}
727487c715dcSDouglas Gilbert 
727587c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
727687c715dcSDouglas Gilbert 	return (int)n_idx;
727787c715dcSDouglas Gilbert err:
727887c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
727987c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
728087c715dcSDouglas Gilbert 	return res;
728187c715dcSDouglas Gilbert }
728287c715dcSDouglas Gilbert 
728387c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
728487c715dcSDouglas Gilbert {
728587c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
728687c715dcSDouglas Gilbert 	int error = -ENOMEM;
72871da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72888b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
72891da177e4SLinus Torvalds 
729024669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
729187c715dcSDouglas Gilbert 	if (!sdbg_host)
72921da177e4SLinus Torvalds 		return -ENOMEM;
729387c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
729487c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
729587c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
729687c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
72971da177e4SLinus Torvalds 
72981da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
72991da177e4SLinus Torvalds 
7300773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
73011da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
73025cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
730387c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
73041da177e4SLinus Torvalds 			goto clean;
73051da177e4SLinus Torvalds 	}
73061da177e4SLinus Torvalds 
73071da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73081da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
73091da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73101da177e4SLinus Torvalds 
73111da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
73129b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
73131da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
73142aad3cd8SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts));
73151da177e4SLinus Torvalds 
73161da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
73171da177e4SLinus Torvalds 	if (error)
73181da177e4SLinus Torvalds 		goto clean;
73191da177e4SLinus Torvalds 
73202aad3cd8SDouglas Gilbert 	atomic_inc(&sdebug_num_hosts);
732187c715dcSDouglas Gilbert 	return 0;
73221da177e4SLinus Torvalds 
73231da177e4SLinus Torvalds clean:
73248b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73258b40228fSFUJITA Tomonori 				 dev_list) {
73261da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7327f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73281da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73291da177e4SLinus Torvalds 	}
73301da177e4SLinus Torvalds 	kfree(sdbg_host);
733187c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
73321da177e4SLinus Torvalds 	return error;
73331da177e4SLinus Torvalds }
73341da177e4SLinus Torvalds 
733587c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
73361da177e4SLinus Torvalds {
733787c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
733887c715dcSDouglas Gilbert 
733987c715dcSDouglas Gilbert 	if (mk_new_store) {
734087c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
734187c715dcSDouglas Gilbert 		if (ph_idx < 0)
734287c715dcSDouglas Gilbert 			return ph_idx;
734387c715dcSDouglas Gilbert 	}
734487c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
734587c715dcSDouglas Gilbert }
734687c715dcSDouglas Gilbert 
734787c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
734887c715dcSDouglas Gilbert {
734987c715dcSDouglas Gilbert 	int idx = -1;
73501da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
735187c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
73521da177e4SLinus Torvalds 
73531da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
73541da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
73551da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
73561da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
735787c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
73581da177e4SLinus Torvalds 	}
735987c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
736087c715dcSDouglas Gilbert 		bool unique = true;
736187c715dcSDouglas Gilbert 
736287c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
736387c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
736487c715dcSDouglas Gilbert 				continue;
736587c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
736687c715dcSDouglas Gilbert 				unique = false;
736787c715dcSDouglas Gilbert 				break;
736887c715dcSDouglas Gilbert 			}
736987c715dcSDouglas Gilbert 		}
737087c715dcSDouglas Gilbert 		if (unique) {
737187c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
737287c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
737387c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
737487c715dcSDouglas Gilbert 		}
737587c715dcSDouglas Gilbert 	}
737687c715dcSDouglas Gilbert 	if (sdbg_host)
737787c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
73781da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
73791da177e4SLinus Torvalds 
73801da177e4SLinus Torvalds 	if (!sdbg_host)
73811da177e4SLinus Torvalds 		return;
73821da177e4SLinus Torvalds 
73831da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
73842aad3cd8SDouglas Gilbert 	atomic_dec(&sdebug_num_hosts);
73851da177e4SLinus Torvalds }
73861da177e4SLinus Torvalds 
7387fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7388cbf67842SDouglas Gilbert {
7389cbf67842SDouglas Gilbert 	int num_in_q = 0;
7390cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7391cbf67842SDouglas Gilbert 
73922aad3cd8SDouglas Gilbert 	sdeb_block_all_queues();
7393cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7394cbf67842SDouglas Gilbert 	if (NULL == devip) {
73952aad3cd8SDouglas Gilbert 		sdeb_unblock_all_queues();
7396cbf67842SDouglas Gilbert 		return	-ENODEV;
7397cbf67842SDouglas Gilbert 	}
7398cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7399c40ecc12SChristoph Hellwig 
7400fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7401fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7402fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7403fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7404fc09acb7SDouglas Gilbert 	}
7405cbf67842SDouglas Gilbert 	if (qdepth < 1)
7406cbf67842SDouglas Gilbert 		qdepth = 1;
7407fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7408db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7409cbf67842SDouglas Gilbert 
7410773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7411c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7412c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7413cbf67842SDouglas Gilbert 	}
74142aad3cd8SDouglas Gilbert 	sdeb_unblock_all_queues();
7415cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7416cbf67842SDouglas Gilbert }
7417cbf67842SDouglas Gilbert 
7418c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7419817fd66bSDouglas Gilbert {
7420c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7421773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7422773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7423773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7424c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7425773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7426817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7427c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7428817fd66bSDouglas Gilbert 	}
7429c4837394SDouglas Gilbert 	return false;
7430817fd66bSDouglas Gilbert }
7431817fd66bSDouglas Gilbert 
7432fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7433fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7434fc13638aSDouglas Gilbert {
7435fc13638aSDouglas Gilbert 	int stopped_state;
7436fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7437fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7438fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7439fc13638aSDouglas Gilbert 
7440fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7441fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7442fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7443fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7444fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7445fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7446fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7447fc13638aSDouglas Gilbert 				return 0;
7448fc13638aSDouglas Gilbert 			}
7449fc13638aSDouglas Gilbert 		}
7450fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7451fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7452fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7453fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7454fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7455fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7456fc13638aSDouglas Gilbert 
7457fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7458fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7459fc13638aSDouglas Gilbert 			else
7460fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7461fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7462fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7463fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7464fc13638aSDouglas Gilbert 						   diff_ns);
7465fc13638aSDouglas Gilbert 			return check_condition_result;
7466fc13638aSDouglas Gilbert 		}
7467fc13638aSDouglas Gilbert 	}
7468fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7469fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7470fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7471fc13638aSDouglas Gilbert 			    my_name);
7472fc13638aSDouglas Gilbert 	return check_condition_result;
7473fc13638aSDouglas Gilbert }
7474fc13638aSDouglas Gilbert 
7475c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost)
7476c4b57d89SKashyap Desai {
7477c4b57d89SKashyap Desai 	int i, qoff;
7478c4b57d89SKashyap Desai 
7479c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7480c4b57d89SKashyap Desai 		return 0;
7481c4b57d89SKashyap Desai 
7482c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7483c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7484c4b57d89SKashyap Desai 
7485c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7486c4b57d89SKashyap Desai 
7487c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7488c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7489c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7490c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7491c4b57d89SKashyap Desai 
7492c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7493c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7494c4b57d89SKashyap Desai 			continue;
7495c4b57d89SKashyap Desai 		}
7496c4b57d89SKashyap Desai 
7497c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7498c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7499c4b57d89SKashyap Desai 
7500c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7501c4b57d89SKashyap Desai 	}
7502c4b57d89SKashyap Desai 
7503c4b57d89SKashyap Desai 	return 0;
7504c4b57d89SKashyap Desai 
7505c4b57d89SKashyap Desai }
7506c4b57d89SKashyap Desai 
7507c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7508c4b57d89SKashyap Desai {
75094a0c6f43SDouglas Gilbert 	bool first;
75104a0c6f43SDouglas Gilbert 	bool retiring = false;
75114a0c6f43SDouglas Gilbert 	int num_entries = 0;
75124a0c6f43SDouglas Gilbert 	unsigned int qc_idx = 0;
7513c4b57d89SKashyap Desai 	unsigned long iflags;
75144a0c6f43SDouglas Gilbert 	ktime_t kt_from_boot = ktime_get_boottime();
7515c4b57d89SKashyap Desai 	struct sdebug_queue *sqp;
7516c4b57d89SKashyap Desai 	struct sdebug_queued_cmd *sqcp;
7517c4b57d89SKashyap Desai 	struct scsi_cmnd *scp;
7518c4b57d89SKashyap Desai 	struct sdebug_dev_info *devip;
75194a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7520c4b57d89SKashyap Desai 
7521c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
75224a0c6f43SDouglas Gilbert 
7523c4b57d89SKashyap Desai 	spin_lock_irqsave(&sqp->qc_lock, iflags);
75244a0c6f43SDouglas Gilbert 
7525*6a0d0ae3SDamien Le Moal 	qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
7526*6a0d0ae3SDamien Le Moal 	if (qc_idx >= sdebug_max_queue)
7527*6a0d0ae3SDamien Le Moal 		goto unlock;
7528*6a0d0ae3SDamien Le Moal 
75294a0c6f43SDouglas Gilbert 	for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
75304a0c6f43SDouglas Gilbert 		if (first) {
75314a0c6f43SDouglas Gilbert 			first = false;
7532b05d4e48SDouglas Gilbert 			if (!test_bit(qc_idx, sqp->in_use_bm))
7533b05d4e48SDouglas Gilbert 				continue;
75344a0c6f43SDouglas Gilbert 		} else {
75354a0c6f43SDouglas Gilbert 			qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
75364a0c6f43SDouglas Gilbert 		}
7537b05d4e48SDouglas Gilbert 		if (qc_idx >= sdebug_max_queue)
75384a0c6f43SDouglas Gilbert 			break;
7539c4b57d89SKashyap Desai 
7540c4b57d89SKashyap Desai 		sqcp = &sqp->qc_arr[qc_idx];
75414a0c6f43SDouglas Gilbert 		sd_dp = sqcp->sd_dp;
75424a0c6f43SDouglas Gilbert 		if (unlikely(!sd_dp))
75434a0c6f43SDouglas Gilbert 			continue;
7544c4b57d89SKashyap Desai 		scp = sqcp->a_cmnd;
7545c4b57d89SKashyap Desai 		if (unlikely(scp == NULL)) {
75464a0c6f43SDouglas Gilbert 			pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
7547c4b57d89SKashyap Desai 			       queue_num, qc_idx, __func__);
75484a0c6f43SDouglas Gilbert 			break;
7549c4b57d89SKashyap Desai 		}
7550d9d23a5aSDouglas Gilbert 		if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) {
75514a0c6f43SDouglas Gilbert 			if (kt_from_boot < sd_dp->cmpl_ts)
75524a0c6f43SDouglas Gilbert 				continue;
75534a0c6f43SDouglas Gilbert 
75546ce913feSChristoph Hellwig 		} else		/* ignoring non REQ_POLLED requests */
75554a0c6f43SDouglas Gilbert 			continue;
7556c4b57d89SKashyap Desai 		devip = (struct sdebug_dev_info *)scp->device->hostdata;
7557c4b57d89SKashyap Desai 		if (likely(devip))
7558c4b57d89SKashyap Desai 			atomic_dec(&devip->num_in_q);
7559c4b57d89SKashyap Desai 		else
7560c4b57d89SKashyap Desai 			pr_err("devip=NULL from %s\n", __func__);
7561c4b57d89SKashyap Desai 		if (unlikely(atomic_read(&retired_max_queue) > 0))
75624a0c6f43SDouglas Gilbert 			retiring = true;
7563c4b57d89SKashyap Desai 
7564c4b57d89SKashyap Desai 		sqcp->a_cmnd = NULL;
7565c4b57d89SKashyap Desai 		if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
75664a0c6f43SDouglas Gilbert 			pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
7567c4b57d89SKashyap Desai 				sqp, queue_num, qc_idx, __func__);
75684a0c6f43SDouglas Gilbert 			break;
7569c4b57d89SKashyap Desai 		}
7570c4b57d89SKashyap Desai 		if (unlikely(retiring)) {	/* user has reduced max_queue */
7571c4b57d89SKashyap Desai 			int k, retval;
7572c4b57d89SKashyap Desai 
7573c4b57d89SKashyap Desai 			retval = atomic_read(&retired_max_queue);
7574c4b57d89SKashyap Desai 			if (qc_idx >= retval) {
7575c4b57d89SKashyap Desai 				pr_err("index %d too large\n", retval);
75764a0c6f43SDouglas Gilbert 				break;
7577c4b57d89SKashyap Desai 			}
7578c4b57d89SKashyap Desai 			k = find_last_bit(sqp->in_use_bm, retval);
7579c4b57d89SKashyap Desai 			if ((k < sdebug_max_queue) || (k == retval))
7580c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, 0);
7581c4b57d89SKashyap Desai 			else
7582c4b57d89SKashyap Desai 				atomic_set(&retired_max_queue, k + 1);
7583c4b57d89SKashyap Desai 		}
7584d9d23a5aSDouglas Gilbert 		WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
7585c4b57d89SKashyap Desai 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75866c2c7d6aSBart Van Assche 		scsi_done(scp); /* callback to mid level */
7587c4b57d89SKashyap Desai 		num_entries++;
75883fd07aecSDamien Le Moal 		spin_lock_irqsave(&sqp->qc_lock, iflags);
7589b05d4e48SDouglas Gilbert 		if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue)
75903fd07aecSDamien Le Moal 			break;
75914a0c6f43SDouglas Gilbert 	}
75923fd07aecSDamien Le Moal 
7593*6a0d0ae3SDamien Le Moal unlock:
7594c4b57d89SKashyap Desai 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
75953fd07aecSDamien Le Moal 
75964a0c6f43SDouglas Gilbert 	if (num_entries > 0)
75974a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7598c4b57d89SKashyap Desai 	return num_entries;
7599c4b57d89SKashyap Desai }
7600c4b57d89SKashyap Desai 
7601fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7602fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7603c2248fc9SDouglas Gilbert {
7604c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7605c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7606c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7607c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7608c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7609c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7610c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7611f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7612c2248fc9SDouglas Gilbert 	int k, na;
7613c2248fc9SDouglas Gilbert 	int errsts = 0;
7614ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7615c2248fc9SDouglas Gilbert 	u32 flags;
7616c2248fc9SDouglas Gilbert 	u16 sa;
7617c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7618c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
76193a90a63dSDouglas Gilbert 	bool inject_now;
7620c2248fc9SDouglas Gilbert 
7621c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
76223a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7623c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
76243a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
76253a90a63dSDouglas Gilbert 	} else {
76263a90a63dSDouglas Gilbert 		inject_now = false;
76273a90a63dSDouglas Gilbert 	}
7628f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7629f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7630c2248fc9SDouglas Gilbert 		char b[120];
7631c2248fc9SDouglas Gilbert 		int n, len, sb;
7632c2248fc9SDouglas Gilbert 
7633c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7634c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7635c2248fc9SDouglas Gilbert 		if (len > 32)
7636c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7637c2248fc9SDouglas Gilbert 		else {
7638c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7639c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7640c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7641c2248fc9SDouglas Gilbert 		}
7642458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7643a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7644c2248fc9SDouglas Gilbert 	}
76453a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
76467ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
764734d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7648ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7649f46eb0e9SDouglas Gilbert 		goto err_out;
7650c2248fc9SDouglas Gilbert 
7651c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7652c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7653c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7654f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7655f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7656c2248fc9SDouglas Gilbert 		if (NULL == devip)
7657f46eb0e9SDouglas Gilbert 			goto err_out;
7658c2248fc9SDouglas Gilbert 	}
76593a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
76603a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
76613a90a63dSDouglas Gilbert 
7662c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7663c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7664c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7665c2248fc9SDouglas Gilbert 		r_oip = oip;
7666c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7667c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7668c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7669c2248fc9SDouglas Gilbert 			else
7670c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7671c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7672c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7673c2248fc9SDouglas Gilbert 					break;
7674c2248fc9SDouglas Gilbert 			}
7675c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7676c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7677c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7678c2248fc9SDouglas Gilbert 					break;
7679c2248fc9SDouglas Gilbert 			}
7680c2248fc9SDouglas Gilbert 		}
7681c2248fc9SDouglas Gilbert 		if (k > na) {
7682c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7683c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7684c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7685c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7686c2248fc9SDouglas Gilbert 			else
7687c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7688c2248fc9SDouglas Gilbert 			goto check_cond;
7689c2248fc9SDouglas Gilbert 		}
7690c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7691c2248fc9SDouglas Gilbert 	flags = oip->flags;
7692f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7693c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7694c2248fc9SDouglas Gilbert 		goto check_cond;
7695c2248fc9SDouglas Gilbert 	}
7696f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7697773642d9SDouglas Gilbert 		if (sdebug_verbose)
7698773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7699773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7700c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7701c2248fc9SDouglas Gilbert 		goto check_cond;
7702c2248fc9SDouglas Gilbert 	}
7703f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7704c2248fc9SDouglas Gilbert 		u8 rem;
7705c2248fc9SDouglas Gilbert 		int j;
7706c2248fc9SDouglas Gilbert 
7707c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7708c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7709c2248fc9SDouglas Gilbert 			if (rem) {
7710c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7711c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7712c2248fc9SDouglas Gilbert 						break;
7713c2248fc9SDouglas Gilbert 				}
7714c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7715c2248fc9SDouglas Gilbert 				goto check_cond;
7716c2248fc9SDouglas Gilbert 			}
7717c2248fc9SDouglas Gilbert 		}
7718c2248fc9SDouglas Gilbert 	}
7719f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7720b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7721b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7722f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7723c2248fc9SDouglas Gilbert 		if (errsts)
7724c2248fc9SDouglas Gilbert 			goto check_cond;
7725c2248fc9SDouglas Gilbert 	}
7726fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7727fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7728fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7729fc13638aSDouglas Gilbert 		if (errsts)
7730c2248fc9SDouglas Gilbert 			goto fini;
7731c2248fc9SDouglas Gilbert 	}
7732773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7733c2248fc9SDouglas Gilbert 		goto fini;
7734f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7735c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7736c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7737c2248fc9SDouglas Gilbert 	}
7738f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7739f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7740f66b8517SMartin Wilck 	else
7741f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7742c2248fc9SDouglas Gilbert 
7743c2248fc9SDouglas Gilbert fini:
774467da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7745f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
774675aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
774775aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
774880c49563SDouglas Gilbert 		/*
774975aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
775075aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
775175aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
775275aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
775380c49563SDouglas Gilbert 		 */
775480c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
77554f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
775680c49563SDouglas Gilbert 
77574f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7758f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
775980c49563SDouglas Gilbert 	} else
7760f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
776110bde980SDouglas Gilbert 				     sdebug_ndelay);
7762c2248fc9SDouglas Gilbert check_cond:
7763f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7764f46eb0e9SDouglas Gilbert err_out:
7765f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7766c2248fc9SDouglas Gilbert }
7767c2248fc9SDouglas Gilbert 
77689e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7769c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7770c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
77719e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
77729e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
77739e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
77749e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
77759e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
77769e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
77779e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7778185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7779cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7780c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7781c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
77829e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
77839e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7784cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7785cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
77869e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7787c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
77889e603ca0SFUJITA Tomonori 	.this_id =		7,
778965e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7790cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
77916bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
779250c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
77939e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7794c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
77959e603ca0SFUJITA Tomonori };
77969e603ca0SFUJITA Tomonori 
77971da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
77981da177e4SLinus Torvalds {
77991da177e4SLinus Torvalds 	int error = 0;
78001da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
78011da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7802f46eb0e9SDouglas Gilbert 	int hprot;
78031da177e4SLinus Torvalds 
78041da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
78051da177e4SLinus Torvalds 
7806773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7807fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
78082a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
78094af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
78104af14d11SChristoph Hellwig 
78111da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
78121da177e4SLinus Torvalds 	if (NULL == hpnt) {
7813c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
78141da177e4SLinus Torvalds 		error = -ENODEV;
78151da177e4SLinus Torvalds 		return error;
78161da177e4SLinus Torvalds 	}
7817c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
78189b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7819c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7820c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7821c4837394SDouglas Gilbert 	}
7822c10fa55fSJohn Garry 	/*
7823c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7824f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7825c10fa55fSJohn Garry 	 */
7826c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7827f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7828f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
78291da177e4SLinus Torvalds 
7830c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7831c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7832c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7833c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7834c4b57d89SKashyap Desai 		poll_queues = 0;
7835c4b57d89SKashyap Desai 	}
7836c4b57d89SKashyap Desai 
7837c4b57d89SKashyap Desai 	/*
7838c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7839c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7840c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7841c4b57d89SKashyap Desai 	 */
7842c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7843fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7844c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7845fc09acb7SDouglas Gilbert 		else
7846fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7847fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7848c4b57d89SKashyap Desai 		poll_queues = 1;
7849c4b57d89SKashyap Desai 	}
7850c4b57d89SKashyap Desai 	if (poll_queues)
7851c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7852c4b57d89SKashyap Desai 
78531da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
78541da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7855773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7856773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
78571da177e4SLinus Torvalds 	else
7858773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7859773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7860f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
78611da177e4SLinus Torvalds 
7862f46eb0e9SDouglas Gilbert 	hprot = 0;
7863c6a44287SMartin K. Petersen 
7864773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7865c6a44287SMartin K. Petersen 
78668475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7867f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7868773642d9SDouglas Gilbert 		if (sdebug_dix)
7869f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7870c6a44287SMartin K. Petersen 		break;
7871c6a44287SMartin K. Petersen 
78728475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7873f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7874773642d9SDouglas Gilbert 		if (sdebug_dix)
7875f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7876c6a44287SMartin K. Petersen 		break;
7877c6a44287SMartin K. Petersen 
78788475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7879f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7880773642d9SDouglas Gilbert 		if (sdebug_dix)
7881f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7882c6a44287SMartin K. Petersen 		break;
7883c6a44287SMartin K. Petersen 
7884c6a44287SMartin K. Petersen 	default:
7885773642d9SDouglas Gilbert 		if (sdebug_dix)
7886f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7887c6a44287SMartin K. Petersen 		break;
7888c6a44287SMartin K. Petersen 	}
7889c6a44287SMartin K. Petersen 
7890f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7891c6a44287SMartin K. Petersen 
7892f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7893c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7894f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7895f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7896f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7897f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7898f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7899f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7900f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7901c6a44287SMartin K. Petersen 
7902773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7903c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7904c6a44287SMartin K. Petersen 	else
7905c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7906c6a44287SMartin K. Petersen 
7907773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7908773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7909c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7910c4837394SDouglas Gilbert 		sdebug_statistics = true;
79111da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
79121da177e4SLinus Torvalds 	if (error) {
7913c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
79141da177e4SLinus Torvalds 		error = -ENODEV;
79151da177e4SLinus Torvalds 		scsi_host_put(hpnt);
791687c715dcSDouglas Gilbert 	} else {
79171da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
791887c715dcSDouglas Gilbert 	}
79191da177e4SLinus Torvalds 
79201da177e4SLinus Torvalds 	return error;
79211da177e4SLinus Torvalds }
79221da177e4SLinus Torvalds 
7923fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
79241da177e4SLinus Torvalds {
79251da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
79268b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
79271da177e4SLinus Torvalds 
79281da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
79291da177e4SLinus Torvalds 
79301da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
79311da177e4SLinus Torvalds 
79328b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
79338b40228fSFUJITA Tomonori 				 dev_list) {
79341da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7935f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
79361da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
79371da177e4SLinus Torvalds 	}
79381da177e4SLinus Torvalds 
79391da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
79401da177e4SLinus Torvalds }
79411da177e4SLinus Torvalds 
79428dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
79438dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
79441da177e4SLinus Torvalds {
79458dea0d02SFUJITA Tomonori 	return 1;
79468dea0d02SFUJITA Tomonori }
79471da177e4SLinus Torvalds 
79488dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
79498dea0d02SFUJITA Tomonori 	.name = "pseudo",
79508dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
79518dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
79528dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
795382069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
79548dea0d02SFUJITA Tomonori };
7955