xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 84905d34)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
51da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
61da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
71da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
81da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91da177e4SLinus Torvalds  *
1048e3bf16SDouglas Gilbert  * Copyright (C) 2001 - 2020 Douglas Gilbert
111da177e4SLinus Torvalds  *
1230f67481SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/genhd.h>
271da177e4SLinus Torvalds #include <linux/fs.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/vmalloc.h>
311da177e4SLinus Torvalds #include <linux/moduleparam.h>
32852e034dSJens Axboe #include <linux/scatterlist.h>
331da177e4SLinus Torvalds #include <linux/blkdev.h>
34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
35cbf67842SDouglas Gilbert #include <linux/spinlock.h>
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 */
6330f67481SDouglas Gilbert #define SDEBUG_VERSION "0190"	/* format to fit INQUIRY revision field */
6430f67481SDouglas Gilbert static const char *sdebug_version_date = "20200710";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
101f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1021da177e4SLinus Torvalds 
1036f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1046f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1056f3cbf55SDouglas Gilbert 
1061da177e4SLinus Torvalds /* Default values for driver parameters */
1071da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1081da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1091da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1111da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1121da177e4SLinus Torvalds  */
1135b94e232SMartin K. Petersen #define DEF_ATO 1
1149b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
115c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1169267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1171da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1189267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1195b94e232SMartin K. Petersen #define DEF_DIF 0
1205b94e232SMartin K. Petersen #define DEF_DIX 0
12187c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1225b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1231da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1245b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1255b94e232SMartin K. Petersen #define DEF_GUARD 0
126cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1275b94e232SMartin K. Petersen #define DEF_LBPU 0
1285b94e232SMartin K. Petersen #define DEF_LBPWS 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS10 0
130be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1315b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
132cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1335b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1341da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1351da177e4SLinus Torvalds #define DEF_OPTS   0
13632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1375b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
139b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1400c4bc91dSDouglas Gilbert #define DEF_RANDOM false
141d986788bSMartin Pitt #define DEF_REMOVABLE false
142760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1435b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1445b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1455b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1466014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1485b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1495b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1505b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
151c2248fc9SDouglas Gilbert #define DEF_STRICT 0
152c4837394SDouglas Gilbert #define DEF_STATISTICS false
153c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
15409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
155c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1561da177e4SLinus Torvalds 
157f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
158f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
159f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
160aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
161f0d1cf93SDouglas Gilbert 
162b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
163b01f6f83SDouglas Gilbert 
164773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
165773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
166773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
167773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
168773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
170773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
171773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
172773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
173773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
174773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
175773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
176773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
177773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
179773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1807ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1817382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
182773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
183773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
185773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
186773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1877ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1887382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1897382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1903a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1913a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1921da177e4SLinus Torvalds 
193cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
194cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
195cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
196cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
197cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
198cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
199cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2000d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
20119c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
202acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
203acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
204acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
205cbf67842SDouglas Gilbert 
206773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2071da177e4SLinus Torvalds  * sector on read commands: */
2081da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20932f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2121da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2131da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2141da177e4SLinus Torvalds 
215c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
216c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
217c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
218c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
219c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
220c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
221c4837394SDouglas Gilbert  */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
223c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
224cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
225cbf67842SDouglas Gilbert 
226b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
227b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
228b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
229fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
230fd32119bSDouglas Gilbert #define F_D_UNKN		8
231b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
232b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
233b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
234b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
235b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
236b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
237b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
238b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
239b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
240b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
241fd32119bSDouglas Gilbert 
242b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
243fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24446f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
245fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2464f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
247fd32119bSDouglas Gilbert 
248fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
249fd32119bSDouglas Gilbert 
250b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
251fd32119bSDouglas Gilbert 
25287c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25387c715dcSDouglas Gilbert 
25464e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25564e14eceSDamien Le Moal enum sdebug_z_type {
25664e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_CNV	= 0x1,
25764e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWR	= 0x2,
25864e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWP	= 0x3,
25964e14eceSDamien Le Moal };
26064e14eceSDamien Le Moal 
261f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
262f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
263f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
264f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
265f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
266f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
267f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
268f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
269f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
270f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
271f0d1cf93SDouglas Gilbert };
272f0d1cf93SDouglas Gilbert 
273f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
27464e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
275f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
27664e14eceSDamien Le Moal 	bool z_non_seq_resource;
277f0d1cf93SDouglas Gilbert 	unsigned int z_size;
278f0d1cf93SDouglas Gilbert 	sector_t z_start;
279f0d1cf93SDouglas Gilbert 	sector_t z_wp;
280f0d1cf93SDouglas Gilbert };
281fd32119bSDouglas Gilbert 
282fd32119bSDouglas Gilbert struct sdebug_dev_info {
283fd32119bSDouglas Gilbert 	struct list_head dev_list;
284fd32119bSDouglas Gilbert 	unsigned int channel;
285fd32119bSDouglas Gilbert 	unsigned int target;
286fd32119bSDouglas Gilbert 	u64 lun;
287bf476433SChristoph Hellwig 	uuid_t lu_name;
288fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
289fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
290fd32119bSDouglas Gilbert 	atomic_t num_in_q;
291c4837394SDouglas Gilbert 	atomic_t stopped;
292fd32119bSDouglas Gilbert 	bool used;
293f0d1cf93SDouglas Gilbert 
294f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
29564e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
296f0d1cf93SDouglas Gilbert 	unsigned int zsize;
297f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
298f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
299aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
300f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
301f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
302f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
303f0d1cf93SDouglas Gilbert 	unsigned int max_open;
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,
32710bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
32810bde980SDouglas Gilbert 
329fd32119bSDouglas Gilbert struct sdebug_defer {
330fd32119bSDouglas Gilbert 	struct hrtimer hrt;
331fd32119bSDouglas Gilbert 	struct execute_work ew;
332c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
333c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
334c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
335c4837394SDouglas Gilbert 	int issuing_cpu;
33610bde980SDouglas Gilbert 	bool init_hrt;
33710bde980SDouglas Gilbert 	bool init_wq;
3387382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
33910bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
340fd32119bSDouglas Gilbert };
341fd32119bSDouglas Gilbert 
342fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
343c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
344c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
345c4837394SDouglas Gilbert 	 */
346fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
347fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
348fd32119bSDouglas Gilbert };
349fd32119bSDouglas Gilbert 
350c4837394SDouglas Gilbert struct sdebug_queue {
351c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
352c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
353c4837394SDouglas Gilbert 	spinlock_t qc_lock;
354c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
355fd32119bSDouglas Gilbert };
356fd32119bSDouglas Gilbert 
357c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
358c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
359c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
360c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3613a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
362c4837394SDouglas Gilbert 
363fd32119bSDouglas Gilbert struct opcode_info_t {
364b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
365b01f6f83SDouglas Gilbert 				/* for terminating element */
366fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
367fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
368fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
369fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
370fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3719a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3729a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
373fd32119bSDouglas Gilbert };
374fd32119bSDouglas Gilbert 
375fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
376c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
377c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
378c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
379c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
380c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
381c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
382c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
383c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
384c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
385c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
386c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
387c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
388c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
38946f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39046f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
391c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
392c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
393c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
394481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
395c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
396c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
397c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
398c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
399c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
400c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
401c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
402c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
403c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
404c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
405c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
406ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
407f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
408f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
409f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
410c2248fc9SDouglas Gilbert };
411c2248fc9SDouglas Gilbert 
412c4837394SDouglas Gilbert 
413c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
414c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
415c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
416c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
417c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
418c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
419c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
420c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
421c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
422c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
423c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
424c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
425ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
426c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
427c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
428c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
429c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
430c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
431c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
432c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
433fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
434c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
435c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
436c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
437c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
438c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
439c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
440c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
441f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
442f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44346f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
444c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
445c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
446c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
44746f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
44846f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
449c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
450c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
451c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
452c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
455c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
456c2248fc9SDouglas Gilbert };
457c2248fc9SDouglas Gilbert 
45880c49563SDouglas Gilbert /*
45980c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46080c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46180c49563SDouglas Gilbert  * command completion, they can mask their return value with
46280c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46380c49563SDouglas Gilbert  */
46480c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46580c49563SDouglas Gilbert 
466c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
467c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
468c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
469c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
470c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
475481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48138d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48238d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
483c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
48638d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
487acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
48880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
489ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
490f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
491f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
492f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
493f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
494f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
495c2248fc9SDouglas Gilbert 
49687c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
49787c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
49887c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
49987c715dcSDouglas Gilbert static int sdebug_add_store(void);
50087c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50187c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50287c715dcSDouglas Gilbert 
50346f64e70SDouglas Gilbert /*
50446f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50546f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
50646f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
50746f64e70SDouglas Gilbert  */
50846f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
509c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
510c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
511c2248fc9SDouglas Gilbert };
512c2248fc9SDouglas Gilbert 
51346f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
514c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
515c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
516c2248fc9SDouglas Gilbert };
517c2248fc9SDouglas Gilbert 
51846f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
51946f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
520b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
521c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52246f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
523c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52446f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
525b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
526c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
527c2248fc9SDouglas Gilbert };
528c2248fc9SDouglas Gilbert 
52946f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53046f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53146f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53246f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53346f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53446f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53546f64e70SDouglas Gilbert 		   0, 0, 0} },
53646f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
53746f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53846f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
539c2248fc9SDouglas Gilbert };
540c2248fc9SDouglas Gilbert 
541c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
542c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
543c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
544c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
545c3e2fe92SDouglas Gilbert };
546c3e2fe92SDouglas Gilbert 
54746f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
548c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
549c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55046f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
551c2248fc9SDouglas Gilbert };
552c2248fc9SDouglas Gilbert 
55346f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55446f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
555b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
556c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
557481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
558481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
559481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
560c2248fc9SDouglas Gilbert };
561c2248fc9SDouglas Gilbert 
56246f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56338d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
564c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56546f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
56638d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
567c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
56846f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
569c2248fc9SDouglas Gilbert };
570c2248fc9SDouglas Gilbert 
57146f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57246f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
573c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57446f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
575c2248fc9SDouglas Gilbert };
576c2248fc9SDouglas Gilbert 
57746f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
578c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
579c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
580c2248fc9SDouglas Gilbert };
581c2248fc9SDouglas Gilbert 
58246f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
583c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
584c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
585c2248fc9SDouglas Gilbert };
586c2248fc9SDouglas Gilbert 
58780c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5884f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
58980c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59080c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59180c49563SDouglas Gilbert };
59280c49563SDouglas Gilbert 
593ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
594b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
595ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
596ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
597ed9f3e25SDouglas Gilbert };
598ed9f3e25SDouglas Gilbert 
599f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
600b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
601f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
602f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
603b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
604f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
605f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
606b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
607f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
608f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
609f0d1cf93SDouglas Gilbert };
610f0d1cf93SDouglas Gilbert 
611f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
612b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
613f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
614f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
615f0d1cf93SDouglas Gilbert };
616f0d1cf93SDouglas Gilbert 
617c2248fc9SDouglas Gilbert 
618c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
619c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
620c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
621ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
622c2248fc9SDouglas Gilbert /* 0 */
62346f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
624c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62546f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
626c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
627c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
628c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
62946f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
630c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
631c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
632c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
633c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63446f64e70SDouglas Gilbert /* 5 */
63546f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
63646f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
63746f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
63846f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
63946f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64046f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64146f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
642c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
643c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64446f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
645c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
646c2248fc9SDouglas Gilbert 	     0, 0} },
64746f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
64846f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
64946f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
650c2248fc9SDouglas Gilbert /* 10 */
65146f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65246f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65346f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65480c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6554f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
656c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65746f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
65846f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
65946f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66046f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
661481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
662481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
663481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66446f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66546f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
66646f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
66746f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
66846f64e70SDouglas Gilbert /* 15 */
669c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
670c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
671c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
672c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
673c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
674c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67546f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
67646f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
67746f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
67846f64e70SDouglas Gilbert 	     0xff, 0xff} },
67946f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68046f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
681c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
682c2248fc9SDouglas Gilbert 	     0} },
68346f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68446f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
685c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
686c2248fc9SDouglas Gilbert 	     0} },
687c2248fc9SDouglas Gilbert /* 20 */
688f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
689f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
690c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
691c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
692c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
693c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
694c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
695c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
69646f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
697b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
69846f64e70SDouglas Gilbert /* 25 */
699acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
700acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
701acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70246f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70346f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70446f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70546f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7064f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
70780c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
708b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
70980c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71046f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
711c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
712b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
713b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
714ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
715ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
716ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
717c2248fc9SDouglas Gilbert 
718ed9f3e25SDouglas Gilbert /* 30 */
719b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
720f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
721f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
722f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
723b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
724f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
725f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
726f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
727f0d1cf93SDouglas Gilbert /* sentinel */
728c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
729c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
730c2248fc9SDouglas Gilbert };
731c2248fc9SDouglas Gilbert 
73287c715dcSDouglas Gilbert static int sdebug_num_hosts;
73387c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
734773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7359b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
736c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7379267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
738773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
739773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
740773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
741773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
742773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
743773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
744c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
745773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
746773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
747c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
748d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
749d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
750cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
751c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
752773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
753773642d9SDouglas Gilbert static int sdebug_no_uld;
754773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
755773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
756773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
757773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
758773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
75986e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
760b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
761773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
762773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
763773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
764773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
765773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
766773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
767773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
768773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
769773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
770773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
771773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
772773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
773773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
77409ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7750c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
77687c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
777773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
778773642d9SDouglas Gilbert static bool sdebug_clustering;
779773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
780773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
781817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
782773642d9SDouglas Gilbert static bool sdebug_verbose;
783f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7844f2c8bf6SDouglas Gilbert static bool write_since_sync;
785c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7869447b6ceSMartin K. Petersen static bool sdebug_wp;
7879267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7889267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7899267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7901da177e4SLinus Torvalds 
791c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
7921da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
7951da177e4SLinus Torvalds    may still need them */
7961da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
7971da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
7981da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8011da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8021da177e4SLinus Torvalds 
80387c715dcSDouglas Gilbert static struct xarray per_store_arr;
80487c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
80587c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
80687c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
80787c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8081da177e4SLinus Torvalds 
80944d92694SMartin K. Petersen static unsigned long map_size;
810cbf67842SDouglas Gilbert static int num_aborts;
811cbf67842SDouglas Gilbert static int num_dev_resets;
812cbf67842SDouglas Gilbert static int num_target_resets;
813cbf67842SDouglas Gilbert static int num_bus_resets;
814cbf67842SDouglas Gilbert static int num_host_resets;
815c6a44287SMartin K. Petersen static int dix_writes;
816c6a44287SMartin K. Petersen static int dix_reads;
817c6a44287SMartin K. Petersen static int dif_errors;
8181da177e4SLinus Torvalds 
819f0d1cf93SDouglas Gilbert /* ZBC global data */
82064e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
82198e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
822380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
823aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
824f0d1cf93SDouglas Gilbert 
825c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
826c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
827fd32119bSDouglas Gilbert 
8281da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
82987c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
83087c715dcSDouglas Gilbert 
83187c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8321da177e4SLinus Torvalds 
833cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
834cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8391da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8401da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8411da177e4SLinus Torvalds };
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds static const int check_condition_result =
8441da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8451da177e4SLinus Torvalds 
846c6a44287SMartin K. Petersen static const int illegal_condition_result =
847c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
848c6a44287SMartin K. Petersen 
849cbf67842SDouglas Gilbert static const int device_qfull_result =
850cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
851cbf67842SDouglas Gilbert 
852ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
853ed9f3e25SDouglas Gilbert 
854fd32119bSDouglas Gilbert 
855760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
856760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
857760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
858760f3b03SDouglas Gilbert  */
859760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
860fd32119bSDouglas Gilbert {
861fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
862fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
863fd32119bSDouglas Gilbert }
864c65b1445SDouglas Gilbert 
86587c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
86687c715dcSDouglas Gilbert 			    unsigned long long lba)
86714faa944SAkinobu Mita {
86887c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
86914faa944SAkinobu Mita 
87087c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
87187c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
87287c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
87387c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
87487c715dcSDouglas Gilbert 	}
87587c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
87614faa944SAkinobu Mita }
87714faa944SAkinobu Mita 
87887c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
87987c715dcSDouglas Gilbert 				      sector_t sector)
88014faa944SAkinobu Mita {
88149413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
88214faa944SAkinobu Mita 
88387c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
88414faa944SAkinobu Mita }
88514faa944SAkinobu Mita 
8868dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8878dea0d02SFUJITA Tomonori {
8888dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
8898dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
8908dea0d02SFUJITA Tomonori 
8918dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
8928dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8938dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
8948dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
895773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
896773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
8978dea0d02SFUJITA Tomonori 		else
898773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
899773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
900f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9018dea0d02SFUJITA Tomonori 	}
9028dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9038dea0d02SFUJITA Tomonori }
9048dea0d02SFUJITA Tomonori 
90522017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
90622017ed2SDouglas Gilbert 
90722017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
908fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
909fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
91022017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
91122017ed2SDouglas Gilbert {
91222017ed2SDouglas Gilbert 	unsigned char *sbuff;
91322017ed2SDouglas Gilbert 	u8 sks[4];
91422017ed2SDouglas Gilbert 	int sl, asc;
91522017ed2SDouglas Gilbert 
91622017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
91722017ed2SDouglas Gilbert 	if (!sbuff) {
91822017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
91922017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
92022017ed2SDouglas Gilbert 		return;
92122017ed2SDouglas Gilbert 	}
92222017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
92322017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
924773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
92522017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
92622017ed2SDouglas Gilbert 	sks[0] = 0x80;
92722017ed2SDouglas Gilbert 	if (c_d)
92822017ed2SDouglas Gilbert 		sks[0] |= 0x40;
92922017ed2SDouglas Gilbert 	if (in_bit >= 0) {
93022017ed2SDouglas Gilbert 		sks[0] |= 0x8;
93122017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
93222017ed2SDouglas Gilbert 	}
93322017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
934773642d9SDouglas Gilbert 	if (sdebug_dsense) {
93522017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
93622017ed2SDouglas Gilbert 		sbuff[7] = sl;
93722017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
93822017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
93922017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
94022017ed2SDouglas Gilbert 	} else
94122017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
942773642d9SDouglas Gilbert 	if (sdebug_verbose)
94322017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
94422017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
94522017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
94622017ed2SDouglas Gilbert }
94722017ed2SDouglas Gilbert 
948cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9498dea0d02SFUJITA Tomonori {
9508dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
9518dea0d02SFUJITA Tomonori 
952cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
953cbf67842SDouglas Gilbert 	if (!sbuff) {
954cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
955cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
956cbf67842SDouglas Gilbert 		return;
957cbf67842SDouglas Gilbert 	}
958cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9598dea0d02SFUJITA Tomonori 
960773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9618dea0d02SFUJITA Tomonori 
962773642d9SDouglas Gilbert 	if (sdebug_verbose)
963cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
964cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
965cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9668dea0d02SFUJITA Tomonori }
9671da177e4SLinus Torvalds 
968fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
96922017ed2SDouglas Gilbert {
97022017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
97122017ed2SDouglas Gilbert }
97222017ed2SDouglas Gilbert 
9736f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9746f4e626fSNathan Chancellor 			    void __user *arg)
9751da177e4SLinus Torvalds {
976773642d9SDouglas Gilbert 	if (sdebug_verbose) {
977cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
978cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
979cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
980cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
981cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
982cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
983cbf67842SDouglas Gilbert 				    __func__);
984cbf67842SDouglas Gilbert 		else
985cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
986cbf67842SDouglas Gilbert 				    __func__, cmd);
9871da177e4SLinus Torvalds 	}
9881da177e4SLinus Torvalds 	return -EINVAL;
9891da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
9901da177e4SLinus Torvalds }
9911da177e4SLinus Torvalds 
9929b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
9939b760fd8SDouglas Gilbert {
9949b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
9959b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
9969b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
9979b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
9989b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
9999b760fd8SDouglas Gilbert 		break;
10009b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10019b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10029b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10039b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10049b760fd8SDouglas Gilbert 		break;
10059b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10069b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10079b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10089b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10099b760fd8SDouglas Gilbert 		break;
10109b760fd8SDouglas Gilbert 	case 16:
10119b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10129b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10149b760fd8SDouglas Gilbert 		break;
10159b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10179b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10199b760fd8SDouglas Gilbert 		break;
10209b760fd8SDouglas Gilbert 	default:
10219b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10229b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10239b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10249b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10259b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10269b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10279b760fd8SDouglas Gilbert 		break;
10289b760fd8SDouglas Gilbert 	}
10299b760fd8SDouglas Gilbert }
10309b760fd8SDouglas Gilbert 
10319b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10329b760fd8SDouglas Gilbert {
10339b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10349b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10359b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10369b760fd8SDouglas Gilbert 
10379b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10389b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10399b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10409b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10419b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10429b760fd8SDouglas Gilbert 		}
10439b760fd8SDouglas Gilbert 	}
10449b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10459b760fd8SDouglas Gilbert }
10469b760fd8SDouglas Gilbert 
104719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
104819c8ead7SEwan D. Milne {
104919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
105019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
105119c8ead7SEwan D. Milne 
105219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
105319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
105419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
105519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
105619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
105719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
105819c8ead7SEwan D. Milne 		}
105919c8ead7SEwan D. Milne 	}
106019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
106119c8ead7SEwan D. Milne }
106219c8ead7SEwan D. Milne 
1063f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10641da177e4SLinus Torvalds {
1065cbf67842SDouglas Gilbert 	int k;
1066cbf67842SDouglas Gilbert 
1067cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1068cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1069cbf67842SDouglas Gilbert 		const char *cp = NULL;
1070cbf67842SDouglas Gilbert 
1071cbf67842SDouglas Gilbert 		switch (k) {
1072cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1073f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1074f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1075773642d9SDouglas Gilbert 			if (sdebug_verbose)
1076cbf67842SDouglas Gilbert 				cp = "power on reset";
1077cbf67842SDouglas Gilbert 			break;
1078cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1079f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1080f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1081773642d9SDouglas Gilbert 			if (sdebug_verbose)
1082cbf67842SDouglas Gilbert 				cp = "bus reset";
1083cbf67842SDouglas Gilbert 			break;
1084cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1085f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1086f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1087773642d9SDouglas Gilbert 			if (sdebug_verbose)
1088cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1089cbf67842SDouglas Gilbert 			break;
10900d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1091f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1092f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1093773642d9SDouglas Gilbert 			if (sdebug_verbose)
10940d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1095f49accf1SEwan D. Milne 			break;
1096acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1097f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1098b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1099b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1100773642d9SDouglas Gilbert 			if (sdebug_verbose)
1101acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1102acafd0b9SEwan D. Milne 			break;
1103acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1104f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1105acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1106acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1107773642d9SDouglas Gilbert 			if (sdebug_verbose)
1108acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1109acafd0b9SEwan D. Milne 			break;
111019c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
111119c8ead7SEwan D. Milne 			/*
111219c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
111319c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
111419c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
111519c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1116773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
111719c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
111819c8ead7SEwan D. Milne 			 */
1119773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
112019c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1121f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
112219c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
112319c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1124773642d9SDouglas Gilbert 			if (sdebug_verbose)
112519c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
112619c8ead7SEwan D. Milne 			break;
1127cbf67842SDouglas Gilbert 		default:
1128773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1129773642d9SDouglas Gilbert 			if (sdebug_verbose)
1130cbf67842SDouglas Gilbert 				cp = "unknown";
1131cbf67842SDouglas Gilbert 			break;
1132cbf67842SDouglas Gilbert 		}
1133cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1134773642d9SDouglas Gilbert 		if (sdebug_verbose)
1135f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1136cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1137cbf67842SDouglas Gilbert 				   my_name, cp);
11381da177e4SLinus Torvalds 		return check_condition_result;
11391da177e4SLinus Torvalds 	}
11401da177e4SLinus Torvalds 	return 0;
11411da177e4SLinus Torvalds }
11421da177e4SLinus Torvalds 
1143fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11441da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11451da177e4SLinus Torvalds 				int arr_len)
11461da177e4SLinus Torvalds {
114721a61829SFUJITA Tomonori 	int act_len;
1148ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11491da177e4SLinus Torvalds 
1150072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11511da177e4SLinus Torvalds 		return 0;
1152ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1153773642d9SDouglas Gilbert 		return DID_ERROR << 16;
115421a61829SFUJITA Tomonori 
115521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
115621a61829SFUJITA Tomonori 				      arr, arr_len);
115742d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
115821a61829SFUJITA Tomonori 
11591da177e4SLinus Torvalds 	return 0;
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds 
1162fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1163fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1164fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1165fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1166fb0cc8d1SDouglas Gilbert  */
1167fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1168fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1169fb0cc8d1SDouglas Gilbert {
11709237f04eSDamien Le Moal 	unsigned int act_len, n;
1171ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1172fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1173fb0cc8d1SDouglas Gilbert 
1174fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1175fb0cc8d1SDouglas Gilbert 		return 0;
1176ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1177fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1178fb0cc8d1SDouglas Gilbert 
1179fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1180fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1181fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
118242d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
118342d387beSBart Van Assche 		 scsi_get_resid(scp));
11849237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
118587c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1186fb0cc8d1SDouglas Gilbert 	return 0;
1187fb0cc8d1SDouglas Gilbert }
1188fb0cc8d1SDouglas Gilbert 
1189fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1190fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1191fb0cc8d1SDouglas Gilbert  */
11921da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
119321a61829SFUJITA Tomonori 			       int arr_len)
11941da177e4SLinus Torvalds {
119521a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
11961da177e4SLinus Torvalds 		return 0;
1197ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
11981da177e4SLinus Torvalds 		return -1;
119921a61829SFUJITA Tomonori 
120021a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12011da177e4SLinus Torvalds }
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 
1204e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1205e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12069b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12071b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12081b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12091b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12101b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12111da177e4SLinus Torvalds 
1212cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1213760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12145a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
121509ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1216bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12171da177e4SLinus Torvalds {
1218c65b1445SDouglas Gilbert 	int num, port_a;
1219c65b1445SDouglas Gilbert 	char b[32];
12201da177e4SLinus Torvalds 
1221c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12221da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12231da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12241da177e4SLinus Torvalds 	arr[1] = 0x1;
12251da177e4SLinus Torvalds 	arr[2] = 0x0;
1226e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1227e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12281da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12291da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12301da177e4SLinus Torvalds 	arr[3] = num;
12311da177e4SLinus Torvalds 	num += 4;
1232c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
123309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
123409ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
123509ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
123609ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
123709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
123809ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
123909ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
124009ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124109ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
124209ba24c1SDouglas Gilbert 			num += 16;
124309ba24c1SDouglas Gilbert 		} else {
12441b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1245c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1246c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1247c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1248c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12491b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1250773642d9SDouglas Gilbert 			num += 8;
125109ba24c1SDouglas Gilbert 		}
1252c65b1445SDouglas Gilbert 		/* Target relative port number */
1253c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1254c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1255c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1256c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1257c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1258c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1259c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1260c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1261c65b1445SDouglas Gilbert 	}
12621b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1263c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1264c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1265c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1266c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12671b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1268773642d9SDouglas Gilbert 	num += 8;
12691b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12705a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12715a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12725a09e398SHannes Reinecke 	arr[num++] = 0x0;
12735a09e398SHannes Reinecke 	arr[num++] = 0x4;
12745a09e398SHannes Reinecke 	arr[num++] = 0;
12755a09e398SHannes Reinecke 	arr[num++] = 0;
1276773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1277773642d9SDouglas Gilbert 	num += 2;
12781b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1279c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1280c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1281c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1282c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12831b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1284773642d9SDouglas Gilbert 	num += 8;
1285c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1286c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1287c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1288c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1289c65b1445SDouglas Gilbert 	arr[num++] = 24;
12901b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1291c65b1445SDouglas Gilbert 	num += 12;
1292c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1293c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1294c65b1445SDouglas Gilbert 	num += 8;
1295c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1296c65b1445SDouglas Gilbert 	num += 4;
1297c65b1445SDouglas Gilbert 	return num;
1298c65b1445SDouglas Gilbert }
1299c65b1445SDouglas Gilbert 
1300c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1301c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1302c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1303c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1304c65b1445SDouglas Gilbert };
1305c65b1445SDouglas Gilbert 
1306cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1307760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1308c65b1445SDouglas Gilbert {
1309c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1310c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1311c65b1445SDouglas Gilbert }
1312c65b1445SDouglas Gilbert 
1313cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1314760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1315c65b1445SDouglas Gilbert {
1316c65b1445SDouglas Gilbert 	int num = 0;
1317c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1318c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1319c65b1445SDouglas Gilbert 	int plen, olen;
1320c65b1445SDouglas Gilbert 
1321c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1322c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1323c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1324c65b1445SDouglas Gilbert 	olen = strlen(na1);
1325c65b1445SDouglas Gilbert 	plen = olen + 1;
1326c65b1445SDouglas Gilbert 	if (plen % 4)
1327c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1328c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1329c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1330c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1331c65b1445SDouglas Gilbert 	num += plen;
1332c65b1445SDouglas Gilbert 
1333c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1334c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1335c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1336c65b1445SDouglas Gilbert 	olen = strlen(na2);
1337c65b1445SDouglas Gilbert 	plen = olen + 1;
1338c65b1445SDouglas Gilbert 	if (plen % 4)
1339c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1340c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1341c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1342c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1343c65b1445SDouglas Gilbert 	num += plen;
1344c65b1445SDouglas Gilbert 
1345c65b1445SDouglas Gilbert 	return num;
1346c65b1445SDouglas Gilbert }
1347c65b1445SDouglas Gilbert 
1348c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1349760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1350c65b1445SDouglas Gilbert {
1351c65b1445SDouglas Gilbert 	int num = 0;
1352c65b1445SDouglas Gilbert 	int port_a, port_b;
1353c65b1445SDouglas Gilbert 
1354c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1355c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1356c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1357c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1358c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1359c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1360c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1361c65b1445SDouglas Gilbert 	num += 6;
1362c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1363c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1364c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1365c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1366c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1367c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1368c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13691b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1370773642d9SDouglas Gilbert 	num += 8;
1371c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1372c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1374c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1375c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1376c65b1445SDouglas Gilbert 	num += 6;
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1378c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1379c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1380c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1381c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13841b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1385773642d9SDouglas Gilbert 	num += 8;
1386c65b1445SDouglas Gilbert 
1387c65b1445SDouglas Gilbert 	return num;
1388c65b1445SDouglas Gilbert }
1389c65b1445SDouglas Gilbert 
1390c65b1445SDouglas Gilbert 
1391c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1392c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1393c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1394c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1395c65b1445SDouglas Gilbert '1','2','3','4',
1396c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1397c65b1445SDouglas Gilbert 0xec,0,0,0,
1398c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1399c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1400c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1401c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1402c65b1445SDouglas Gilbert 0x53,0x41,
1403c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1404c65b1445SDouglas Gilbert 0x20,0x20,
1405c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1406c65b1445SDouglas Gilbert 0x10,0x80,
1407c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1408c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1409c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1410c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1411c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1412c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1413c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1414c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1415c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1416c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1417c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1418c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1419c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1420c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1421c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1422c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1423c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1424c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1425c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1426c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1428c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1429c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1430c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1433c65b1445SDouglas Gilbert };
1434c65b1445SDouglas Gilbert 
1435cbf67842SDouglas Gilbert /* ATA Information VPD page */
1436760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1437c65b1445SDouglas Gilbert {
1438c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1439c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1440c65b1445SDouglas Gilbert }
1441c65b1445SDouglas Gilbert 
1442c65b1445SDouglas Gilbert 
1443c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14441e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14451e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14461e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14471e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1448c65b1445SDouglas Gilbert };
1449c65b1445SDouglas Gilbert 
1450cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1451760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1452c65b1445SDouglas Gilbert {
1453ea61fca5SMartin K. Petersen 	unsigned int gran;
1454ea61fca5SMartin K. Petersen 
1455c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1456e308b3d1SMartin K. Petersen 
1457e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
145886e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
145986e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
146086e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
146186e6828aSLukas Herbolt 	else
1462773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1463773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1464e308b3d1SMartin K. Petersen 
1465e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1466773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1467773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
146844d92694SMartin K. Petersen 
1469e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1470773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1471e308b3d1SMartin K. Petersen 
1472773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1473e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1474773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1475e308b3d1SMartin K. Petersen 
1476e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1477773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
147844d92694SMartin K. Petersen 	}
147944d92694SMartin K. Petersen 
1480e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1481773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1482773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
148344d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
148444d92694SMartin K. Petersen 	}
148544d92694SMartin K. Petersen 
1486e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1487773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14886014759cSMartin K. Petersen 
14895b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1490773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
14915b94e232SMartin K. Petersen 
14925b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
149344d92694SMartin K. Petersen 
1494c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
14951da177e4SLinus Torvalds }
14961da177e4SLinus Torvalds 
14971e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
149864e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1499eac6e8e4SMatthew Wilcox {
1500eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1501eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15021e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15031e49f785SDouglas Gilbert 	arr[2] = 0;
15041e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
150564e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
150664e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1507eac6e8e4SMatthew Wilcox 
1508eac6e8e4SMatthew Wilcox 	return 0x3c;
1509eac6e8e4SMatthew Wilcox }
15101da177e4SLinus Torvalds 
1511760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1512760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15136014759cSMartin K. Petersen {
15143f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15156014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1516773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15176014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1518773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15196014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1520773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15215b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1522760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1523760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1524760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1525760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1526760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15273f0bc3b3SMartin K. Petersen 	return 0x4;
15286014759cSMartin K. Petersen }
15296014759cSMartin K. Petersen 
1530d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1531f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1532d36da305SDouglas Gilbert {
1533d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1534d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1535d36da305SDouglas Gilbert 	/*
1536d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1537d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1538f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1539f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1540d36da305SDouglas Gilbert 	 */
1541d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1542d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
154364e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1544f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1545f0d1cf93SDouglas Gilbert 	else
1546d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1547d36da305SDouglas Gilbert 	return 0x3c;
1548d36da305SDouglas Gilbert }
1549d36da305SDouglas Gilbert 
15501da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1551c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15521da177e4SLinus Torvalds 
1553c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15541da177e4SLinus Torvalds {
15551da177e4SLinus Torvalds 	unsigned char pq_pdt;
15565a09e398SHannes Reinecke 	unsigned char *arr;
155701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15585a09e398SHannes Reinecke 	int alloc_len, n, ret;
1559d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15601da177e4SLinus Torvalds 
1561773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15626f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15636f3cbf55SDouglas Gilbert 	if (! arr)
15646f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1565760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
156664e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1567d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1568b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1569c2248fc9SDouglas Gilbert 	if (have_wlun)
1570b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1571b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1572b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1573c65b1445SDouglas Gilbert 	else
1574773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15751da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15761da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
157722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15785a09e398SHannes Reinecke 		kfree(arr);
15791da177e4SLinus Torvalds 		return check_condition_result;
15801da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15815a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1582c65b1445SDouglas Gilbert 		char lu_id_str[6];
1583c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
15841da177e4SLinus Torvalds 
15855a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
15865a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1587b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
158823183910SDouglas Gilbert 			host_no = 0;
1589c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1590c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1591c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1592c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1593c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
15941da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1595c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1596c65b1445SDouglas Gilbert 			n = 4;
1597c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1598c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1599c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1600c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1601c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1602c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1603c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1604c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1605d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1606c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1607760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1608760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1609d36da305SDouglas Gilbert 				if (is_disk)
1610d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
161164e14eceSDamien Le Moal 				if (is_zbc)
1612d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1613760f3b03SDouglas Gilbert 			}
1614c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16151da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1616c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16171da177e4SLinus Torvalds 			arr[3] = len;
1618c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16191da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1620c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1621760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16225a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
162309ba24c1SDouglas Gilbert 						lu_id_str, len,
162409ba24c1SDouglas Gilbert 						&devip->lu_name);
1625c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1626c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1627760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1628c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1629c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1630760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1631c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1632c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1633c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16348475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1635c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1636760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1637c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1638c6a44287SMartin K. Petersen 			else
1639c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1640c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1641c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1642c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1643c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1644c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1645c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1646c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1647c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1648c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1649c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1650760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1651d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1652c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1653760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1654773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1655d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1656c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1657760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1658d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1659eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
166064e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1661760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16626014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1663760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1664d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1665d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1666f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16671da177e4SLinus Torvalds 		} else {
166822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16695a09e398SHannes Reinecke 			kfree(arr);
16701da177e4SLinus Torvalds 			return check_condition_result;
16711da177e4SLinus Torvalds 		}
1672773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
16735a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1674c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
16755a09e398SHannes Reinecke 		kfree(arr);
16765a09e398SHannes Reinecke 		return ret;
16771da177e4SLinus Torvalds 	}
16781da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1679773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1680773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16811da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16821da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1683f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1684b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
168570bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1686c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
16871da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1688c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1689e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1690e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1691e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
16929b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
16939b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
16941da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1695760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1696760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1697c65b1445SDouglas Gilbert 	n = 62;
1698760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1699760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1700760f3b03SDouglas Gilbert 		n += 2;
1701760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1702760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1703760f3b03SDouglas Gilbert 		n += 2;
1704d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1705d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1706d36da305SDouglas Gilbert 		n += 2;
17071da177e4SLinus Torvalds 	}
1708760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17095a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
171087c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
17115a09e398SHannes Reinecke 	kfree(arr);
17125a09e398SHannes Reinecke 	return ret;
17131da177e4SLinus Torvalds }
17141da177e4SLinus Torvalds 
171584905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1716fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1717fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1718fd32119bSDouglas Gilbert 
17191da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17201da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17211da177e4SLinus Torvalds {
172201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
172384905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
172484905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
172584905d34SDouglas Gilbert 	int alloc_len = cmd[4];
17261da177e4SLinus Torvalds 	int len = 18;
172784905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17281da177e4SLinus Torvalds 
1729c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
173084905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
173184905d34SDouglas Gilbert 		if (dsense) {
173284905d34SDouglas Gilbert 			arr[0] = 0x72;
173384905d34SDouglas Gilbert 			arr[1] = NOT_READY;
173484905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
173584905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
173684905d34SDouglas Gilbert 			len = 8;
173784905d34SDouglas Gilbert 		} else {
173884905d34SDouglas Gilbert 			arr[0] = 0x70;
173984905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
174084905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
174184905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
174284905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
174384905d34SDouglas Gilbert 		}
174484905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
174584905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1746c2248fc9SDouglas Gilbert 		if (dsense) {
1747c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1748c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1749c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
175084905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1751c2248fc9SDouglas Gilbert 			len = 8;
1752c65b1445SDouglas Gilbert 		} else {
1753c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1754c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1755c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1756c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
175784905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1758c65b1445SDouglas Gilbert 		}
175984905d34SDouglas Gilbert 	} else {	/* nothing to report */
1760c2248fc9SDouglas Gilbert 		if (dsense) {
1761c2248fc9SDouglas Gilbert 			len = 8;
176284905d34SDouglas Gilbert 			memset(arr, 0, len);
176384905d34SDouglas Gilbert 			arr[0] = 0x72;
1764c2248fc9SDouglas Gilbert 		} else {
176584905d34SDouglas Gilbert 			memset(arr, 0, len);
1766c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1767c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1768c2248fc9SDouglas Gilbert 		}
1769c65b1445SDouglas Gilbert 	}
177084905d34SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
17711da177e4SLinus Torvalds }
17721da177e4SLinus Torvalds 
1773c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1774c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1775c65b1445SDouglas Gilbert {
177601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1777c4837394SDouglas Gilbert 	int power_cond, stop;
17784f2c8bf6SDouglas Gilbert 	bool changing;
1779c65b1445SDouglas Gilbert 
1780c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1781c65b1445SDouglas Gilbert 	if (power_cond) {
178222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1783c65b1445SDouglas Gilbert 		return check_condition_result;
1784c65b1445SDouglas Gilbert 	}
1785c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
17864f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1787c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
17884f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
17894f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
17904f2c8bf6SDouglas Gilbert 	else
17914f2c8bf6SDouglas Gilbert 		return 0;
1792c65b1445SDouglas Gilbert }
1793c65b1445SDouglas Gilbert 
179428898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
179528898873SFUJITA Tomonori {
1796773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1797773642d9SDouglas Gilbert 
1798773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1799773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1800773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
180128898873SFUJITA Tomonori 	else
180228898873SFUJITA Tomonori 		return sdebug_store_sectors;
180328898873SFUJITA Tomonori }
180428898873SFUJITA Tomonori 
18051da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18061da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18071da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18081da177e4SLinus Torvalds {
18091da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1810c65b1445SDouglas Gilbert 	unsigned int capac;
18111da177e4SLinus Torvalds 
1812c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
181328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18141da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1815c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1816c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1817773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1818773642d9SDouglas Gilbert 	} else
1819773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1820773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18211da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18221da177e4SLinus Torvalds }
18231da177e4SLinus Torvalds 
1824c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1825c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1826c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1827c65b1445SDouglas Gilbert {
182801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1829c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1830773642d9SDouglas Gilbert 	int alloc_len;
1831c65b1445SDouglas Gilbert 
1832773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1833c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
183428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1835c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1836773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1837773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1838773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1839773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
184044d92694SMartin K. Petersen 
1841be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18425b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1843760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1844760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1845760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1846760f3b03SDouglas Gilbert 		 */
1847760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1848760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1849be1dd78dSEric Sandeen 	}
185044d92694SMartin K. Petersen 
1851773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1852c6a44287SMartin K. Petersen 
1853760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1854773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1855c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1856c6a44287SMartin K. Petersen 	}
1857c6a44287SMartin K. Petersen 
1858c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
185987c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1860c65b1445SDouglas Gilbert }
1861c65b1445SDouglas Gilbert 
18625a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18635a09e398SHannes Reinecke 
18645a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18655a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18665a09e398SHannes Reinecke {
186701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
18685a09e398SHannes Reinecke 	unsigned char *arr;
18695a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
18705a09e398SHannes Reinecke 	int n, ret, alen, rlen;
18715a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
18725a09e398SHannes Reinecke 
1873773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
18746f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
18756f3cbf55SDouglas Gilbert 	if (! arr)
18766f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
18775a09e398SHannes Reinecke 	/*
18785a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
18795a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
18805a09e398SHannes Reinecke 	 * So we create two port groups with one port each
18815a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
18825a09e398SHannes Reinecke 	 */
18835a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
18845a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
18855a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
18865a09e398SHannes Reinecke 			(devip->channel & 0x7f);
18875a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
18885a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
18895a09e398SHannes Reinecke 
18905a09e398SHannes Reinecke 	/*
18915a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
18925a09e398SHannes Reinecke 	 */
18935a09e398SHannes Reinecke 	n = 4;
1894b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
18955a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
18965a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
18975a09e398SHannes Reinecke 	} else {
18985a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1899773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19005a09e398SHannes Reinecke 	}
1901773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1902773642d9SDouglas Gilbert 	n += 2;
19035a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19045a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19055a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19065a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19075a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19085a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1909773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1910773642d9SDouglas Gilbert 	n += 2;
19115a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19125a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1913773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1914773642d9SDouglas Gilbert 	n += 2;
19155a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19165a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19175a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19185a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19195a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19205a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1921773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1922773642d9SDouglas Gilbert 	n += 2;
19235a09e398SHannes Reinecke 
19245a09e398SHannes Reinecke 	rlen = n - 4;
1925773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19265a09e398SHannes Reinecke 
19275a09e398SHannes Reinecke 	/*
19285a09e398SHannes Reinecke 	 * Return the smallest value of either
19295a09e398SHannes Reinecke 	 * - The allocated length
19305a09e398SHannes Reinecke 	 * - The constructed command length
19315a09e398SHannes Reinecke 	 * - The maximum array size
19325a09e398SHannes Reinecke 	 */
193387c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
19345a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
193587c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19365a09e398SHannes Reinecke 	kfree(arr);
19375a09e398SHannes Reinecke 	return ret;
19385a09e398SHannes Reinecke }
19395a09e398SHannes Reinecke 
1940fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1941fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
194238d5c833SDouglas Gilbert {
194338d5c833SDouglas Gilbert 	bool rctd;
194438d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
194538d5c833SDouglas Gilbert 	u16 req_sa, u;
194638d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
194738d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
194838d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
194938d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
195038d5c833SDouglas Gilbert 	u8 *arr;
195138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
195238d5c833SDouglas Gilbert 
195338d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
195438d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
195538d5c833SDouglas Gilbert 	req_opcode = cmd[3];
195638d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
195738d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19586d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
195938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
196038d5c833SDouglas Gilbert 		return check_condition_result;
196138d5c833SDouglas Gilbert 	}
196238d5c833SDouglas Gilbert 	if (alloc_len > 8192)
196338d5c833SDouglas Gilbert 		a_len = 8192;
196438d5c833SDouglas Gilbert 	else
196538d5c833SDouglas Gilbert 		a_len = alloc_len;
196699531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
196738d5c833SDouglas Gilbert 	if (NULL == arr) {
196838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
196938d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
197038d5c833SDouglas Gilbert 		return check_condition_result;
197138d5c833SDouglas Gilbert 	}
197238d5c833SDouglas Gilbert 	switch (reporting_opts) {
197338d5c833SDouglas Gilbert 	case 0:	/* all commands */
197438d5c833SDouglas Gilbert 		/* count number of commands */
197538d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
197638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
197738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
197838d5c833SDouglas Gilbert 				continue;
197938d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
198038d5c833SDouglas Gilbert 		}
198138d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
198238d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
198338d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
198438d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
198538d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
198638d5c833SDouglas Gilbert 				continue;
198738d5c833SDouglas Gilbert 			na = oip->num_attached;
198838d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
198938d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
199038d5c833SDouglas Gilbert 			if (rctd)
199138d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
199238d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
199338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
199438d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
199538d5c833SDouglas Gilbert 			if (rctd)
199638d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
199738d5c833SDouglas Gilbert 			r_oip = oip;
199838d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
199938d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
200038d5c833SDouglas Gilbert 					continue;
200138d5c833SDouglas Gilbert 				offset += bump;
200238d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
200338d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
200438d5c833SDouglas Gilbert 				if (rctd)
200538d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
200638d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
200738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
200838d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
200938d5c833SDouglas Gilbert 						   arr + offset + 6);
201038d5c833SDouglas Gilbert 				if (rctd)
201138d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
201238d5c833SDouglas Gilbert 							   arr + offset + 8);
201338d5c833SDouglas Gilbert 			}
201438d5c833SDouglas Gilbert 			oip = r_oip;
201538d5c833SDouglas Gilbert 			offset += bump;
201638d5c833SDouglas Gilbert 		}
201738d5c833SDouglas Gilbert 		break;
201838d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
201938d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
202038d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
202138d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
202238d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
202338d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
202438d5c833SDouglas Gilbert 			supp = 1;
202538d5c833SDouglas Gilbert 			offset = 4;
202638d5c833SDouglas Gilbert 		} else {
202738d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
202838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
202938d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
203038d5c833SDouglas Gilbert 							     2, 2);
203138d5c833SDouglas Gilbert 					kfree(arr);
203238d5c833SDouglas Gilbert 					return check_condition_result;
203338d5c833SDouglas Gilbert 				}
203438d5c833SDouglas Gilbert 				req_sa = 0;
203538d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
203638d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
203738d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
203838d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
203938d5c833SDouglas Gilbert 				return check_condition_result;
204038d5c833SDouglas Gilbert 			}
204138d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
204238d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
204338d5c833SDouglas Gilbert 				supp = 3;
204438d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
204538d5c833SDouglas Gilbert 				na = oip->num_attached;
204638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
204738d5c833SDouglas Gilbert 				     ++k, ++oip) {
204838d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
204938d5c833SDouglas Gilbert 						break;
205038d5c833SDouglas Gilbert 				}
205138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
205238d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
205338d5c833SDouglas Gilbert 				na = oip->num_attached;
205438d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
205538d5c833SDouglas Gilbert 				     ++k, ++oip) {
205638d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
205738d5c833SDouglas Gilbert 						break;
205838d5c833SDouglas Gilbert 				}
205938d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
206038d5c833SDouglas Gilbert 			} else
206138d5c833SDouglas Gilbert 				supp = 3;
206238d5c833SDouglas Gilbert 			if (3 == supp) {
206338d5c833SDouglas Gilbert 				u = oip->len_mask[0];
206438d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
206538d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
206638d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
206738d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
206838d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
206938d5c833SDouglas Gilbert 				offset = 4 + u;
207038d5c833SDouglas Gilbert 			} else
207138d5c833SDouglas Gilbert 				offset = 4;
207238d5c833SDouglas Gilbert 		}
207338d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
207438d5c833SDouglas Gilbert 		if (rctd) {
207538d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
207638d5c833SDouglas Gilbert 			offset += 12;
207738d5c833SDouglas Gilbert 		}
207838d5c833SDouglas Gilbert 		break;
207938d5c833SDouglas Gilbert 	default:
208038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
208138d5c833SDouglas Gilbert 		kfree(arr);
208238d5c833SDouglas Gilbert 		return check_condition_result;
208338d5c833SDouglas Gilbert 	}
208438d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
208538d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
208638d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
208738d5c833SDouglas Gilbert 	kfree(arr);
208838d5c833SDouglas Gilbert 	return errsts;
208938d5c833SDouglas Gilbert }
209038d5c833SDouglas Gilbert 
2091fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2092fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
209338d5c833SDouglas Gilbert {
209438d5c833SDouglas Gilbert 	bool repd;
209538d5c833SDouglas Gilbert 	u32 alloc_len, len;
209638d5c833SDouglas Gilbert 	u8 arr[16];
209738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
209838d5c833SDouglas Gilbert 
209938d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
210038d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
210138d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
210238d5c833SDouglas Gilbert 	if (alloc_len < 4) {
210338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
210438d5c833SDouglas Gilbert 		return check_condition_result;
210538d5c833SDouglas Gilbert 	}
210638d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
210738d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
210838d5c833SDouglas Gilbert 	if (repd) {
210938d5c833SDouglas Gilbert 		arr[3] = 0xc;
211038d5c833SDouglas Gilbert 		len = 16;
211138d5c833SDouglas Gilbert 	} else
211238d5c833SDouglas Gilbert 		len = 4;
211338d5c833SDouglas Gilbert 
211438d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
211538d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
211638d5c833SDouglas Gilbert }
211738d5c833SDouglas Gilbert 
21181da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21191da177e4SLinus Torvalds 
21201da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21211da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21221da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21231da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21241da177e4SLinus Torvalds 
21251da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21261da177e4SLinus Torvalds 	if (1 == pcontrol)
21271da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21281da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21291da177e4SLinus Torvalds }
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21321da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21331da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21341da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21351da177e4SLinus Torvalds 
21361da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21371da177e4SLinus Torvalds 	if (1 == pcontrol)
21381da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21391da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21401da177e4SLinus Torvalds }
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21431da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21441da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21451da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21461da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2149773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2150773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2151773642d9SDouglas Gilbert 	if (sdebug_removable)
21521da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21531da177e4SLinus Torvalds 	if (1 == pcontrol)
21541da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21551da177e4SLinus Torvalds 	return sizeof(format_pg);
21561da177e4SLinus Torvalds }
21571da177e4SLinus Torvalds 
2158fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2159fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2160fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2161fd32119bSDouglas Gilbert 
21621da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21631da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2164cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2165cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2166cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21671da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
21681da177e4SLinus Torvalds 
2169773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2170cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
21711da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
21721da177e4SLinus Torvalds 	if (1 == pcontrol)
2173cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2174cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2175cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
21761da177e4SLinus Torvalds 	return sizeof(caching_pg);
21771da177e4SLinus Torvalds }
21781da177e4SLinus Torvalds 
2179fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2180fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2181fd32119bSDouglas Gilbert 
21821da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
21831da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2184c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2185c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2186c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
21871da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
21881da177e4SLinus Torvalds 
2189773642d9SDouglas Gilbert 	if (sdebug_dsense)
21901da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2191c65b1445SDouglas Gilbert 	else
2192c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2193c6a44287SMartin K. Petersen 
2194773642d9SDouglas Gilbert 	if (sdebug_ato)
2195c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2196c6a44287SMartin K. Petersen 
21971da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
21981da177e4SLinus Torvalds 	if (1 == pcontrol)
2199c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2200c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2201c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22021da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22031da177e4SLinus Torvalds }
22041da177e4SLinus Torvalds 
2205c65b1445SDouglas Gilbert 
22061da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22071da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2208c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22091da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2210c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2211c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2212c65b1445SDouglas Gilbert 
22131da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22141da177e4SLinus Torvalds 	if (1 == pcontrol)
2215c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2216c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2217c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22181da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22191da177e4SLinus Torvalds }
22201da177e4SLinus Torvalds 
2221c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2222c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2223c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2224c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2225c65b1445SDouglas Gilbert 
2226c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2227c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2228c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2229c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2230c65b1445SDouglas Gilbert }
2231c65b1445SDouglas Gilbert 
2232c65b1445SDouglas Gilbert 
2233c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2234c65b1445SDouglas Gilbert 			      int target_dev_id)
2235c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2236c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2237c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2238773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2239773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2240c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2241c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2242c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2243c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2244773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2245773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2246c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2247c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2248c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2249c65b1445SDouglas Gilbert 		};
2250c65b1445SDouglas Gilbert 	int port_a, port_b;
2251c65b1445SDouglas Gilbert 
22521b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22531b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22541b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22551b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2256c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2257c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2258c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2259773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2260773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2261c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2262c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2263c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2264c65b1445SDouglas Gilbert }
2265c65b1445SDouglas Gilbert 
2266c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2267c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2268c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2269c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2270c65b1445SDouglas Gilbert 		};
2271c65b1445SDouglas Gilbert 
2272c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2273c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2274c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2275c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2276c65b1445SDouglas Gilbert }
2277c65b1445SDouglas Gilbert 
22781da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
22791da177e4SLinus Torvalds 
2280fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2281fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
22821da177e4SLinus Torvalds {
228323183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
22841da177e4SLinus Torvalds 	unsigned char dev_spec;
2285760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2286c2248fc9SDouglas Gilbert 	int target = scp->device->id;
22871da177e4SLinus Torvalds 	unsigned char *ap;
22881da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
228901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2290d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
22911da177e4SLinus Torvalds 
2292760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
22931da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
22941da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
22951da177e4SLinus Torvalds 	subpcode = cmd[3];
22961da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2297760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2298760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
229964e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2300d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
230123183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
230223183910SDouglas Gilbert 	else
230323183910SDouglas Gilbert 		bd_len = 0;
2304773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23051da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23061da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2307cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23081da177e4SLinus Torvalds 		return check_condition_result;
23091da177e4SLinus Torvalds 	}
2310c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2311c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2312d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2313d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2314b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23159447b6ceSMartin K. Petersen 		if (sdebug_wp)
23169447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23179447b6ceSMartin K. Petersen 	} else
231823183910SDouglas Gilbert 		dev_spec = 0x0;
23191da177e4SLinus Torvalds 	if (msense_6) {
23201da177e4SLinus Torvalds 		arr[2] = dev_spec;
232123183910SDouglas Gilbert 		arr[3] = bd_len;
23221da177e4SLinus Torvalds 		offset = 4;
23231da177e4SLinus Torvalds 	} else {
23241da177e4SLinus Torvalds 		arr[3] = dev_spec;
232523183910SDouglas Gilbert 		if (16 == bd_len)
232623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
232723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23281da177e4SLinus Torvalds 		offset = 8;
23291da177e4SLinus Torvalds 	}
23301da177e4SLinus Torvalds 	ap = arr + offset;
233128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
233228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
233328898873SFUJITA Tomonori 
233423183910SDouglas Gilbert 	if (8 == bd_len) {
2335773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2336773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2337773642d9SDouglas Gilbert 		else
2338773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2339773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
234023183910SDouglas Gilbert 		offset += bd_len;
234123183910SDouglas Gilbert 		ap = arr + offset;
234223183910SDouglas Gilbert 	} else if (16 == bd_len) {
2343773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2344773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
234523183910SDouglas Gilbert 		offset += bd_len;
234623183910SDouglas Gilbert 		ap = arr + offset;
234723183910SDouglas Gilbert 	}
23481da177e4SLinus Torvalds 
2349c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2350c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
235122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23521da177e4SLinus Torvalds 		return check_condition_result;
23531da177e4SLinus Torvalds 	}
2354760f3b03SDouglas Gilbert 	bad_pcode = false;
2355760f3b03SDouglas Gilbert 
23561da177e4SLinus Torvalds 	switch (pcode) {
23571da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23581da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23591da177e4SLinus Torvalds 		offset += len;
23601da177e4SLinus Torvalds 		break;
23611da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23621da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23631da177e4SLinus Torvalds 		offset += len;
23641da177e4SLinus Torvalds 		break;
23651da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2366760f3b03SDouglas Gilbert 		if (is_disk) {
23671da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
23681da177e4SLinus Torvalds 			offset += len;
2369760f3b03SDouglas Gilbert 		} else
2370760f3b03SDouglas Gilbert 			bad_pcode = true;
23711da177e4SLinus Torvalds 		break;
23721da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2373d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
23741da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
23751da177e4SLinus Torvalds 			offset += len;
2376760f3b03SDouglas Gilbert 		} else
2377760f3b03SDouglas Gilbert 			bad_pcode = true;
23781da177e4SLinus Torvalds 		break;
23791da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
23801da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
23811da177e4SLinus Torvalds 		offset += len;
23821da177e4SLinus Torvalds 		break;
2383c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2384c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
238522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2386c65b1445SDouglas Gilbert 			return check_condition_result;
2387c65b1445SDouglas Gilbert 		}
2388c65b1445SDouglas Gilbert 		len = 0;
2389c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2390c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2391c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2392c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2393c65b1445SDouglas Gilbert 						  target_dev_id);
2394c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2395c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2396c65b1445SDouglas Gilbert 		offset += len;
2397c65b1445SDouglas Gilbert 		break;
23981da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
23991da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24001da177e4SLinus Torvalds 		offset += len;
24011da177e4SLinus Torvalds 		break;
24021da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2403c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24041da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24051da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2406760f3b03SDouglas Gilbert 			if (is_disk) {
2407760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2408760f3b03SDouglas Gilbert 						      target);
2409760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2410760f3b03SDouglas Gilbert 						       target);
2411d36da305SDouglas Gilbert 			} else if (is_zbc) {
2412d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2413d36da305SDouglas Gilbert 						       target);
2414760f3b03SDouglas Gilbert 			}
24151da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2416c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2417c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2418c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2419c65b1445SDouglas Gilbert 						  target, target_dev_id);
2420c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2421c65b1445SDouglas Gilbert 			}
24221da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2423760f3b03SDouglas Gilbert 			offset += len;
2424c65b1445SDouglas Gilbert 		} else {
242522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2426c65b1445SDouglas Gilbert 			return check_condition_result;
2427c65b1445SDouglas Gilbert 		}
24281da177e4SLinus Torvalds 		break;
24291da177e4SLinus Torvalds 	default:
2430760f3b03SDouglas Gilbert 		bad_pcode = true;
2431760f3b03SDouglas Gilbert 		break;
2432760f3b03SDouglas Gilbert 	}
2433760f3b03SDouglas Gilbert 	if (bad_pcode) {
243422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24351da177e4SLinus Torvalds 		return check_condition_result;
24361da177e4SLinus Torvalds 	}
24371da177e4SLinus Torvalds 	if (msense_6)
24381da177e4SLinus Torvalds 		arr[0] = offset - 1;
2439773642d9SDouglas Gilbert 	else
2440773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
244187c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24421da177e4SLinus Torvalds }
24431da177e4SLinus Torvalds 
2444c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2445c65b1445SDouglas Gilbert 
2446fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2447fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2448c65b1445SDouglas Gilbert {
2449c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2450c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2451c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
245201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2453c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2454c65b1445SDouglas Gilbert 
2455c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2456c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2457c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2458773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2459c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
246022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2461c65b1445SDouglas Gilbert 		return check_condition_result;
2462c65b1445SDouglas Gilbert 	}
2463c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2464c65b1445SDouglas Gilbert 	if (-1 == res)
2465773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2466773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2467cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2468cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2469cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2470773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2471773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
247223183910SDouglas Gilbert 	if (md_len > 2) {
247322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2474c65b1445SDouglas Gilbert 		return check_condition_result;
2475c65b1445SDouglas Gilbert 	}
2476c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2477c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2478c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2479c65b1445SDouglas Gilbert 	if (ps) {
248022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2481c65b1445SDouglas Gilbert 		return check_condition_result;
2482c65b1445SDouglas Gilbert 	}
2483c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2484773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2485c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2486c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2487cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2488c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2489c65b1445SDouglas Gilbert 		return check_condition_result;
2490c65b1445SDouglas Gilbert 	}
2491c65b1445SDouglas Gilbert 	switch (mpage) {
2492cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2493cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2494cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2495cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2496cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2497cbf67842SDouglas Gilbert 		}
2498cbf67842SDouglas Gilbert 		break;
2499c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2500c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2501c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2502c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25039447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25049447b6ceSMartin K. Petersen 				sdebug_wp = true;
25059447b6ceSMartin K. Petersen 			else
25069447b6ceSMartin K. Petersen 				sdebug_wp = false;
2507773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2508cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2509c65b1445SDouglas Gilbert 		}
2510c65b1445SDouglas Gilbert 		break;
2511c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2512c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2513c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2514c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2515cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2516c65b1445SDouglas Gilbert 		}
2517c65b1445SDouglas Gilbert 		break;
2518c65b1445SDouglas Gilbert 	default:
2519c65b1445SDouglas Gilbert 		break;
2520c65b1445SDouglas Gilbert 	}
252122017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2522c65b1445SDouglas Gilbert 	return check_condition_result;
2523cbf67842SDouglas Gilbert set_mode_changed_ua:
2524cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2525cbf67842SDouglas Gilbert 	return 0;
2526c65b1445SDouglas Gilbert }
2527c65b1445SDouglas Gilbert 
2528c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2529c65b1445SDouglas Gilbert {
2530c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2531c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2532c65b1445SDouglas Gilbert 		};
2533c65b1445SDouglas Gilbert 
2534c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2535c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2536c65b1445SDouglas Gilbert }
2537c65b1445SDouglas Gilbert 
2538c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2539c65b1445SDouglas Gilbert {
2540c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2541c65b1445SDouglas Gilbert 		};
2542c65b1445SDouglas Gilbert 
2543c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2544c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2545c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2546c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2547c65b1445SDouglas Gilbert 	}
2548c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2549c65b1445SDouglas Gilbert }
2550c65b1445SDouglas Gilbert 
2551c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2552c65b1445SDouglas Gilbert 
2553c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2554c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2555c65b1445SDouglas Gilbert {
2556ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2557c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
255801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2559c65b1445SDouglas Gilbert 
2560c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2561c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2562c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2563c65b1445SDouglas Gilbert 	if (ppc || sp) {
256422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2565c65b1445SDouglas Gilbert 		return check_condition_result;
2566c65b1445SDouglas Gilbert 	}
2567c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
256823183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2569773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2570c65b1445SDouglas Gilbert 	arr[0] = pcode;
257123183910SDouglas Gilbert 	if (0 == subpcode) {
2572c65b1445SDouglas Gilbert 		switch (pcode) {
2573c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2574c65b1445SDouglas Gilbert 			n = 4;
2575c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2576c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2577c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2578c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2579c65b1445SDouglas Gilbert 			break;
2580c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2581c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2582c65b1445SDouglas Gilbert 			break;
2583c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2584c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2585c65b1445SDouglas Gilbert 			break;
2586c65b1445SDouglas Gilbert 		default:
258722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2588c65b1445SDouglas Gilbert 			return check_condition_result;
2589c65b1445SDouglas Gilbert 		}
259023183910SDouglas Gilbert 	} else if (0xff == subpcode) {
259123183910SDouglas Gilbert 		arr[0] |= 0x40;
259223183910SDouglas Gilbert 		arr[1] = subpcode;
259323183910SDouglas Gilbert 		switch (pcode) {
259423183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
259523183910SDouglas Gilbert 			n = 4;
259623183910SDouglas Gilbert 			arr[n++] = 0x0;
259723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
259823183910SDouglas Gilbert 			arr[n++] = 0x0;
259923183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
260023183910SDouglas Gilbert 			arr[n++] = 0xd;
260123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
260223183910SDouglas Gilbert 			arr[n++] = 0x2f;
260323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
260423183910SDouglas Gilbert 			arr[3] = n - 4;
260523183910SDouglas Gilbert 			break;
260623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
260723183910SDouglas Gilbert 			n = 4;
260823183910SDouglas Gilbert 			arr[n++] = 0xd;
260923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
261023183910SDouglas Gilbert 			arr[3] = n - 4;
261123183910SDouglas Gilbert 			break;
261223183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
261323183910SDouglas Gilbert 			n = 4;
261423183910SDouglas Gilbert 			arr[n++] = 0x2f;
261523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
261623183910SDouglas Gilbert 			arr[3] = n - 4;
261723183910SDouglas Gilbert 			break;
261823183910SDouglas Gilbert 		default:
261922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
262023183910SDouglas Gilbert 			return check_condition_result;
262123183910SDouglas Gilbert 		}
262223183910SDouglas Gilbert 	} else {
262322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
262423183910SDouglas Gilbert 		return check_condition_result;
262523183910SDouglas Gilbert 	}
262687c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2627c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
262887c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2629c65b1445SDouglas Gilbert }
2630c65b1445SDouglas Gilbert 
2631f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2632f0d1cf93SDouglas Gilbert {
2633f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2634f0d1cf93SDouglas Gilbert }
2635f0d1cf93SDouglas Gilbert 
2636f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2637f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2638f0d1cf93SDouglas Gilbert {
2639108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2640f0d1cf93SDouglas Gilbert }
2641f0d1cf93SDouglas Gilbert 
2642f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2643f0d1cf93SDouglas Gilbert {
264464e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2645f0d1cf93SDouglas Gilbert }
2646f0d1cf93SDouglas Gilbert 
2647f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2648f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2649f0d1cf93SDouglas Gilbert {
2650f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2651f0d1cf93SDouglas Gilbert 
2652f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2653f0d1cf93SDouglas Gilbert 		return;
2654f0d1cf93SDouglas Gilbert 
2655f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2656f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2657f0d1cf93SDouglas Gilbert 		return;
2658f0d1cf93SDouglas Gilbert 
2659f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2660f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2661f0d1cf93SDouglas Gilbert 	else
2662f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2663f0d1cf93SDouglas Gilbert 
2664f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2665f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2666f0d1cf93SDouglas Gilbert 	} else {
2667f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2668f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2669f0d1cf93SDouglas Gilbert 	}
2670f0d1cf93SDouglas Gilbert }
2671f0d1cf93SDouglas Gilbert 
2672f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2673f0d1cf93SDouglas Gilbert {
2674f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2675f0d1cf93SDouglas Gilbert 	unsigned int i;
2676f0d1cf93SDouglas Gilbert 
2677f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2678f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2679f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2680f0d1cf93SDouglas Gilbert 			return;
2681f0d1cf93SDouglas Gilbert 		}
2682f0d1cf93SDouglas Gilbert 	}
2683f0d1cf93SDouglas Gilbert }
2684f0d1cf93SDouglas Gilbert 
2685f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2686f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2687f0d1cf93SDouglas Gilbert {
2688f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2689f0d1cf93SDouglas Gilbert 
2690f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2691f0d1cf93SDouglas Gilbert 		return;
2692f0d1cf93SDouglas Gilbert 
2693f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2694f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2695f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2696f0d1cf93SDouglas Gilbert 		return;
2697f0d1cf93SDouglas Gilbert 
2698f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2699f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2700f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2701f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2702f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2703f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2704f0d1cf93SDouglas Gilbert 
2705f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2706f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2707f0d1cf93SDouglas Gilbert 	if (explicit) {
2708f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2709f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2710f0d1cf93SDouglas Gilbert 	} else {
2711f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2712f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2713f0d1cf93SDouglas Gilbert 	}
2714f0d1cf93SDouglas Gilbert }
2715f0d1cf93SDouglas Gilbert 
2716f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2717f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2718f0d1cf93SDouglas Gilbert {
2719f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
272064e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2721f0d1cf93SDouglas Gilbert 
2722f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2723f0d1cf93SDouglas Gilbert 		return;
2724f0d1cf93SDouglas Gilbert 
272564e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2726f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
272764e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2728f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
272964e14eceSDamien Le Moal 		return;
273064e14eceSDamien Le Moal 	}
273164e14eceSDamien Le Moal 
273264e14eceSDamien Le Moal 	while (num) {
273364e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
273464e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
273564e14eceSDamien Le Moal 
273664e14eceSDamien Le Moal 		end = lba + num;
273764e14eceSDamien Le Moal 		if (end >= zend) {
273864e14eceSDamien Le Moal 			n = zend - lba;
273964e14eceSDamien Le Moal 			zsp->z_wp = zend;
274064e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
274164e14eceSDamien Le Moal 			n = num;
274264e14eceSDamien Le Moal 			zsp->z_wp = end;
274364e14eceSDamien Le Moal 		} else {
274464e14eceSDamien Le Moal 			n = num;
274564e14eceSDamien Le Moal 		}
274664e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
274764e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
274864e14eceSDamien Le Moal 
274964e14eceSDamien Le Moal 		num -= n;
275064e14eceSDamien Le Moal 		lba += n;
275164e14eceSDamien Le Moal 		if (num) {
275264e14eceSDamien Le Moal 			zsp++;
275364e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
275464e14eceSDamien Le Moal 		}
275564e14eceSDamien Le Moal 	}
2756f0d1cf93SDouglas Gilbert }
2757f0d1cf93SDouglas Gilbert 
2758f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27599447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27601da177e4SLinus Torvalds {
2761f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2762f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2763f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2764f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2765f0d1cf93SDouglas Gilbert 
2766f0d1cf93SDouglas Gilbert 	if (!write) {
276764e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
276864e14eceSDamien Le Moal 			return 0;
276964e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2770f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2771f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2772f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2773f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2774f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2775f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2776f0d1cf93SDouglas Gilbert 			return check_condition_result;
2777f0d1cf93SDouglas Gilbert 		}
2778f0d1cf93SDouglas Gilbert 		return 0;
2779f0d1cf93SDouglas Gilbert 	}
2780f0d1cf93SDouglas Gilbert 
2781f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2782f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2783f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2784f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2785f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2786f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2787f0d1cf93SDouglas Gilbert 			return check_condition_result;
2788f0d1cf93SDouglas Gilbert 		}
2789f0d1cf93SDouglas Gilbert 		return 0;
2790f0d1cf93SDouglas Gilbert 	}
2791f0d1cf93SDouglas Gilbert 
279264e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2793f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2794f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2795f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2796f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2797f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2798f0d1cf93SDouglas Gilbert 			return check_condition_result;
2799f0d1cf93SDouglas Gilbert 		}
2800f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2801f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2802f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2803f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2804f0d1cf93SDouglas Gilbert 			return check_condition_result;
2805f0d1cf93SDouglas Gilbert 		}
2806f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2807f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2808f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2809f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2810f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2811f0d1cf93SDouglas Gilbert 			return check_condition_result;
2812f0d1cf93SDouglas Gilbert 		}
281364e14eceSDamien Le Moal 	}
2814f0d1cf93SDouglas Gilbert 
2815f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2816f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2817f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2818f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2819f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2820f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2821f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2822f0d1cf93SDouglas Gilbert 			return check_condition_result;
2823f0d1cf93SDouglas Gilbert 		}
2824f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2825f0d1cf93SDouglas Gilbert 	}
2826f0d1cf93SDouglas Gilbert 
2827f0d1cf93SDouglas Gilbert 	return 0;
2828f0d1cf93SDouglas Gilbert }
2829f0d1cf93SDouglas Gilbert 
2830f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2831f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2832f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2833f0d1cf93SDouglas Gilbert {
2834f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2835f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2836f0d1cf93SDouglas Gilbert 
2837c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
283822017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28391da177e4SLinus Torvalds 		return check_condition_result;
28401da177e4SLinus Torvalds 	}
2841c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2842c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
284322017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2844cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2845c65b1445SDouglas Gilbert 		return check_condition_result;
2846c65b1445SDouglas Gilbert 	}
28479447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28489447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28499447b6ceSMartin K. Petersen 		return check_condition_result;
28509447b6ceSMartin K. Petersen 	}
2851f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2852f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2853f0d1cf93SDouglas Gilbert 
285419789100SFUJITA Tomonori 	return 0;
285519789100SFUJITA Tomonori }
285619789100SFUJITA Tomonori 
2857b6ff8ca7SDouglas Gilbert /*
2858b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2859b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2860b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2861b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2862b6ff8ca7SDouglas Gilbert  */
2863b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2864b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
286587c715dcSDouglas Gilbert {
2866b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2867b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2868b6ff8ca7SDouglas Gilbert 		return NULL;
2869b6ff8ca7SDouglas Gilbert 	}
2870b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
287187c715dcSDouglas Gilbert }
287287c715dcSDouglas Gilbert 
2873a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
287487c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
287587c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
287619789100SFUJITA Tomonori {
287719789100SFUJITA Tomonori 	int ret;
2878c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2879a4517511SAkinobu Mita 	enum dma_data_direction dir;
288087c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
288187c715dcSDouglas Gilbert 	u8 *fsp;
288219789100SFUJITA Tomonori 
2883c2248fc9SDouglas Gilbert 	if (do_write) {
2884a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
28854f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2886a4517511SAkinobu Mita 	} else {
2887a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2888a4517511SAkinobu Mita 	}
2889a4517511SAkinobu Mita 
289087c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2891a4517511SAkinobu Mita 		return 0;
289287c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2893a4517511SAkinobu Mita 		return -1;
289487c715dcSDouglas Gilbert 	fsp = sip->storep;
289519789100SFUJITA Tomonori 
289619789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
289719789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
289819789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
289919789100SFUJITA Tomonori 
2900386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
290187c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29020a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2903773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2904a4517511SAkinobu Mita 		return ret;
2905a4517511SAkinobu Mita 
2906a4517511SAkinobu Mita 	if (rest) {
2907386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
290887c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29090a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29100a7e69c7SDouglas Gilbert 			    do_write);
2911a4517511SAkinobu Mita 	}
291219789100SFUJITA Tomonori 
291319789100SFUJITA Tomonori 	return ret;
291419789100SFUJITA Tomonori }
291519789100SFUJITA Tomonori 
291687c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
291787c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
291887c715dcSDouglas Gilbert {
291987c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
292087c715dcSDouglas Gilbert 
292187c715dcSDouglas Gilbert 	if (!sdb->length)
292287c715dcSDouglas Gilbert 		return 0;
292387c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
292487c715dcSDouglas Gilbert 		return -1;
292587c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
292687c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
292787c715dcSDouglas Gilbert }
292887c715dcSDouglas Gilbert 
292987c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
293087c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
293138d5c833SDouglas Gilbert  * return false. */
293287c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2933c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
293438d5c833SDouglas Gilbert {
293538d5c833SDouglas Gilbert 	bool res;
293638d5c833SDouglas Gilbert 	u64 block, rest = 0;
293738d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2938773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
293987c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
294038d5c833SDouglas Gilbert 
294138d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
294238d5c833SDouglas Gilbert 	if (block + num > store_blks)
294338d5c833SDouglas Gilbert 		rest = block + num - store_blks;
294438d5c833SDouglas Gilbert 
294587c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
294638d5c833SDouglas Gilbert 	if (!res)
294738d5c833SDouglas Gilbert 		return res;
294838d5c833SDouglas Gilbert 	if (rest)
294987c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
295038d5c833SDouglas Gilbert 			     rest * lb_size);
295138d5c833SDouglas Gilbert 	if (!res)
295238d5c833SDouglas Gilbert 		return res;
2953c3e2fe92SDouglas Gilbert 	if (compare_only)
2954c3e2fe92SDouglas Gilbert 		return true;
295538d5c833SDouglas Gilbert 	arr += num * lb_size;
295687c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
295738d5c833SDouglas Gilbert 	if (rest)
295887c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
295938d5c833SDouglas Gilbert 	return res;
296038d5c833SDouglas Gilbert }
296138d5c833SDouglas Gilbert 
296251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2963beb40ea4SAkinobu Mita {
296451d648afSAkinobu Mita 	__be16 csum;
2965beb40ea4SAkinobu Mita 
2966773642d9SDouglas Gilbert 	if (sdebug_guard)
296751d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
296851d648afSAkinobu Mita 	else
2969beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
297051d648afSAkinobu Mita 
2971beb40ea4SAkinobu Mita 	return csum;
2972beb40ea4SAkinobu Mita }
2973beb40ea4SAkinobu Mita 
29746ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2975beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2976beb40ea4SAkinobu Mita {
2977773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2978beb40ea4SAkinobu Mita 
2979beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2980c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2981beb40ea4SAkinobu Mita 			(unsigned long)sector,
2982beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2983beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2984beb40ea4SAkinobu Mita 		return 0x01;
2985beb40ea4SAkinobu Mita 	}
29868475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2987beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2988c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2989c1287970STomas Winkler 			(unsigned long)sector);
2990beb40ea4SAkinobu Mita 		return 0x03;
2991beb40ea4SAkinobu Mita 	}
29928475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2993beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2994c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2995c1287970STomas Winkler 			(unsigned long)sector);
2996beb40ea4SAkinobu Mita 		return 0x03;
2997beb40ea4SAkinobu Mita 	}
2998beb40ea4SAkinobu Mita 	return 0;
2999beb40ea4SAkinobu Mita }
3000beb40ea4SAkinobu Mita 
300187c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
300265f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3003c6a44287SMartin K. Petersen {
3004be4e11beSAkinobu Mita 	size_t resid;
3005c6a44287SMartin K. Petersen 	void *paddr;
300687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3007b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
300887c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
300914faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3010be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3011c6a44287SMartin K. Petersen 
3012e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3013e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3014c6a44287SMartin K. Petersen 
301587c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
301687c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3017be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3018be4e11beSAkinobu Mita 
3019be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
302087c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
302187c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3022be4e11beSAkinobu Mita 		size_t rest = 0;
302314faa944SAkinobu Mita 
302414faa944SAkinobu Mita 		if (dif_store_end < start + len)
302514faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3026c6a44287SMartin K. Petersen 
3027be4e11beSAkinobu Mita 		paddr = miter.addr;
302814faa944SAkinobu Mita 
302965f72f2aSAkinobu Mita 		if (read)
303065f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
303165f72f2aSAkinobu Mita 		else
303265f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
303365f72f2aSAkinobu Mita 
303465f72f2aSAkinobu Mita 		if (rest) {
303565f72f2aSAkinobu Mita 			if (read)
303614faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
303765f72f2aSAkinobu Mita 			else
303865f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
303965f72f2aSAkinobu Mita 		}
3040c6a44287SMartin K. Petersen 
3041e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3042c6a44287SMartin K. Petersen 		resid -= len;
3043c6a44287SMartin K. Petersen 	}
3044be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3045bb8c063cSAkinobu Mita }
3046c6a44287SMartin K. Petersen 
304787c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3048bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3049bb8c063cSAkinobu Mita {
3050bb8c063cSAkinobu Mita 	unsigned int i;
3051bb8c063cSAkinobu Mita 	sector_t sector;
305287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3053b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
305487c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3055bb8c063cSAkinobu Mita 
3056c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3057bb8c063cSAkinobu Mita 		int ret;
3058bb8c063cSAkinobu Mita 
3059bb8c063cSAkinobu Mita 		sector = start_sec + i;
306087c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3061bb8c063cSAkinobu Mita 
306251d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3063bb8c063cSAkinobu Mita 			continue;
3064bb8c063cSAkinobu Mita 
306587c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
306687c715dcSDouglas Gilbert 				 ei_lba);
3067bb8c063cSAkinobu Mita 		if (ret) {
3068bb8c063cSAkinobu Mita 			dif_errors++;
3069bb8c063cSAkinobu Mita 			return ret;
3070bb8c063cSAkinobu Mita 		}
3071bb8c063cSAkinobu Mita 	}
3072bb8c063cSAkinobu Mita 
307387c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3074c6a44287SMartin K. Petersen 	dix_reads++;
3075c6a44287SMartin K. Petersen 
3076c6a44287SMartin K. Petersen 	return 0;
3077c6a44287SMartin K. Petersen }
3078c6a44287SMartin K. Petersen 
3079fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
308019789100SFUJITA Tomonori {
308187c715dcSDouglas Gilbert 	bool check_prot;
3082c2248fc9SDouglas Gilbert 	u32 num;
3083c2248fc9SDouglas Gilbert 	u32 ei_lba;
308419789100SFUJITA Tomonori 	int ret;
308587c715dcSDouglas Gilbert 	u64 lba;
3086b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
308787c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
308887c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
308919789100SFUJITA Tomonori 
3090c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3091c2248fc9SDouglas Gilbert 	case READ_16:
3092c2248fc9SDouglas Gilbert 		ei_lba = 0;
3093c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3094c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3095c2248fc9SDouglas Gilbert 		check_prot = true;
3096c2248fc9SDouglas Gilbert 		break;
3097c2248fc9SDouglas Gilbert 	case READ_10:
3098c2248fc9SDouglas Gilbert 		ei_lba = 0;
3099c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3100c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3101c2248fc9SDouglas Gilbert 		check_prot = true;
3102c2248fc9SDouglas Gilbert 		break;
3103c2248fc9SDouglas Gilbert 	case READ_6:
3104c2248fc9SDouglas Gilbert 		ei_lba = 0;
3105c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3106c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3107c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3108c2248fc9SDouglas Gilbert 		check_prot = true;
3109c2248fc9SDouglas Gilbert 		break;
3110c2248fc9SDouglas Gilbert 	case READ_12:
3111c2248fc9SDouglas Gilbert 		ei_lba = 0;
3112c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3113c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3114c2248fc9SDouglas Gilbert 		check_prot = true;
3115c2248fc9SDouglas Gilbert 		break;
3116c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3117c2248fc9SDouglas Gilbert 		ei_lba = 0;
3118c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3119c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3120c2248fc9SDouglas Gilbert 		check_prot = false;
3121c2248fc9SDouglas Gilbert 		break;
3122c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3123c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3124c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3125c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3126c2248fc9SDouglas Gilbert 		check_prot = false;
3127c2248fc9SDouglas Gilbert 		break;
3128c2248fc9SDouglas Gilbert 	}
3129f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31308475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3131c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3132c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3133c2248fc9SDouglas Gilbert 			return check_condition_result;
3134c2248fc9SDouglas Gilbert 		}
31358475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31368475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3137c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3138c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3139c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3140c2248fc9SDouglas Gilbert 	}
31413a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
31423a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3143c2248fc9SDouglas Gilbert 		num /= 2;
31443a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3145c2248fc9SDouglas Gilbert 	}
3146c2248fc9SDouglas Gilbert 
31479447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31489447b6ceSMartin K. Petersen 	if (ret)
31499447b6ceSMartin K. Petersen 		return ret;
3150f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3151d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3152d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3153c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3154c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3155c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3156c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3157c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
315832f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
315932f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3160c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3161c65b1445SDouglas Gilbert 		}
3162c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
31631da177e4SLinus Torvalds 		return check_condition_result;
31641da177e4SLinus Torvalds 	}
3165c6a44287SMartin K. Petersen 
316667da413fSDouglas Gilbert 	read_lock(macc_lckp);
31676c78cc06SAkinobu Mita 
3168c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3169f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3170c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
3171c6a44287SMartin K. Petersen 
3172c6a44287SMartin K. Petersen 		if (prot_ret) {
317367da413fSDouglas Gilbert 			read_unlock(macc_lckp);
3174c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
3175c6a44287SMartin K. Petersen 			return illegal_condition_result;
3176c6a44287SMartin K. Petersen 		}
3177c6a44287SMartin K. Petersen 	}
3178c6a44287SMartin K. Petersen 
317987c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
318067da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3181f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3182a4517511SAkinobu Mita 		return DID_ERROR << 16;
3183a4517511SAkinobu Mita 
318442d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3185a4517511SAkinobu Mita 
31863a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
31873a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
31883a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
31893a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
31903a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3191c2248fc9SDouglas Gilbert 			return check_condition_result;
31923a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3193c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3194c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
31953a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3196c2248fc9SDouglas Gilbert 			return illegal_condition_result;
31973a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3198c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
31993a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3200c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3201c2248fc9SDouglas Gilbert 		}
3202c2248fc9SDouglas Gilbert 	}
3203a4517511SAkinobu Mita 	return 0;
32041da177e4SLinus Torvalds }
32051da177e4SLinus Torvalds 
320658a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
3207c6a44287SMartin K. Petersen {
3208cbf67842SDouglas Gilbert 	int i, j, n;
3209c6a44287SMartin K. Petersen 
3210cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
3211c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
3212cbf67842SDouglas Gilbert 		char b[128];
3213c6a44287SMartin K. Petersen 
3214cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
3215c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
3216c6a44287SMartin K. Petersen 
3217cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
3218cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3219cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
3220cbf67842SDouglas Gilbert 			else
3221cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3222cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
3223cbf67842SDouglas Gilbert 		}
3224cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
3225c6a44287SMartin K. Petersen 	}
3226c6a44287SMartin K. Petersen }
3227c6a44287SMartin K. Petersen 
3228c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3229395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3230c6a44287SMartin K. Petersen {
3231be4e11beSAkinobu Mita 	int ret;
32326ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3233be4e11beSAkinobu Mita 	void *daddr;
323465f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3235c6a44287SMartin K. Petersen 	int ppage_offset;
3236be4e11beSAkinobu Mita 	int dpage_offset;
3237be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3238be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3239c6a44287SMartin K. Petersen 
3240c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3241c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3242c6a44287SMartin K. Petersen 
3243be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3244be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3245be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3246be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3247be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3248c6a44287SMartin K. Petersen 
3249be4e11beSAkinobu Mita 	/* For each protection page */
3250be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3251be4e11beSAkinobu Mita 		dpage_offset = 0;
3252be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3253be4e11beSAkinobu Mita 			ret = 0x01;
3254be4e11beSAkinobu Mita 			goto out;
3255c6a44287SMartin K. Petersen 		}
3256c6a44287SMartin K. Petersen 
3257be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32586ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3259be4e11beSAkinobu Mita 			/* If we're at the end of the current
3260be4e11beSAkinobu Mita 			 * data page advance to the next one
3261be4e11beSAkinobu Mita 			 */
3262be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3263be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3264be4e11beSAkinobu Mita 					ret = 0x01;
3265be4e11beSAkinobu Mita 					goto out;
3266be4e11beSAkinobu Mita 				}
3267be4e11beSAkinobu Mita 				dpage_offset = 0;
3268be4e11beSAkinobu Mita 			}
3269c6a44287SMartin K. Petersen 
3270be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3271be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3272be4e11beSAkinobu Mita 
3273be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
3274beb40ea4SAkinobu Mita 			if (ret) {
3275773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
3276395cef03SMartin K. Petersen 				goto out;
3277395cef03SMartin K. Petersen 			}
3278395cef03SMartin K. Petersen 
3279c6a44287SMartin K. Petersen 			sector++;
3280395cef03SMartin K. Petersen 			ei_lba++;
3281773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3282c6a44287SMartin K. Petersen 		}
3283be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3284be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3285c6a44287SMartin K. Petersen 	}
3286be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3287c6a44287SMartin K. Petersen 
328865f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3289c6a44287SMartin K. Petersen 	dix_writes++;
3290c6a44287SMartin K. Petersen 
3291c6a44287SMartin K. Petersen 	return 0;
3292c6a44287SMartin K. Petersen 
3293c6a44287SMartin K. Petersen out:
3294c6a44287SMartin K. Petersen 	dif_errors++;
3295be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3296be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3297c6a44287SMartin K. Petersen 	return ret;
3298c6a44287SMartin K. Petersen }
3299c6a44287SMartin K. Petersen 
3300b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3301b90ebc3dSAkinobu Mita {
3302773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3303773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3304773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3305b90ebc3dSAkinobu Mita 	return lba;
3306b90ebc3dSAkinobu Mita }
3307b90ebc3dSAkinobu Mita 
3308b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3309b90ebc3dSAkinobu Mita {
3310773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3311a027b5b9SAkinobu Mita 
3312773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3313773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3314a027b5b9SAkinobu Mita 	return lba;
3315a027b5b9SAkinobu Mita }
3316a027b5b9SAkinobu Mita 
331787c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
331887c715dcSDouglas Gilbert 			      unsigned int *num)
331944d92694SMartin K. Petersen {
3320b90ebc3dSAkinobu Mita 	sector_t end;
3321b90ebc3dSAkinobu Mita 	unsigned int mapped;
3322b90ebc3dSAkinobu Mita 	unsigned long index;
3323b90ebc3dSAkinobu Mita 	unsigned long next;
332444d92694SMartin K. Petersen 
3325b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
332687c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
332744d92694SMartin K. Petersen 
332844d92694SMartin K. Petersen 	if (mapped)
332987c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
333044d92694SMartin K. Petersen 	else
333187c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
333244d92694SMartin K. Petersen 
3333b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
333444d92694SMartin K. Petersen 	*num = end - lba;
333544d92694SMartin K. Petersen 	return mapped;
333644d92694SMartin K. Petersen }
333744d92694SMartin K. Petersen 
333887c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
333987c715dcSDouglas Gilbert 		       unsigned int len)
334044d92694SMartin K. Petersen {
334144d92694SMartin K. Petersen 	sector_t end = lba + len;
334244d92694SMartin K. Petersen 
334344d92694SMartin K. Petersen 	while (lba < end) {
3344b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
334544d92694SMartin K. Petersen 
3346b90ebc3dSAkinobu Mita 		if (index < map_size)
334787c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
334844d92694SMartin K. Petersen 
3349b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
335044d92694SMartin K. Petersen 	}
335144d92694SMartin K. Petersen }
335244d92694SMartin K. Petersen 
335387c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
335487c715dcSDouglas Gilbert 			 unsigned int len)
335544d92694SMartin K. Petersen {
335644d92694SMartin K. Petersen 	sector_t end = lba + len;
335787c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
335844d92694SMartin K. Petersen 
335944d92694SMartin K. Petersen 	while (lba < end) {
3360b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
336144d92694SMartin K. Petersen 
3362b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3363773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3364b90ebc3dSAkinobu Mita 		    index < map_size) {
336587c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3366760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
336787c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3368760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3369773642d9SDouglas Gilbert 				       sdebug_sector_size *
3370773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3371be1dd78dSEric Sandeen 			}
337287c715dcSDouglas Gilbert 			if (sip->dif_storep) {
337387c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
337487c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3375773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3376e9926b43SAkinobu Mita 			}
3377b90ebc3dSAkinobu Mita 		}
3378b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
337944d92694SMartin K. Petersen 	}
338044d92694SMartin K. Petersen }
338144d92694SMartin K. Petersen 
3382fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
33831da177e4SLinus Torvalds {
338487c715dcSDouglas Gilbert 	bool check_prot;
3385c2248fc9SDouglas Gilbert 	u32 num;
3386c2248fc9SDouglas Gilbert 	u32 ei_lba;
338719789100SFUJITA Tomonori 	int ret;
338887c715dcSDouglas Gilbert 	u64 lba;
3389b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3390b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
339187c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
33921da177e4SLinus Torvalds 
3393c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3394c2248fc9SDouglas Gilbert 	case WRITE_16:
3395c2248fc9SDouglas Gilbert 		ei_lba = 0;
3396c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3397c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3398c2248fc9SDouglas Gilbert 		check_prot = true;
3399c2248fc9SDouglas Gilbert 		break;
3400c2248fc9SDouglas Gilbert 	case WRITE_10:
3401c2248fc9SDouglas Gilbert 		ei_lba = 0;
3402c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3403c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3404c2248fc9SDouglas Gilbert 		check_prot = true;
3405c2248fc9SDouglas Gilbert 		break;
3406c2248fc9SDouglas Gilbert 	case WRITE_6:
3407c2248fc9SDouglas Gilbert 		ei_lba = 0;
3408c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3409c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3410c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3411c2248fc9SDouglas Gilbert 		check_prot = true;
3412c2248fc9SDouglas Gilbert 		break;
3413c2248fc9SDouglas Gilbert 	case WRITE_12:
3414c2248fc9SDouglas Gilbert 		ei_lba = 0;
3415c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3416c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3417c2248fc9SDouglas Gilbert 		check_prot = true;
3418c2248fc9SDouglas Gilbert 		break;
3419c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3420c2248fc9SDouglas Gilbert 		ei_lba = 0;
3421c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3422c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3423c2248fc9SDouglas Gilbert 		check_prot = false;
3424c2248fc9SDouglas Gilbert 		break;
3425c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3426c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3427c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3428c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3429c2248fc9SDouglas Gilbert 		check_prot = false;
3430c2248fc9SDouglas Gilbert 		break;
3431c2248fc9SDouglas Gilbert 	}
3432f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34338475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3434c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3435c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3436c2248fc9SDouglas Gilbert 			return check_condition_result;
3437c2248fc9SDouglas Gilbert 		}
34388475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34398475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3440c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3441c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3442c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3443c2248fc9SDouglas Gilbert 	}
3444f0d1cf93SDouglas Gilbert 
344567da413fSDouglas Gilbert 	write_lock(macc_lckp);
3446f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3447f0d1cf93SDouglas Gilbert 	if (ret) {
3448f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3449f0d1cf93SDouglas Gilbert 		return ret;
3450f0d1cf93SDouglas Gilbert 	}
34516c78cc06SAkinobu Mita 
3452c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3453f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3454c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3455c6a44287SMartin K. Petersen 
3456c6a44287SMartin K. Petersen 		if (prot_ret) {
345767da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3458c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3459c6a44287SMartin K. Petersen 			return illegal_condition_result;
3460c6a44287SMartin K. Petersen 		}
3461c6a44287SMartin K. Petersen 	}
3462c6a44287SMartin K. Petersen 
346387c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3464f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
346587c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3466f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3467f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3468f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
346967da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3470f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3471773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3472c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3473c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3474c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3475cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3476773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
347744d92694SMartin K. Petersen 
34783a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
34793a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
34803a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
34813a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
34823a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3483c2248fc9SDouglas Gilbert 			return check_condition_result;
34843a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3485c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3486c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
34873a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3488c2248fc9SDouglas Gilbert 			return illegal_condition_result;
34893a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3490c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
34913a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3492c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3493c2248fc9SDouglas Gilbert 		}
3494c2248fc9SDouglas Gilbert 	}
34951da177e4SLinus Torvalds 	return 0;
34961da177e4SLinus Torvalds }
34971da177e4SLinus Torvalds 
3498481b5e5cSDouglas Gilbert /*
3499481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3500481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3501481b5e5cSDouglas Gilbert  */
3502481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3503481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3504481b5e5cSDouglas Gilbert {
3505481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3506481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3507481b5e5cSDouglas Gilbert 	u8 *up;
3508b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3509b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
3510481b5e5cSDouglas Gilbert 	u8 wrprotect;
3511481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3512481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3513481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3514481b5e5cSDouglas Gilbert 	u32 ei_lba;
3515481b5e5cSDouglas Gilbert 	u64 lba;
3516481b5e5cSDouglas Gilbert 	int ret, res;
3517481b5e5cSDouglas Gilbert 	bool is_16;
3518481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3519481b5e5cSDouglas Gilbert 
3520481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3521481b5e5cSDouglas Gilbert 		is_16 = false;
3522481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3523481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3524481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3525481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3526481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3527481b5e5cSDouglas Gilbert 		is_16 = true;
3528481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3529481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3530481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3531481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3532481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3533481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3534481b5e5cSDouglas Gilbert 			    wrprotect) {
3535481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3536481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3537481b5e5cSDouglas Gilbert 			}
3538481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3539481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3540481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3541481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3542481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3543481b5e5cSDouglas Gilbert 		}
3544481b5e5cSDouglas Gilbert 	}
3545481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3546481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3547481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3548481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3549481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3550481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3551481b5e5cSDouglas Gilbert 				my_name, __func__);
3552481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3553481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3554481b5e5cSDouglas Gilbert 	}
3555481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3556481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3557481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3558481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3559481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3560481b5e5cSDouglas Gilbert 				my_name, __func__);
3561481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3562481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3563481b5e5cSDouglas Gilbert 	}
3564481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3565481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3566481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3567481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3568481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3569481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3570481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3571481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3572481b5e5cSDouglas Gilbert 	if (res == -1) {
3573481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3574481b5e5cSDouglas Gilbert 		goto err_out;
3575481b5e5cSDouglas Gilbert 	}
3576481b5e5cSDouglas Gilbert 
357767da413fSDouglas Gilbert 	write_lock(macc_lckp);
3578481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3579481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3580481b5e5cSDouglas Gilbert 	cum_lb = 0;
3581481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3582481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3583481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3584481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3585481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3586481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3587481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3588481b5e5cSDouglas Gilbert 		if (num == 0)
3589481b5e5cSDouglas Gilbert 			continue;
35909447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3591481b5e5cSDouglas Gilbert 		if (ret)
3592481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3593481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3594481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3595481b5e5cSDouglas Gilbert 
3596481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3597481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3598481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3599481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3600481b5e5cSDouglas Gilbert 				    my_name, __func__);
3601481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3602481b5e5cSDouglas Gilbert 					0);
3603481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3604481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3605481b5e5cSDouglas Gilbert 		}
3606481b5e5cSDouglas Gilbert 
3607481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3608481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3609481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3610481b5e5cSDouglas Gilbert 							 ei_lba);
3611481b5e5cSDouglas Gilbert 
3612481b5e5cSDouglas Gilbert 			if (prot_ret) {
3613481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3614481b5e5cSDouglas Gilbert 						prot_ret);
3615481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3616481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3617481b5e5cSDouglas Gilbert 			}
3618481b5e5cSDouglas Gilbert 		}
3619481b5e5cSDouglas Gilbert 
362087c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3621f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3622f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3623f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3624481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
362587c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3626481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3627481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3628481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3629481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3630481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3631481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3632481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3633481b5e5cSDouglas Gilbert 
36343a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36353a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
36363a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36373a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36383a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
36393a90a63dSDouglas Gilbert 				ret = check_condition_result;
3640481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36413a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3642481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
36433a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
36443a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3645481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3646481b5e5cSDouglas Gilbert 				goto err_out_unlock;
36473a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
36483a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
36493a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3650481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3651481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3652481b5e5cSDouglas Gilbert 			}
3653481b5e5cSDouglas Gilbert 		}
3654481b5e5cSDouglas Gilbert 		sg_off += num_by;
3655481b5e5cSDouglas Gilbert 		cum_lb += num;
3656481b5e5cSDouglas Gilbert 	}
3657481b5e5cSDouglas Gilbert 	ret = 0;
3658481b5e5cSDouglas Gilbert err_out_unlock:
365967da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3660481b5e5cSDouglas Gilbert err_out:
3661481b5e5cSDouglas Gilbert 	kfree(lrdp);
3662481b5e5cSDouglas Gilbert 	return ret;
3663481b5e5cSDouglas Gilbert }
3664481b5e5cSDouglas Gilbert 
3665fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3666fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
366744d92694SMartin K. Petersen {
3668f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3669f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
367044d92694SMartin K. Petersen 	unsigned long long i;
367140d07b52SDouglas Gilbert 	u64 block, lbaa;
367287c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
367387c715dcSDouglas Gilbert 	int ret;
367487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3675b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
3676b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
367740d07b52SDouglas Gilbert 	u8 *fs1p;
367887c715dcSDouglas Gilbert 	u8 *fsp;
367944d92694SMartin K. Petersen 
368067da413fSDouglas Gilbert 	write_lock(macc_lckp);
368144d92694SMartin K. Petersen 
3682f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3683f0d1cf93SDouglas Gilbert 	if (ret) {
3684f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3685f0d1cf93SDouglas Gilbert 		return ret;
3686f0d1cf93SDouglas Gilbert 	}
3687f0d1cf93SDouglas Gilbert 
36889ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
368987c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
369044d92694SMartin K. Petersen 		goto out;
369144d92694SMartin K. Petersen 	}
369240d07b52SDouglas Gilbert 	lbaa = lba;
369340d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3694c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
369587c715dcSDouglas Gilbert 	fsp = sip->storep;
369687c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3697c2248fc9SDouglas Gilbert 	if (ndob) {
369840d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3699c2248fc9SDouglas Gilbert 		ret = 0;
3700c2248fc9SDouglas Gilbert 	} else
370140d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
370244d92694SMartin K. Petersen 
370344d92694SMartin K. Petersen 	if (-1 == ret) {
370467da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3705773642d9SDouglas Gilbert 		return DID_ERROR << 16;
370640d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3707c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3708e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
370940d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
371044d92694SMartin K. Petersen 
371144d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
371240d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
371340d07b52SDouglas Gilbert 		lbaa = lba + i;
371440d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
371587c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
371640d07b52SDouglas Gilbert 	}
37179ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
371887c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3719f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3720f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3721f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
372244d92694SMartin K. Petersen out:
372367da413fSDouglas Gilbert 	write_unlock(macc_lckp);
372444d92694SMartin K. Petersen 
372544d92694SMartin K. Petersen 	return 0;
372644d92694SMartin K. Petersen }
372744d92694SMartin K. Petersen 
3728fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3729fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3730c2248fc9SDouglas Gilbert {
3731c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3732c2248fc9SDouglas Gilbert 	u32 lba;
3733c2248fc9SDouglas Gilbert 	u16 num;
3734c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3735c2248fc9SDouglas Gilbert 	bool unmap = false;
3736c2248fc9SDouglas Gilbert 
3737c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3738773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3739c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3740c2248fc9SDouglas Gilbert 			return check_condition_result;
3741c2248fc9SDouglas Gilbert 		} else
3742c2248fc9SDouglas Gilbert 			unmap = true;
3743c2248fc9SDouglas Gilbert 	}
3744c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3745c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3746773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3747c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3748c2248fc9SDouglas Gilbert 		return check_condition_result;
3749c2248fc9SDouglas Gilbert 	}
3750c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3751c2248fc9SDouglas Gilbert }
3752c2248fc9SDouglas Gilbert 
3753fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3754fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3755c2248fc9SDouglas Gilbert {
3756c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3757c2248fc9SDouglas Gilbert 	u64 lba;
3758c2248fc9SDouglas Gilbert 	u32 num;
3759c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3760c2248fc9SDouglas Gilbert 	bool unmap = false;
3761c2248fc9SDouglas Gilbert 	bool ndob = false;
3762c2248fc9SDouglas Gilbert 
3763c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3764773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3765c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3766c2248fc9SDouglas Gilbert 			return check_condition_result;
3767c2248fc9SDouglas Gilbert 		} else
3768c2248fc9SDouglas Gilbert 			unmap = true;
3769c2248fc9SDouglas Gilbert 	}
3770c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3771c2248fc9SDouglas Gilbert 		ndob = true;
3772c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3773c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3774773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3775c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3776c2248fc9SDouglas Gilbert 		return check_condition_result;
3777c2248fc9SDouglas Gilbert 	}
3778c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3779c2248fc9SDouglas Gilbert }
3780c2248fc9SDouglas Gilbert 
3781acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3782acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3783acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3784fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3785fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3786acafd0b9SEwan D. Milne {
3787acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3788acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3789acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3790acafd0b9SEwan D. Milne 	u8 mode;
3791acafd0b9SEwan D. Milne 
3792acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3793acafd0b9SEwan D. Milne 	switch (mode) {
3794acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3795acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3796acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3797acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3798acafd0b9SEwan D. Milne 		break;
3799acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3800acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3801acafd0b9SEwan D. Milne 		break;
3802acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3803acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3804acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3805acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3806acafd0b9SEwan D. Milne 				    dev_list)
3807acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3808acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3809acafd0b9SEwan D. Milne 				if (devip != dp)
3810acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3811acafd0b9SEwan D. Milne 						dp->uas_bm);
3812acafd0b9SEwan D. Milne 			}
3813acafd0b9SEwan D. Milne 		break;
3814acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3815acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3816acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3817acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3818acafd0b9SEwan D. Milne 				    dev_list)
3819acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3820acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3821acafd0b9SEwan D. Milne 					dp->uas_bm);
3822acafd0b9SEwan D. Milne 		break;
3823acafd0b9SEwan D. Milne 	default:
3824acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3825acafd0b9SEwan D. Milne 		break;
3826acafd0b9SEwan D. Milne 	}
3827acafd0b9SEwan D. Milne 	return 0;
3828acafd0b9SEwan D. Milne }
3829acafd0b9SEwan D. Milne 
3830fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3831fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
383238d5c833SDouglas Gilbert {
383338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
383438d5c833SDouglas Gilbert 	u8 *arr;
3835b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3836b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
383738d5c833SDouglas Gilbert 	u64 lba;
383838d5c833SDouglas Gilbert 	u32 dnum;
3839773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
384038d5c833SDouglas Gilbert 	u8 num;
384138d5c833SDouglas Gilbert 	int ret;
3842d467d31fSDouglas Gilbert 	int retval = 0;
384338d5c833SDouglas Gilbert 
3844d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
384538d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
384638d5c833SDouglas Gilbert 	if (0 == num)
384738d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38488475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
384938d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
385038d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
385138d5c833SDouglas Gilbert 		return check_condition_result;
385238d5c833SDouglas Gilbert 	}
38538475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
38548475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
385538d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
385638d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
385738d5c833SDouglas Gilbert 			    "to DIF device\n");
38589447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
38599447b6ceSMartin K. Petersen 	if (ret)
38609447b6ceSMartin K. Petersen 		return ret;
3861d467d31fSDouglas Gilbert 	dnum = 2 * num;
38626396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3863d467d31fSDouglas Gilbert 	if (NULL == arr) {
3864d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3865d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3866d467d31fSDouglas Gilbert 		return check_condition_result;
3867d467d31fSDouglas Gilbert 	}
386838d5c833SDouglas Gilbert 
386967da413fSDouglas Gilbert 	write_lock(macc_lckp);
387038d5c833SDouglas Gilbert 
387187c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
387238d5c833SDouglas Gilbert 	if (ret == -1) {
3873d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3874d467d31fSDouglas Gilbert 		goto cleanup;
3875773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
387638d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
387738d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
387838d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3879c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
388038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3881d467d31fSDouglas Gilbert 		retval = check_condition_result;
3882d467d31fSDouglas Gilbert 		goto cleanup;
388338d5c833SDouglas Gilbert 	}
388438d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
388587c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3886d467d31fSDouglas Gilbert cleanup:
388767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3888d467d31fSDouglas Gilbert 	kfree(arr);
3889d467d31fSDouglas Gilbert 	return retval;
389038d5c833SDouglas Gilbert }
389138d5c833SDouglas Gilbert 
389244d92694SMartin K. Petersen struct unmap_block_desc {
389344d92694SMartin K. Petersen 	__be64	lba;
389444d92694SMartin K. Petersen 	__be32	blocks;
389544d92694SMartin K. Petersen 	__be32	__reserved;
389644d92694SMartin K. Petersen };
389744d92694SMartin K. Petersen 
3898fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
389944d92694SMartin K. Petersen {
390044d92694SMartin K. Petersen 	unsigned char *buf;
390144d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
3902b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3903b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
390444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
390544d92694SMartin K. Petersen 	int ret;
390644d92694SMartin K. Petersen 
3907c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3908c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3909c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3910c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
391144d92694SMartin K. Petersen 
391244d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3913773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3914c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
391544d92694SMartin K. Petersen 		return check_condition_result;
3916c2248fc9SDouglas Gilbert 	}
391744d92694SMartin K. Petersen 
3918b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3919c2248fc9SDouglas Gilbert 	if (!buf) {
3920c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3921c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3922c2248fc9SDouglas Gilbert 		return check_condition_result;
3923c2248fc9SDouglas Gilbert 	}
3924c2248fc9SDouglas Gilbert 
3925c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
392644d92694SMartin K. Petersen 
392744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
392844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
392944d92694SMartin K. Petersen 
393044d92694SMartin K. Petersen 	desc = (void *)&buf[8];
393144d92694SMartin K. Petersen 
393267da413fSDouglas Gilbert 	write_lock(macc_lckp);
39336c78cc06SAkinobu Mita 
393444d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
393544d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
393644d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
393744d92694SMartin K. Petersen 
39389447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
393944d92694SMartin K. Petersen 		if (ret)
394044d92694SMartin K. Petersen 			goto out;
394144d92694SMartin K. Petersen 
394287c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
394344d92694SMartin K. Petersen 	}
394444d92694SMartin K. Petersen 
394544d92694SMartin K. Petersen 	ret = 0;
394644d92694SMartin K. Petersen 
394744d92694SMartin K. Petersen out:
394867da413fSDouglas Gilbert 	write_unlock(macc_lckp);
394944d92694SMartin K. Petersen 	kfree(buf);
395044d92694SMartin K. Petersen 
395144d92694SMartin K. Petersen 	return ret;
395244d92694SMartin K. Petersen }
395344d92694SMartin K. Petersen 
395444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
395544d92694SMartin K. Petersen 
3956fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3957fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
395844d92694SMartin K. Petersen {
3959c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3960c2248fc9SDouglas Gilbert 	u64 lba;
3961c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
396244d92694SMartin K. Petersen 	int ret;
396387c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
396444d92694SMartin K. Petersen 
3965c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3966c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
396744d92694SMartin K. Petersen 
396844d92694SMartin K. Petersen 	if (alloc_len < 24)
396944d92694SMartin K. Petersen 		return 0;
397044d92694SMartin K. Petersen 
39719447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
397244d92694SMartin K. Petersen 	if (ret)
397344d92694SMartin K. Petersen 		return ret;
397444d92694SMartin K. Petersen 
3975b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
3976b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
3977b6ff8ca7SDouglas Gilbert 
397887c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
3979b6ff8ca7SDouglas Gilbert 	} else {
3980c2248fc9SDouglas Gilbert 		mapped = 1;
3981c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3982c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3983c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3984c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3985c2248fc9SDouglas Gilbert 		else
3986c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3987c2248fc9SDouglas Gilbert 	}
398844d92694SMartin K. Petersen 
398944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3990c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3991c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3992c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3993c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
399444d92694SMartin K. Petersen 
3995c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
399644d92694SMartin K. Petersen }
399744d92694SMartin K. Petersen 
399880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
399980c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
400080c49563SDouglas Gilbert {
40014f2c8bf6SDouglas Gilbert 	int res = 0;
400280c49563SDouglas Gilbert 	u64 lba;
400380c49563SDouglas Gilbert 	u32 num_blocks;
400480c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
400580c49563SDouglas Gilbert 
400680c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
400780c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
400880c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
400980c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
401080c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
401180c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
401280c49563SDouglas Gilbert 	}
401380c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
401480c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
401580c49563SDouglas Gilbert 		return check_condition_result;
401680c49563SDouglas Gilbert 	}
40174f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
40184f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40194f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40204f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40214f2c8bf6SDouglas Gilbert 	return res;
402280c49563SDouglas Gilbert }
402380c49563SDouglas Gilbert 
4024ed9f3e25SDouglas Gilbert /*
4025ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4026ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4027ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4028ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4029ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4030ed9f3e25SDouglas Gilbert  */
4031ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4032ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4033ed9f3e25SDouglas Gilbert {
4034ed9f3e25SDouglas Gilbert 	int res = 0;
4035ed9f3e25SDouglas Gilbert 	u64 lba;
4036ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4037ed9f3e25SDouglas Gilbert 	u32 nblks;
4038ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4039b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4040b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4041b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4042ed9f3e25SDouglas Gilbert 
4043ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4044ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4045ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4046ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4047ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4048ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4049ed9f3e25SDouglas Gilbert 	}
4050ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4051ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4052ed9f3e25SDouglas Gilbert 		return check_condition_result;
4053ed9f3e25SDouglas Gilbert 	}
4054ed9f3e25SDouglas Gilbert 	if (!fsp)
4055ed9f3e25SDouglas Gilbert 		goto fini;
4056ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4057ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4058ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4059ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4060ed9f3e25SDouglas Gilbert 
4061ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4062ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4063ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4064ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4065ed9f3e25SDouglas Gilbert 	if (rest)
4066ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4067ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4068ed9f3e25SDouglas Gilbert fini:
4069ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4070ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4071ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4072ed9f3e25SDouglas Gilbert }
4073ed9f3e25SDouglas Gilbert 
4074fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4075fb0cc8d1SDouglas Gilbert 
40768d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
40778d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
40788d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
40798d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
40808d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
40818d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
40828d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
40838d039e22SDouglas Gilbert  */
40841da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
40851da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
40861da177e4SLinus Torvalds {
408701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
40888d039e22SDouglas Gilbert 	unsigned int alloc_len;
40898d039e22SDouglas Gilbert 	unsigned char select_report;
40908d039e22SDouglas Gilbert 	u64 lun;
40918d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4092fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
40938d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
40948d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
40958d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
40968d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4097fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4098fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4099fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41001da177e4SLinus Torvalds 
410119c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41028d039e22SDouglas Gilbert 
41038d039e22SDouglas Gilbert 	select_report = cmd[2];
41048d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41058d039e22SDouglas Gilbert 
41068d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41078d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41088d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41091da177e4SLinus Torvalds 		return check_condition_result;
41101da177e4SLinus Torvalds 	}
41118d039e22SDouglas Gilbert 
41128d039e22SDouglas Gilbert 	switch (select_report) {
41138d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4114773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41158d039e22SDouglas Gilbert 		wlun_cnt = 0;
41168d039e22SDouglas Gilbert 		break;
41178d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4118c65b1445SDouglas Gilbert 		lun_cnt = 0;
41198d039e22SDouglas Gilbert 		wlun_cnt = 1;
41208d039e22SDouglas Gilbert 		break;
41218d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41228d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41238d039e22SDouglas Gilbert 		wlun_cnt = 1;
41248d039e22SDouglas Gilbert 		break;
41258d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41268d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41278d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41288d039e22SDouglas Gilbert 	default:
41298d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41308d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41318d039e22SDouglas Gilbert 		return check_condition_result;
41328d039e22SDouglas Gilbert 	}
41338d039e22SDouglas Gilbert 
41348d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4135c65b1445SDouglas Gilbert 		--lun_cnt;
41368d039e22SDouglas Gilbert 
41378d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4138fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4139fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41408d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41418d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41428d039e22SDouglas Gilbert 
4143fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41448d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4145fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4146fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4147fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4148fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4149fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4150fb0cc8d1SDouglas Gilbert 			++lun_p;
4151fb0cc8d1SDouglas Gilbert 			j = 1;
4152fb0cc8d1SDouglas Gilbert 		}
4153fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4154fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4155fb0cc8d1SDouglas Gilbert 				break;
4156fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4157fb0cc8d1SDouglas Gilbert 		}
4158fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4159fb0cc8d1SDouglas Gilbert 			break;
4160fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4161fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4162fb0cc8d1SDouglas Gilbert 		if (res)
4163fb0cc8d1SDouglas Gilbert 			return res;
4164fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4165fb0cc8d1SDouglas Gilbert 	}
4166fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4167fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4168fb0cc8d1SDouglas Gilbert 		++j;
4169fb0cc8d1SDouglas Gilbert 	}
4170fb0cc8d1SDouglas Gilbert 	if (j > 0)
4171fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
41728d039e22SDouglas Gilbert 	return res;
41731da177e4SLinus Torvalds }
41741da177e4SLinus Torvalds 
4175c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4176c3e2fe92SDouglas Gilbert {
4177c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4178c3e2fe92SDouglas Gilbert 	u8 bytchk;
4179c3e2fe92SDouglas Gilbert 	int ret, j;
4180c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4181c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4182c3e2fe92SDouglas Gilbert 	u64 lba;
4183c3e2fe92SDouglas Gilbert 	u8 *arr;
4184c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4185b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4186b6ff8ca7SDouglas Gilbert 	rwlock_t *macc_lckp = &sip->macc_lck;
4187c3e2fe92SDouglas Gilbert 
4188c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4189c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4190c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4191c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4192c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4193c3e2fe92SDouglas Gilbert 		return check_condition_result;
4194c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4195c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4196c3e2fe92SDouglas Gilbert 	}
4197c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4198c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4199c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4200c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4201c3e2fe92SDouglas Gilbert 		break;
4202c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4203c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4204c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4205c3e2fe92SDouglas Gilbert 		break;
4206c3e2fe92SDouglas Gilbert 	default:
4207c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4208c3e2fe92SDouglas Gilbert 		return check_condition_result;
4209c3e2fe92SDouglas Gilbert 	}
4210c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4211c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4212c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4213c3e2fe92SDouglas Gilbert 	if (ret)
4214c3e2fe92SDouglas Gilbert 		return ret;
4215c3e2fe92SDouglas Gilbert 
4216c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4217c3e2fe92SDouglas Gilbert 	if (!arr) {
4218c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4219c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4220c3e2fe92SDouglas Gilbert 		return check_condition_result;
4221c3e2fe92SDouglas Gilbert 	}
4222c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
422367da413fSDouglas Gilbert 	read_lock(macc_lckp);
4224c3e2fe92SDouglas Gilbert 
4225c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4226c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4227c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4228c3e2fe92SDouglas Gilbert 		goto cleanup;
4229c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4230c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4231c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4232c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4233c3e2fe92SDouglas Gilbert 	}
4234c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4235c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4236c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4237c3e2fe92SDouglas Gilbert 	}
4238c3e2fe92SDouglas Gilbert 	ret = 0;
4239c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4240c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4241c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4242c3e2fe92SDouglas Gilbert 		goto cleanup;
4243c3e2fe92SDouglas Gilbert 	}
4244c3e2fe92SDouglas Gilbert cleanup:
424567da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4246c3e2fe92SDouglas Gilbert 	kfree(arr);
4247c3e2fe92SDouglas Gilbert 	return ret;
4248c3e2fe92SDouglas Gilbert }
4249c3e2fe92SDouglas Gilbert 
4250f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4251f0d1cf93SDouglas Gilbert 
4252f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4253f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4254f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4255f0d1cf93SDouglas Gilbert {
4256f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4257f0d1cf93SDouglas Gilbert 	int ret = 0;
4258f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4259f0d1cf93SDouglas Gilbert 	bool partial;
4260f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4261f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4262f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4263f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4264b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4265f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4266f0d1cf93SDouglas Gilbert 
4267f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4268f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4269f0d1cf93SDouglas Gilbert 		return check_condition_result;
4270f0d1cf93SDouglas Gilbert 	}
4271f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4272f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4273f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4274f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4275f0d1cf93SDouglas Gilbert 
4276f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4277f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4278f0d1cf93SDouglas Gilbert 		return check_condition_result;
4279f0d1cf93SDouglas Gilbert 	}
4280f0d1cf93SDouglas Gilbert 
4281108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4282f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4283f0d1cf93SDouglas Gilbert 			    max_zones);
4284f0d1cf93SDouglas Gilbert 
4285f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4286f0d1cf93SDouglas Gilbert 	if (!arr) {
4287f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4288f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4289f0d1cf93SDouglas Gilbert 		return check_condition_result;
4290f0d1cf93SDouglas Gilbert 	}
4291f0d1cf93SDouglas Gilbert 
4292f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4293f0d1cf93SDouglas Gilbert 
4294f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4295f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4296f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4297f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4298f0d1cf93SDouglas Gilbert 			break;
4299f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4300f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4301f0d1cf93SDouglas Gilbert 		case 0x00:
4302f0d1cf93SDouglas Gilbert 			/* All zones */
4303f0d1cf93SDouglas Gilbert 			break;
4304f0d1cf93SDouglas Gilbert 		case 0x01:
4305f0d1cf93SDouglas Gilbert 			/* Empty zones */
4306f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4307f0d1cf93SDouglas Gilbert 				continue;
4308f0d1cf93SDouglas Gilbert 			break;
4309f0d1cf93SDouglas Gilbert 		case 0x02:
4310f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4311f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4312f0d1cf93SDouglas Gilbert 				continue;
4313f0d1cf93SDouglas Gilbert 			break;
4314f0d1cf93SDouglas Gilbert 		case 0x03:
4315f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4316f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4317f0d1cf93SDouglas Gilbert 				continue;
4318f0d1cf93SDouglas Gilbert 			break;
4319f0d1cf93SDouglas Gilbert 		case 0x04:
4320f0d1cf93SDouglas Gilbert 			/* Closed zones */
4321f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4322f0d1cf93SDouglas Gilbert 				continue;
4323f0d1cf93SDouglas Gilbert 			break;
4324f0d1cf93SDouglas Gilbert 		case 0x05:
4325f0d1cf93SDouglas Gilbert 			/* Full zones */
4326f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4327f0d1cf93SDouglas Gilbert 				continue;
4328f0d1cf93SDouglas Gilbert 			break;
4329f0d1cf93SDouglas Gilbert 		case 0x06:
4330f0d1cf93SDouglas Gilbert 		case 0x07:
4331f0d1cf93SDouglas Gilbert 		case 0x10:
4332f0d1cf93SDouglas Gilbert 			/*
433364e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
433464e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4335f0d1cf93SDouglas Gilbert 			 */
4336f0d1cf93SDouglas Gilbert 			continue;
433764e14eceSDamien Le Moal 		case 0x11:
433864e14eceSDamien Le Moal 			/* non-seq-resource set */
433964e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
434064e14eceSDamien Le Moal 				continue;
434164e14eceSDamien Le Moal 			break;
4342f0d1cf93SDouglas Gilbert 		case 0x3f:
4343f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4344f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4345f0d1cf93SDouglas Gilbert 				continue;
4346f0d1cf93SDouglas Gilbert 			break;
4347f0d1cf93SDouglas Gilbert 		default:
4348f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4349f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4350f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4351f0d1cf93SDouglas Gilbert 			goto fini;
4352f0d1cf93SDouglas Gilbert 		}
4353f0d1cf93SDouglas Gilbert 
4354f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4355f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
435664e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4357f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
435864e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
435964e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4360f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4361f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4362f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4363f0d1cf93SDouglas Gilbert 			desc += 64;
4364f0d1cf93SDouglas Gilbert 		}
4365f0d1cf93SDouglas Gilbert 
4366f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4367f0d1cf93SDouglas Gilbert 			break;
4368f0d1cf93SDouglas Gilbert 
4369f0d1cf93SDouglas Gilbert 		nrz++;
4370f0d1cf93SDouglas Gilbert 	}
4371f0d1cf93SDouglas Gilbert 
4372f0d1cf93SDouglas Gilbert 	/* Report header */
4373f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4374f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4375f0d1cf93SDouglas Gilbert 
4376f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4377f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4378f0d1cf93SDouglas Gilbert 
4379f0d1cf93SDouglas Gilbert fini:
4380f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4381f0d1cf93SDouglas Gilbert 	kfree(arr);
4382f0d1cf93SDouglas Gilbert 	return ret;
4383f0d1cf93SDouglas Gilbert }
4384f0d1cf93SDouglas Gilbert 
4385f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4386f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4387f0d1cf93SDouglas Gilbert {
4388f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4389f0d1cf93SDouglas Gilbert 	unsigned int i;
4390f0d1cf93SDouglas Gilbert 
4391f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4392f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4393f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4394f0d1cf93SDouglas Gilbert 	}
4395f0d1cf93SDouglas Gilbert }
4396f0d1cf93SDouglas Gilbert 
4397f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4398f0d1cf93SDouglas Gilbert {
4399f0d1cf93SDouglas Gilbert 	int res = 0;
4400f0d1cf93SDouglas Gilbert 	u64 z_id;
4401f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4402f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4403f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4404f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4405b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4406f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4407f0d1cf93SDouglas Gilbert 
4408f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4409f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4410f0d1cf93SDouglas Gilbert 		return check_condition_result;
4411f0d1cf93SDouglas Gilbert 	}
4412f0d1cf93SDouglas Gilbert 
4413f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4414f0d1cf93SDouglas Gilbert 
4415f0d1cf93SDouglas Gilbert 	if (all) {
4416f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4417f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4418f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4419f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4420f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4421f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4422f0d1cf93SDouglas Gilbert 			goto fini;
4423f0d1cf93SDouglas Gilbert 		}
4424f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4425f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4426f0d1cf93SDouglas Gilbert 		goto fini;
4427f0d1cf93SDouglas Gilbert 	}
4428f0d1cf93SDouglas Gilbert 
4429f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4430f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4431f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4432f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4433f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4434f0d1cf93SDouglas Gilbert 		goto fini;
4435f0d1cf93SDouglas Gilbert 	}
4436f0d1cf93SDouglas Gilbert 
4437f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4438f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4439f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4440f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4441f0d1cf93SDouglas Gilbert 		goto fini;
4442f0d1cf93SDouglas Gilbert 	}
4443f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4444f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4445f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4446f0d1cf93SDouglas Gilbert 		goto fini;
4447f0d1cf93SDouglas Gilbert 	}
4448f0d1cf93SDouglas Gilbert 
4449f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4450f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4451f0d1cf93SDouglas Gilbert 		goto fini;
4452f0d1cf93SDouglas Gilbert 
4453f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4454f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4455f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4456f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4457f0d1cf93SDouglas Gilbert 		goto fini;
4458f0d1cf93SDouglas Gilbert 	}
4459f0d1cf93SDouglas Gilbert 
4460f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
4461f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4462f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4463f0d1cf93SDouglas Gilbert fini:
4464f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4465f0d1cf93SDouglas Gilbert 	return res;
4466f0d1cf93SDouglas Gilbert }
4467f0d1cf93SDouglas Gilbert 
4468f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4469f0d1cf93SDouglas Gilbert {
4470f0d1cf93SDouglas Gilbert 	unsigned int i;
4471f0d1cf93SDouglas Gilbert 
4472f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4473f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4474f0d1cf93SDouglas Gilbert }
4475f0d1cf93SDouglas Gilbert 
4476f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4477f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4478f0d1cf93SDouglas Gilbert {
4479f0d1cf93SDouglas Gilbert 	int res = 0;
4480f0d1cf93SDouglas Gilbert 	u64 z_id;
4481f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4482f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4483f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4484b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4485f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4486f0d1cf93SDouglas Gilbert 
4487f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4488f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4489f0d1cf93SDouglas Gilbert 		return check_condition_result;
4490f0d1cf93SDouglas Gilbert 	}
4491f0d1cf93SDouglas Gilbert 
4492f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4493f0d1cf93SDouglas Gilbert 
4494f0d1cf93SDouglas Gilbert 	if (all) {
4495f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4496f0d1cf93SDouglas Gilbert 		goto fini;
4497f0d1cf93SDouglas Gilbert 	}
4498f0d1cf93SDouglas Gilbert 
4499f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4500f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4501f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4502f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4503f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4504f0d1cf93SDouglas Gilbert 		goto fini;
4505f0d1cf93SDouglas Gilbert 	}
4506f0d1cf93SDouglas Gilbert 
4507f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4508f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4509f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4510f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4511f0d1cf93SDouglas Gilbert 		goto fini;
4512f0d1cf93SDouglas Gilbert 	}
4513f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4514f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4515f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4516f0d1cf93SDouglas Gilbert 		goto fini;
4517f0d1cf93SDouglas Gilbert 	}
4518f0d1cf93SDouglas Gilbert 
4519f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4520f0d1cf93SDouglas Gilbert fini:
4521f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4522f0d1cf93SDouglas Gilbert 	return res;
4523f0d1cf93SDouglas Gilbert }
4524f0d1cf93SDouglas Gilbert 
4525f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4526f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4527f0d1cf93SDouglas Gilbert {
4528f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4529f0d1cf93SDouglas Gilbert 
4530f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4531f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4532f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4533f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4534f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4535f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4536f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4537f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4538f0d1cf93SDouglas Gilbert 	}
4539f0d1cf93SDouglas Gilbert }
4540f0d1cf93SDouglas Gilbert 
4541f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4542f0d1cf93SDouglas Gilbert {
4543f0d1cf93SDouglas Gilbert 	unsigned int i;
4544f0d1cf93SDouglas Gilbert 
4545f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4546f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4547f0d1cf93SDouglas Gilbert }
4548f0d1cf93SDouglas Gilbert 
4549f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4550f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4551f0d1cf93SDouglas Gilbert {
4552f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4553f0d1cf93SDouglas Gilbert 	int res = 0;
4554f0d1cf93SDouglas Gilbert 	u64 z_id;
4555f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4556f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4557b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4558f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4559f0d1cf93SDouglas Gilbert 
4560f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4561f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4562f0d1cf93SDouglas Gilbert 		return check_condition_result;
4563f0d1cf93SDouglas Gilbert 	}
4564f0d1cf93SDouglas Gilbert 
4565f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4566f0d1cf93SDouglas Gilbert 
4567f0d1cf93SDouglas Gilbert 	if (all) {
4568f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4569f0d1cf93SDouglas Gilbert 		goto fini;
4570f0d1cf93SDouglas Gilbert 	}
4571f0d1cf93SDouglas Gilbert 
4572f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4573f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4574f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4575f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4576f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4577f0d1cf93SDouglas Gilbert 		goto fini;
4578f0d1cf93SDouglas Gilbert 	}
4579f0d1cf93SDouglas Gilbert 
4580f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4581f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4582f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4583f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4584f0d1cf93SDouglas Gilbert 		goto fini;
4585f0d1cf93SDouglas Gilbert 	}
4586f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4587f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4588f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4589f0d1cf93SDouglas Gilbert 		goto fini;
4590f0d1cf93SDouglas Gilbert 	}
4591f0d1cf93SDouglas Gilbert 
4592f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4593f0d1cf93SDouglas Gilbert fini:
4594f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4595f0d1cf93SDouglas Gilbert 	return res;
4596f0d1cf93SDouglas Gilbert }
4597f0d1cf93SDouglas Gilbert 
4598f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4599f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4600f0d1cf93SDouglas Gilbert {
4601f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4602f0d1cf93SDouglas Gilbert 
4603f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4604f0d1cf93SDouglas Gilbert 		return;
4605f0d1cf93SDouglas Gilbert 
4606f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4607f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4608f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4609f0d1cf93SDouglas Gilbert 
4610f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4611f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4612f0d1cf93SDouglas Gilbert 
461364e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4614f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4615f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4616f0d1cf93SDouglas Gilbert }
4617f0d1cf93SDouglas Gilbert 
4618f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4619f0d1cf93SDouglas Gilbert {
4620f0d1cf93SDouglas Gilbert 	unsigned int i;
4621f0d1cf93SDouglas Gilbert 
4622f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4623f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4624f0d1cf93SDouglas Gilbert }
4625f0d1cf93SDouglas Gilbert 
4626f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4627f0d1cf93SDouglas Gilbert {
4628f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4629f0d1cf93SDouglas Gilbert 	int res = 0;
4630f0d1cf93SDouglas Gilbert 	u64 z_id;
4631f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4632f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4633b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4634f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4635f0d1cf93SDouglas Gilbert 
4636f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4637f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4638f0d1cf93SDouglas Gilbert 		return check_condition_result;
4639f0d1cf93SDouglas Gilbert 	}
4640f0d1cf93SDouglas Gilbert 
4641f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4642f0d1cf93SDouglas Gilbert 
4643f0d1cf93SDouglas Gilbert 	if (all) {
4644f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4645f0d1cf93SDouglas Gilbert 		goto fini;
4646f0d1cf93SDouglas Gilbert 	}
4647f0d1cf93SDouglas Gilbert 
4648f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4649f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4650f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4651f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4652f0d1cf93SDouglas Gilbert 		goto fini;
4653f0d1cf93SDouglas Gilbert 	}
4654f0d1cf93SDouglas Gilbert 
4655f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4656f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4657f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4658f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4659f0d1cf93SDouglas Gilbert 		goto fini;
4660f0d1cf93SDouglas Gilbert 	}
4661f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4662f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4663f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4664f0d1cf93SDouglas Gilbert 		goto fini;
4665f0d1cf93SDouglas Gilbert 	}
4666f0d1cf93SDouglas Gilbert 
4667f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4668f0d1cf93SDouglas Gilbert fini:
4669f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4670f0d1cf93SDouglas Gilbert 	return res;
4671f0d1cf93SDouglas Gilbert }
4672f0d1cf93SDouglas Gilbert 
4673c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4674c4837394SDouglas Gilbert {
4675c10fa55fSJohn Garry 	u16 hwq;
4676c10fa55fSJohn Garry 
4677c10fa55fSJohn Garry 	if (sdebug_host_max_queue) {
4678c10fa55fSJohn Garry 		/* Provide a simple method to choose the hwq */
4679c10fa55fSJohn Garry 		hwq = smp_processor_id() % submit_queues;
4680c10fa55fSJohn Garry 	} else {
4681c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
4682c10fa55fSJohn Garry 
4683c10fa55fSJohn Garry 		hwq = blk_mq_unique_tag_to_hwq(tag);
4684c4837394SDouglas Gilbert 
4685458df78bSBart Van Assche 		pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4686458df78bSBart Van Assche 		if (WARN_ON_ONCE(hwq >= submit_queues))
4687458df78bSBart Van Assche 			hwq = 0;
4688c10fa55fSJohn Garry 	}
4689458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4690c4837394SDouglas Gilbert }
4691c4837394SDouglas Gilbert 
4692c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4693c10fa55fSJohn Garry {
4694c10fa55fSJohn Garry 	return blk_mq_unique_tag(cmnd->request);
4695c10fa55fSJohn Garry }
4696c10fa55fSJohn Garry 
4697c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4698fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
46991da177e4SLinus Torvalds {
47007382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4701c4837394SDouglas Gilbert 	int qc_idx;
4702cbf67842SDouglas Gilbert 	int retiring = 0;
47031da177e4SLinus Torvalds 	unsigned long iflags;
4704c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4705cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4706cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4707cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47081da177e4SLinus Torvalds 
470910bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
47107382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47117382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4712c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4713c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4714c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4715cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4716c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4717c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4718c4837394SDouglas Gilbert 	}
4719c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4720c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47211da177e4SLinus Torvalds 		return;
47221da177e4SLinus Torvalds 	}
4723c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4724c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4725cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4726b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4727c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4728c10fa55fSJohn Garry 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4729c10fa55fSJohn Garry 		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
47301da177e4SLinus Torvalds 		return;
47311da177e4SLinus Torvalds 	}
4732cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4733f46eb0e9SDouglas Gilbert 	if (likely(devip))
4734cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4735cbf67842SDouglas Gilbert 	else
4736c1287970STomas Winkler 		pr_err("devip=NULL\n");
4737f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4738cbf67842SDouglas Gilbert 		retiring = 1;
4739cbf67842SDouglas Gilbert 
4740cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4741c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4742c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4743c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4744cbf67842SDouglas Gilbert 		return;
47451da177e4SLinus Torvalds 	}
47461da177e4SLinus Torvalds 
4747cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4748cbf67842SDouglas Gilbert 		int k, retval;
4749cbf67842SDouglas Gilbert 
4750cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4751c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4752c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4753c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4754cbf67842SDouglas Gilbert 			return;
4755cbf67842SDouglas Gilbert 		}
4756c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4757773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4758cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4759cbf67842SDouglas Gilbert 		else
4760cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4761cbf67842SDouglas Gilbert 	}
4762c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47637382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
47647382f9d8SDouglas Gilbert 		if (sdebug_verbose)
47657382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
47667382f9d8SDouglas Gilbert 		return;
47677382f9d8SDouglas Gilbert 	}
4768cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4769cbf67842SDouglas Gilbert }
4770cbf67842SDouglas Gilbert 
4771cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4772fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4773cbf67842SDouglas Gilbert {
4774a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4775a10bc12aSDouglas Gilbert 						  hrt);
4776a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4777cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4778cbf67842SDouglas Gilbert }
47791da177e4SLinus Torvalds 
4780a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4781fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4782a10bc12aSDouglas Gilbert {
4783a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4784a10bc12aSDouglas Gilbert 						  ew.work);
4785a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4786a10bc12aSDouglas Gilbert }
4787a10bc12aSDouglas Gilbert 
478809ba24c1SDouglas Gilbert static bool got_shared_uuid;
4789bf476433SChristoph Hellwig static uuid_t shared_uuid;
479009ba24c1SDouglas Gilbert 
4791f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4792f0d1cf93SDouglas Gilbert {
4793f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4794f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4795f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4796f0d1cf93SDouglas Gilbert 	unsigned int i;
4797f0d1cf93SDouglas Gilbert 
4798f0d1cf93SDouglas Gilbert 	/*
479998e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
480098e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4801f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4802f0d1cf93SDouglas Gilbert 	 * created for the device.
4803f0d1cf93SDouglas Gilbert 	 */
480498e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4805f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4806f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4807f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4808f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4809f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4810f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4811f0d1cf93SDouglas Gilbert 			return -EINVAL;
4812f0d1cf93SDouglas Gilbert 		}
4813f0d1cf93SDouglas Gilbert 	} else {
4814108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4815108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4816108e36f0SDamien Le Moal 			return -EINVAL;
4817108e36f0SDamien Le Moal 		}
481898e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4819f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4820f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4821f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4822f0d1cf93SDouglas Gilbert 			return -EINVAL;
4823f0d1cf93SDouglas Gilbert 		}
4824f0d1cf93SDouglas Gilbert 	}
4825f0d1cf93SDouglas Gilbert 
4826f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4827f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4828f0d1cf93SDouglas Gilbert 
4829aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4830aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4831aa8fecf9SDamien Le Moal 		return -EINVAL;
4832aa8fecf9SDamien Le Moal 	}
4833aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4834aa8fecf9SDamien Le Moal 
483564e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
483664e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4837380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4838f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4839f0d1cf93SDouglas Gilbert 		else
4840380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
484164e14eceSDamien Le Moal 	}
4842f0d1cf93SDouglas Gilbert 
4843f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4844f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4845f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4846f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4847f0d1cf93SDouglas Gilbert 
4848f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4849f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4850f0d1cf93SDouglas Gilbert 
4851f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4852f0d1cf93SDouglas Gilbert 
4853aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
485464e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4855f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4856f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4857f0d1cf93SDouglas Gilbert 		} else {
485864e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
485964e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
486064e14eceSDamien Le Moal 			else
486164e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4862f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4863f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4864f0d1cf93SDouglas Gilbert 		}
4865f0d1cf93SDouglas Gilbert 
4866f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4867f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4868f0d1cf93SDouglas Gilbert 		else
4869f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4870f0d1cf93SDouglas Gilbert 
4871f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4872f0d1cf93SDouglas Gilbert 	}
4873f0d1cf93SDouglas Gilbert 
4874f0d1cf93SDouglas Gilbert 	return 0;
4875f0d1cf93SDouglas Gilbert }
4876f0d1cf93SDouglas Gilbert 
4877fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4878fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
48795cb2fc06SFUJITA Tomonori {
48805cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
48815cb2fc06SFUJITA Tomonori 
48825cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
48835cb2fc06SFUJITA Tomonori 	if (devip) {
488409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4885bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
488609ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
488709ba24c1SDouglas Gilbert 			if (got_shared_uuid)
488809ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
488909ba24c1SDouglas Gilbert 			else {
4890bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
489109ba24c1SDouglas Gilbert 				got_shared_uuid = true;
489209ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
489309ba24c1SDouglas Gilbert 			}
489409ba24c1SDouglas Gilbert 		}
48955cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4896f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
489764e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4898f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4899f0d1cf93SDouglas Gilbert 				kfree(devip);
4900f0d1cf93SDouglas Gilbert 				return NULL;
4901f0d1cf93SDouglas Gilbert 			}
490264e14eceSDamien Le Moal 		} else {
490364e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4904f0d1cf93SDouglas Gilbert 		}
4905f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
49065cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49075cb2fc06SFUJITA Tomonori 	}
49085cb2fc06SFUJITA Tomonori 	return devip;
49095cb2fc06SFUJITA Tomonori }
49105cb2fc06SFUJITA Tomonori 
4911f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49121da177e4SLinus Torvalds {
49131da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49141da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4915f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49161da177e4SLinus Torvalds 
4917d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49181da177e4SLinus Torvalds 	if (!sdbg_host) {
4919c1287970STomas Winkler 		pr_err("Host info NULL\n");
49201da177e4SLinus Torvalds 		return NULL;
49211da177e4SLinus Torvalds 	}
49221da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49231da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49241da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49251da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49261da177e4SLinus Torvalds 			return devip;
49271da177e4SLinus Torvalds 		else {
49281da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49291da177e4SLinus Torvalds 				open_devip = devip;
49301da177e4SLinus Torvalds 		}
49311da177e4SLinus Torvalds 	}
49325cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49335cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49345cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4935c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49361da177e4SLinus Torvalds 			return NULL;
49371da177e4SLinus Torvalds 		}
49381da177e4SLinus Torvalds 	}
4939a75869d1SFUJITA Tomonori 
49401da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
49411da177e4SLinus Torvalds 	open_devip->target = sdev->id;
49421da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
49431da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4944cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4945cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4946c2248fc9SDouglas Gilbert 	open_devip->used = true;
49471da177e4SLinus Torvalds 	return open_devip;
49481da177e4SLinus Torvalds }
49491da177e4SLinus Torvalds 
49508dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
49511da177e4SLinus Torvalds {
4952773642d9SDouglas Gilbert 	if (sdebug_verbose)
4953c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
49548dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49558dea0d02SFUJITA Tomonori 	return 0;
49568dea0d02SFUJITA Tomonori }
49571da177e4SLinus Torvalds 
49588dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
49598dea0d02SFUJITA Tomonori {
4960f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4961f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4962a34c4e98SFUJITA Tomonori 
4963773642d9SDouglas Gilbert 	if (sdebug_verbose)
4964c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
49658dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4966b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4967b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4968b01f6f83SDouglas Gilbert 	if (devip == NULL) {
4969f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
4970b01f6f83SDouglas Gilbert 		if (devip == NULL)
49718dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
4972f46eb0e9SDouglas Gilbert 	}
4973c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
4974773642d9SDouglas Gilbert 	if (sdebug_no_uld)
497578d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
49769b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
49778dea0d02SFUJITA Tomonori 	return 0;
49788dea0d02SFUJITA Tomonori }
49798dea0d02SFUJITA Tomonori 
49808dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
49818dea0d02SFUJITA Tomonori {
49828dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
49838dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
49848dea0d02SFUJITA Tomonori 
4985773642d9SDouglas Gilbert 	if (sdebug_verbose)
4986c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
49878dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49888dea0d02SFUJITA Tomonori 	if (devip) {
498925985edcSLucas De Marchi 		/* make this slot available for re-use */
4990c2248fc9SDouglas Gilbert 		devip->used = false;
49918dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
49928dea0d02SFUJITA Tomonori 	}
49938dea0d02SFUJITA Tomonori }
49948dea0d02SFUJITA Tomonori 
499510bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
499610bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
4997c4837394SDouglas Gilbert {
4998c4837394SDouglas Gilbert 	if (!sd_dp)
4999c4837394SDouglas Gilbert 		return;
500010bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5001c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
500210bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5003c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5004c4837394SDouglas Gilbert }
5005c4837394SDouglas Gilbert 
5006a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5007a10bc12aSDouglas Gilbert    returns false */
5008a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50098dea0d02SFUJITA Tomonori {
50108dea0d02SFUJITA Tomonori 	unsigned long iflags;
5011c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
501210bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5013c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50148dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5015cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5016a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50178dea0d02SFUJITA Tomonori 
5018c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5019c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5020773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5021cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5022cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5023cbf67842SDouglas Gilbert 			qmax = r_qmax;
5024cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5025c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5026c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5027a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5028a10bc12aSDouglas Gilbert 					continue;
5029c4837394SDouglas Gilbert 				/* found */
5030db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5031db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5032db525fceSDouglas Gilbert 				if (devip)
5033db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5034db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5035a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
503610bde980SDouglas Gilbert 				if (sd_dp) {
503710bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
503810bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
503910bde980SDouglas Gilbert 				} else
504010bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5041c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
504210bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5043c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5044a10bc12aSDouglas Gilbert 				return true;
50458dea0d02SFUJITA Tomonori 			}
5046cbf67842SDouglas Gilbert 		}
5047c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5048c4837394SDouglas Gilbert 	}
5049a10bc12aSDouglas Gilbert 	return false;
50508dea0d02SFUJITA Tomonori }
50518dea0d02SFUJITA Tomonori 
5052a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
50538dea0d02SFUJITA Tomonori static void stop_all_queued(void)
50548dea0d02SFUJITA Tomonori {
50558dea0d02SFUJITA Tomonori 	unsigned long iflags;
5056c4837394SDouglas Gilbert 	int j, k;
505710bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5058c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50598dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5060cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5061a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50628dea0d02SFUJITA Tomonori 
5063c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5064c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5065c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5066c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5067c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5068c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5069a10bc12aSDouglas Gilbert 					continue;
5070db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5071db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5072db525fceSDouglas Gilbert 				if (devip)
5073db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5074db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5075a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
507610bde980SDouglas Gilbert 				if (sd_dp) {
507710bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
507810bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
507910bde980SDouglas Gilbert 				} else
508010bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5081c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
508210bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5083c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5084c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
50858dea0d02SFUJITA Tomonori 			}
50868dea0d02SFUJITA Tomonori 		}
5087c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5088c4837394SDouglas Gilbert 	}
5089cbf67842SDouglas Gilbert }
5090cbf67842SDouglas Gilbert 
5091cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5092cbf67842SDouglas Gilbert static void free_all_queued(void)
5093cbf67842SDouglas Gilbert {
5094c4837394SDouglas Gilbert 	int j, k;
5095c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5096cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5097cbf67842SDouglas Gilbert 
5098c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5099c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5100c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5101a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5102a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5103cbf67842SDouglas Gilbert 		}
51041da177e4SLinus Torvalds 	}
5105c4837394SDouglas Gilbert }
51061da177e4SLinus Torvalds 
51071da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51081da177e4SLinus Torvalds {
5109a10bc12aSDouglas Gilbert 	bool ok;
5110a10bc12aSDouglas Gilbert 
51111da177e4SLinus Torvalds 	++num_aborts;
5112cbf67842SDouglas Gilbert 	if (SCpnt) {
5113a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5114a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5115a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5116a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5117a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5118cbf67842SDouglas Gilbert 	}
51191da177e4SLinus Torvalds 	return SUCCESS;
51201da177e4SLinus Torvalds }
51211da177e4SLinus Torvalds 
51221da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51231da177e4SLinus Torvalds {
51241da177e4SLinus Torvalds 	++num_dev_resets;
5125cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5126cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5127f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5128f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5129cbf67842SDouglas Gilbert 
5130773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5131cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51321da177e4SLinus Torvalds 		if (devip)
5133cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51341da177e4SLinus Torvalds 	}
51351da177e4SLinus Torvalds 	return SUCCESS;
51361da177e4SLinus Torvalds }
51371da177e4SLinus Torvalds 
5138cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5139cbf67842SDouglas Gilbert {
5140cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5141cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5142cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5143cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5144cbf67842SDouglas Gilbert 	int k = 0;
5145cbf67842SDouglas Gilbert 
5146cbf67842SDouglas Gilbert 	++num_target_resets;
5147cbf67842SDouglas Gilbert 	if (!SCpnt)
5148cbf67842SDouglas Gilbert 		goto lie;
5149cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5150cbf67842SDouglas Gilbert 	if (!sdp)
5151cbf67842SDouglas Gilbert 		goto lie;
5152773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5153cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5154cbf67842SDouglas Gilbert 	hp = sdp->host;
5155cbf67842SDouglas Gilbert 	if (!hp)
5156cbf67842SDouglas Gilbert 		goto lie;
5157cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5158cbf67842SDouglas Gilbert 	if (sdbg_host) {
5159cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5160cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5161cbf67842SDouglas Gilbert 				    dev_list)
5162cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5163cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5164cbf67842SDouglas Gilbert 				++k;
5165cbf67842SDouglas Gilbert 			}
5166cbf67842SDouglas Gilbert 	}
5167773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5168cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5169cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5170cbf67842SDouglas Gilbert lie:
5171cbf67842SDouglas Gilbert 	return SUCCESS;
5172cbf67842SDouglas Gilbert }
5173cbf67842SDouglas Gilbert 
51741da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
51751da177e4SLinus Torvalds {
51761da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5177cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
51781da177e4SLinus Torvalds 	struct scsi_device *sdp;
51791da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5180cbf67842SDouglas Gilbert 	int k = 0;
51811da177e4SLinus Torvalds 
51821da177e4SLinus Torvalds 	++num_bus_resets;
5183cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5184cbf67842SDouglas Gilbert 		goto lie;
5185cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5186773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5187cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5188cbf67842SDouglas Gilbert 	hp = sdp->host;
5189cbf67842SDouglas Gilbert 	if (hp) {
5190d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
51911da177e4SLinus Torvalds 		if (sdbg_host) {
5192cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
51931da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5194cbf67842SDouglas Gilbert 					    dev_list) {
5195cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5196cbf67842SDouglas Gilbert 				++k;
51971da177e4SLinus Torvalds 			}
51981da177e4SLinus Torvalds 		}
5199cbf67842SDouglas Gilbert 	}
5200773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5201cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5202cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5203cbf67842SDouglas Gilbert lie:
52041da177e4SLinus Torvalds 	return SUCCESS;
52051da177e4SLinus Torvalds }
52061da177e4SLinus Torvalds 
52071da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52081da177e4SLinus Torvalds {
52091da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5210cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5211cbf67842SDouglas Gilbert 	int k = 0;
52121da177e4SLinus Torvalds 
52131da177e4SLinus Torvalds 	++num_host_resets;
5214773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5215cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52161da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52171da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5218cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5219cbf67842SDouglas Gilbert 				    dev_list) {
5220cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5221cbf67842SDouglas Gilbert 			++k;
5222cbf67842SDouglas Gilbert 		}
52231da177e4SLinus Torvalds 	}
52241da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52251da177e4SLinus Torvalds 	stop_all_queued();
5226773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5227cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5228cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
52291da177e4SLinus Torvalds 	return SUCCESS;
52301da177e4SLinus Torvalds }
52311da177e4SLinus Torvalds 
523287c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52331da177e4SLinus Torvalds {
52341442f76dSChristoph Hellwig 	struct msdos_partition *pp;
52351da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
52361da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
52371da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
52381da177e4SLinus Torvalds 
52391da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5240773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
52411da177e4SLinus Torvalds 		return;
5242773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5243773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5244c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
52451da177e4SLinus Torvalds 	}
5246c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
52471da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5248773642d9SDouglas Gilbert 			   / sdebug_num_parts;
52491da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
52501da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5251773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
52521da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
52531da177e4SLinus Torvalds 			    * heads_by_sects;
5254773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5255773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
52561da177e4SLinus Torvalds 
52571da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
52581da177e4SLinus Torvalds 	ramp[511] = 0xAA;
52591442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
52601da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
52611da177e4SLinus Torvalds 		start_sec = starts[k];
52621da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
52631da177e4SLinus Torvalds 		pp->boot_ind = 0;
52641da177e4SLinus Torvalds 
52651da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
52661da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
52671da177e4SLinus Torvalds 			   / sdebug_sectors_per;
52681da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
52691da177e4SLinus Torvalds 
52701da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
52711da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
52721da177e4SLinus Torvalds 			       / sdebug_sectors_per;
52731da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
52741da177e4SLinus Torvalds 
5275150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5276150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
52771da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
52781da177e4SLinus Torvalds 	}
52791da177e4SLinus Torvalds }
52801da177e4SLinus Torvalds 
5281c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5282c4837394SDouglas Gilbert {
5283c4837394SDouglas Gilbert 	int j;
5284c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5285c4837394SDouglas Gilbert 
5286c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5287c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5288c4837394SDouglas Gilbert }
5289c4837394SDouglas Gilbert 
5290c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5291c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5292c4837394SDouglas Gilbert  */
5293c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5294c4837394SDouglas Gilbert {
5295c4837394SDouglas Gilbert 	int count, modulo;
5296c4837394SDouglas Gilbert 
5297c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5298c4837394SDouglas Gilbert 	if (modulo < 2)
5299c4837394SDouglas Gilbert 		return;
5300c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5301c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5302c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5303c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5304c4837394SDouglas Gilbert }
5305c4837394SDouglas Gilbert 
5306c4837394SDouglas Gilbert static void clear_queue_stats(void)
5307c4837394SDouglas Gilbert {
5308c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5309c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5310c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5311c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5312c4837394SDouglas Gilbert }
5313c4837394SDouglas Gilbert 
53143a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5315c4837394SDouglas Gilbert {
53163a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
53173a90a63dSDouglas Gilbert 		return false;
53183a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5319c4837394SDouglas Gilbert }
5320c4837394SDouglas Gilbert 
5321a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5322a2aede97SDouglas Gilbert 
5323c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5324c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5325c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5326c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5327c4837394SDouglas Gilbert  */
5328fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5329f66b8517SMartin Wilck 			 int scsi_result,
5330f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5331f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5332f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
53331da177e4SLinus Torvalds {
5334a2aede97SDouglas Gilbert 	bool new_sd_dp;
53353a90a63dSDouglas Gilbert 	bool inject = false;
53363a90a63dSDouglas Gilbert 	int k, num_in_q, qdepth;
5337a2aede97SDouglas Gilbert 	unsigned long iflags;
5338a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5339c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5340c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5341299b6c07STomas Winkler 	struct scsi_device *sdp;
5342a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53431da177e4SLinus Torvalds 
5344b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5345b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5346f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5347f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
53481da177e4SLinus Torvalds 	}
5349299b6c07STomas Winkler 	sdp = cmnd->device;
5350299b6c07STomas Winkler 
5351cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5352cd62b7daSDouglas Gilbert 		goto respond_in_thread;
53531da177e4SLinus Torvalds 
5354c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5355c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5356c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5357c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5358c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5359c4837394SDouglas Gilbert 	}
5360cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5361cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5362f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5363cd62b7daSDouglas Gilbert 		if (scsi_result) {
5364c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5365cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5366cd62b7daSDouglas Gilbert 		} else
5367cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5368c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5369773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5370f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5371cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5372cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5373773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5374cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
53753a90a63dSDouglas Gilbert 			inject = true;
5376cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
53771da177e4SLinus Torvalds 		}
5378cbf67842SDouglas Gilbert 	}
5379cbf67842SDouglas Gilbert 
5380c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5381f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5382c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5383cd62b7daSDouglas Gilbert 		if (scsi_result)
5384cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5385773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5386cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5387773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5388cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5389cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5390773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5391cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5392cbf67842SDouglas Gilbert 						    "report: host busy"));
5393cd62b7daSDouglas Gilbert 		if (scsi_result)
5394cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5395cd62b7daSDouglas Gilbert 		else
5396cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
53971da177e4SLinus Torvalds 	}
539874595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5399cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5400c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
54011da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5402c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5403a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5404c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
540574595c04SDouglas Gilbert 	if (!sd_dp) {
540610bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
540774595c04SDouglas Gilbert 		if (!sd_dp) {
540874595c04SDouglas Gilbert 			atomic_dec(&devip->num_in_q);
540974595c04SDouglas Gilbert 			clear_bit(k, sqp->in_use_bm);
541010bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
541174595c04SDouglas Gilbert 		}
5412a2aede97SDouglas Gilbert 		new_sd_dp = true;
5413a2aede97SDouglas Gilbert 	} else {
5414a2aede97SDouglas Gilbert 		new_sd_dp = false;
541510bde980SDouglas Gilbert 	}
5416f66b8517SMartin Wilck 
5417c10fa55fSJohn Garry 	/* Set the hostwide tag */
5418c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5419c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5420c10fa55fSJohn Garry 
5421a2aede97SDouglas Gilbert 	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
5422a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5423a2aede97SDouglas Gilbert 
5424a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
54253a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5426f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5427f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5428f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5429f66b8517SMartin Wilck 	}
5430f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5431f66b8517SMartin Wilck 		cmnd->result = scsi_result;
54323a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
54333a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
54343a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
54353a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
54363a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
54373a90a63dSDouglas Gilbert 		}
54383a90a63dSDouglas Gilbert 	}
5439f66b8517SMartin Wilck 
5440f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5441f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5442f66b8517SMartin Wilck 			    __func__, cmnd->result);
5443f66b8517SMartin Wilck 
544410bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5445b333a819SDouglas Gilbert 		ktime_t kt;
5446cbf67842SDouglas Gilbert 
5447b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
54480c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
54490c4bc91dSDouglas Gilbert 
54500c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
54510c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
54520c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
54530c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
54540c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
54550c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
54560c4bc91dSDouglas Gilbert 				ns <<= 12;
54570c4bc91dSDouglas Gilbert 			}
54580c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
54590c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
54600c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
54610c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5462a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5463a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5464a2aede97SDouglas Gilbert 
5465a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5466a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5467a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5468a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5469a2aede97SDouglas Gilbert 					if (new_sd_dp)
5470a2aede97SDouglas Gilbert 						kfree(sd_dp);
5471a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
5472a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
5473a2aede97SDouglas Gilbert 					return 0;
5474a2aede97SDouglas Gilbert 				}
5475a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5476a2aede97SDouglas Gilbert 				kt -= d;
5477a2aede97SDouglas Gilbert 			}
54780c4bc91dSDouglas Gilbert 		}
547910bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
548010bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
5481a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5482a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5483c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
5484a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5485c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5486c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5487cbf67842SDouglas Gilbert 		}
5488c4837394SDouglas Gilbert 		if (sdebug_statistics)
5489c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
549010bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
5491a2aede97SDouglas Gilbert 		/* schedule the invocation of scsi_done() for a later time */
5492c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
5493c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
549410bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
549510bde980SDouglas Gilbert 			sd_dp->init_wq = true;
5496a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5497c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5498c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5499a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5500cbf67842SDouglas Gilbert 		}
5501c4837394SDouglas Gilbert 		if (sdebug_statistics)
5502c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
550310bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
55043a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55053a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending)))
55067382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
5507a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
55083a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55093a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
55103a90a63dSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
55117382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
55123a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
55137382f9d8SDouglas Gilbert 		}
5514cbf67842SDouglas Gilbert 	}
55153a90a63dSDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
55163a90a63dSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
55173a90a63dSDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
55181da177e4SLinus Torvalds 	return 0;
5519cd62b7daSDouglas Gilbert 
5520cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5521f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5522f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5523f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5524cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
5525cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
5526cd62b7daSDouglas Gilbert 	return 0;
55271da177e4SLinus Torvalds }
5528cbf67842SDouglas Gilbert 
552923183910SDouglas Gilbert /* Note: The following macros create attribute files in the
553023183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
553123183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
553223183910SDouglas Gilbert    as it can when the corresponding attribute in the
553323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
553423183910SDouglas Gilbert  */
5535773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5536773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
55379b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5538773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5539c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5540773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5541773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5542773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5543773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5544773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5545773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5546773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5547773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5548c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5549e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5550e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5551e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5552e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
55535d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
55545d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
55555d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5556773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5557773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5558773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5559773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5560773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5561773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
55625d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
55635d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
55645d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
55655d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5566773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5567773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5568773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5569773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5570773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5571773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
55725d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5573773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
557487c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
557587c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5576773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5577773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
55780c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5579773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5580773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5581773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5582c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5583773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5584c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5585773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5586773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5587773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5588773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
558909ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
55905d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5591773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
559223183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
55939447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5594773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
55955b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
55969267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5597380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5598aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
559998e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56001da177e4SLinus Torvalds 
56011da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56021da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
56031da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5604b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
56051da177e4SLinus Torvalds 
56065d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56075b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56089b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56090759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5610cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5611c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
56125b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
56135b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5614c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5615beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
561623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
56175b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5618185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5619c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5620c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5621e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
56229b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
56239b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
56245d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
56255d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
56265d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
56275b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
56285b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
56295b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
56305b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5631c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5632cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5633d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
56345d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5635cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5636c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
563778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
56381da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5639c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
564032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
564186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
56425d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
56435d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
56445d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
56451da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
56460c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5647d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5648760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5649ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5650c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5651c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5652c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
56535b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
56545b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
56556014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
56566014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
565709ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
565809ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5659c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
56605b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
56619447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
56625b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
56639267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5664380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5665aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
566698e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
56671da177e4SLinus Torvalds 
5668760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5669760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
56701da177e4SLinus Torvalds 
56711da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
56721da177e4SLinus Torvalds {
5673c4837394SDouglas Gilbert 	int k;
5674c4837394SDouglas Gilbert 
5675760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5676760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5677760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5678c4837394SDouglas Gilbert 		return sdebug_info;
5679760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5680760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5681760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5682760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
56831da177e4SLinus Torvalds 	return sdebug_info;
56841da177e4SLinus Torvalds }
56851da177e4SLinus Torvalds 
5686cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5687fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5688fd32119bSDouglas Gilbert 				 int length)
56891da177e4SLinus Torvalds {
56901da177e4SLinus Torvalds 	char arr[16];
5691c8ed555aSAl Viro 	int opts;
56921da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
56931da177e4SLinus Torvalds 
56941da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
56951da177e4SLinus Torvalds 		return -EACCES;
56961da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
56971da177e4SLinus Torvalds 	arr[minLen] = '\0';
5698c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
56991da177e4SLinus Torvalds 		return -EINVAL;
5700773642d9SDouglas Gilbert 	sdebug_opts = opts;
5701773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5702773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5703773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5704c4837394SDouglas Gilbert 		tweak_cmnd_count();
57051da177e4SLinus Torvalds 	return length;
57061da177e4SLinus Torvalds }
5707c8ed555aSAl Viro 
5708cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5709cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5710cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5711c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5712c8ed555aSAl Viro {
5713c4837394SDouglas Gilbert 	int f, j, l;
5714c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
571587c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5716cbf67842SDouglas Gilbert 
5717c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5718c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5719c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5720c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5721c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5722c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5723c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5724c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5725c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5726c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5727c4837394SDouglas Gilbert 		   num_aborts);
5728c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5729c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5730c4837394SDouglas Gilbert 		   num_host_resets);
5731c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5732c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5733458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5734458df78bSBart Van Assche 		   sdebug_statistics);
5735c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
5736c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5737c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5738c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
5739c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
5740cbf67842SDouglas Gilbert 
5741c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5742c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5743c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5744c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5745773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5746c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5747c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5748c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5749c4837394SDouglas Gilbert 		}
5750cbf67842SDouglas Gilbert 	}
575187c715dcSDouglas Gilbert 
575287c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
575387c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
575487c715dcSDouglas Gilbert 		bool niu;
575587c715dcSDouglas Gilbert 		int idx;
575687c715dcSDouglas Gilbert 		unsigned long l_idx;
575787c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
575887c715dcSDouglas Gilbert 
575987c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
576087c715dcSDouglas Gilbert 		j = 0;
576187c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
576287c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
576387c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
576487c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
576587c715dcSDouglas Gilbert 			++j;
576687c715dcSDouglas Gilbert 		}
576787c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
576887c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
576987c715dcSDouglas Gilbert 		j = 0;
577087c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
577187c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
577287c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
577387c715dcSDouglas Gilbert 			idx = (int)l_idx;
577487c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
577587c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
577687c715dcSDouglas Gilbert 			++j;
577787c715dcSDouglas Gilbert 		}
577887c715dcSDouglas Gilbert 	}
5779c8ed555aSAl Viro 	return 0;
57801da177e4SLinus Torvalds }
57811da177e4SLinus Torvalds 
578282069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
57831da177e4SLinus Torvalds {
5784c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
57851da177e4SLinus Torvalds }
5786c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5787c4837394SDouglas Gilbert  * of delay is jiffies.
5788c4837394SDouglas Gilbert  */
578982069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
579082069379SAkinobu Mita 			   size_t count)
57911da177e4SLinus Torvalds {
5792c2206098SDouglas Gilbert 	int jdelay, res;
57931da177e4SLinus Torvalds 
5794b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5795cbf67842SDouglas Gilbert 		res = count;
5796c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5797c4837394SDouglas Gilbert 			int j, k;
5798c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5799cbf67842SDouglas Gilbert 
5800c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5801c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5802c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5803c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5804c4837394SDouglas Gilbert 						   sdebug_max_queue);
5805c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5806c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5807c4837394SDouglas Gilbert 					break;
5808c4837394SDouglas Gilbert 				}
5809c4837394SDouglas Gilbert 			}
5810c4837394SDouglas Gilbert 			if (res > 0) {
5811c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5812773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
58131da177e4SLinus Torvalds 			}
5814c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5815cbf67842SDouglas Gilbert 		}
5816cbf67842SDouglas Gilbert 		return res;
58171da177e4SLinus Torvalds 	}
58181da177e4SLinus Torvalds 	return -EINVAL;
58191da177e4SLinus Torvalds }
582082069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
58211da177e4SLinus Torvalds 
5822cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5823cbf67842SDouglas Gilbert {
5824773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5825cbf67842SDouglas Gilbert }
5826cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5827c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5828cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5829cbf67842SDouglas Gilbert 			    size_t count)
5830cbf67842SDouglas Gilbert {
5831c4837394SDouglas Gilbert 	int ndelay, res;
5832cbf67842SDouglas Gilbert 
5833cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5834c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5835cbf67842SDouglas Gilbert 		res = count;
5836773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5837c4837394SDouglas Gilbert 			int j, k;
5838c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5839c4837394SDouglas Gilbert 
5840c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5841c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5842c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5843c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5844c4837394SDouglas Gilbert 						   sdebug_max_queue);
5845c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5846c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5847c4837394SDouglas Gilbert 					break;
5848c4837394SDouglas Gilbert 				}
5849c4837394SDouglas Gilbert 			}
5850c4837394SDouglas Gilbert 			if (res > 0) {
5851773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5852c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5853c2206098SDouglas Gilbert 							: DEF_JDELAY;
5854cbf67842SDouglas Gilbert 			}
5855c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5856cbf67842SDouglas Gilbert 		}
5857cbf67842SDouglas Gilbert 		return res;
5858cbf67842SDouglas Gilbert 	}
5859cbf67842SDouglas Gilbert 	return -EINVAL;
5860cbf67842SDouglas Gilbert }
5861cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5862cbf67842SDouglas Gilbert 
586382069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
58641da177e4SLinus Torvalds {
5865773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
58661da177e4SLinus Torvalds }
58671da177e4SLinus Torvalds 
586882069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
586982069379SAkinobu Mita 			  size_t count)
58701da177e4SLinus Torvalds {
58711da177e4SLinus Torvalds 	int opts;
58721da177e4SLinus Torvalds 	char work[20];
58731da177e4SLinus Torvalds 
58749a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
58759a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
58769a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
58771da177e4SLinus Torvalds 				goto opts_done;
58781da177e4SLinus Torvalds 		} else {
58799a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
58801da177e4SLinus Torvalds 				goto opts_done;
58811da177e4SLinus Torvalds 		}
58821da177e4SLinus Torvalds 	}
58831da177e4SLinus Torvalds 	return -EINVAL;
58841da177e4SLinus Torvalds opts_done:
5885773642d9SDouglas Gilbert 	sdebug_opts = opts;
5886773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5887773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5888c4837394SDouglas Gilbert 	tweak_cmnd_count();
58891da177e4SLinus Torvalds 	return count;
58901da177e4SLinus Torvalds }
589182069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
58921da177e4SLinus Torvalds 
589382069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
58941da177e4SLinus Torvalds {
5895773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
58961da177e4SLinus Torvalds }
589782069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
589882069379SAkinobu Mita 			   size_t count)
58991da177e4SLinus Torvalds {
59001da177e4SLinus Torvalds 	int n;
59011da177e4SLinus Torvalds 
5902f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5903f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5904f0d1cf93SDouglas Gilbert 		return -EINVAL;
5905f0d1cf93SDouglas Gilbert 
59061da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5907f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
5908f0d1cf93SDouglas Gilbert 			return -EINVAL;
5909773642d9SDouglas Gilbert 		sdebug_ptype = n;
59101da177e4SLinus Torvalds 		return count;
59111da177e4SLinus Torvalds 	}
59121da177e4SLinus Torvalds 	return -EINVAL;
59131da177e4SLinus Torvalds }
591482069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
59151da177e4SLinus Torvalds 
591682069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
59171da177e4SLinus Torvalds {
5918773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
59191da177e4SLinus Torvalds }
592082069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
592182069379SAkinobu Mita 			    size_t count)
59221da177e4SLinus Torvalds {
59231da177e4SLinus Torvalds 	int n;
59241da177e4SLinus Torvalds 
59251da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5926773642d9SDouglas Gilbert 		sdebug_dsense = n;
59271da177e4SLinus Torvalds 		return count;
59281da177e4SLinus Torvalds 	}
59291da177e4SLinus Torvalds 	return -EINVAL;
59301da177e4SLinus Torvalds }
593182069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
59321da177e4SLinus Torvalds 
593382069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
593423183910SDouglas Gilbert {
5935773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
593623183910SDouglas Gilbert }
593782069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
593882069379SAkinobu Mita 			     size_t count)
593923183910SDouglas Gilbert {
594087c715dcSDouglas Gilbert 	int n, idx;
594123183910SDouglas Gilbert 
594223183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
594387c715dcSDouglas Gilbert 		bool want_store = (n == 0);
594487c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
594587c715dcSDouglas Gilbert 
5946cbf67842SDouglas Gilbert 		n = (n > 0);
5947773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
594887c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
594987c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
5950cbf67842SDouglas Gilbert 
595187c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
595287c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
595387c715dcSDouglas Gilbert 				idx = sdebug_add_store();
595487c715dcSDouglas Gilbert 				if (idx < 0)
595587c715dcSDouglas Gilbert 					return idx;
595687c715dcSDouglas Gilbert 			} else {
595787c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
595887c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
595987c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
5960cbf67842SDouglas Gilbert 			}
596187c715dcSDouglas Gilbert 			/* make all hosts use same store */
596287c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
596387c715dcSDouglas Gilbert 					    host_list) {
596487c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
596587c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
596687c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
596787c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
596887c715dcSDouglas Gilbert 				}
596987c715dcSDouglas Gilbert 			}
597087c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
597187c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
597287c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
5973cbf67842SDouglas Gilbert 		}
5974773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
597523183910SDouglas Gilbert 		return count;
597623183910SDouglas Gilbert 	}
597723183910SDouglas Gilbert 	return -EINVAL;
597823183910SDouglas Gilbert }
597982069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
598023183910SDouglas Gilbert 
598182069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
5982c65b1445SDouglas Gilbert {
5983773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
5984c65b1445SDouglas Gilbert }
598582069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
598682069379SAkinobu Mita 			      size_t count)
5987c65b1445SDouglas Gilbert {
5988c65b1445SDouglas Gilbert 	int n;
5989c65b1445SDouglas Gilbert 
5990c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5991773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
5992c65b1445SDouglas Gilbert 		return count;
5993c65b1445SDouglas Gilbert 	}
5994c65b1445SDouglas Gilbert 	return -EINVAL;
5995c65b1445SDouglas Gilbert }
599682069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
5997c65b1445SDouglas Gilbert 
599882069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
59991da177e4SLinus Torvalds {
6000773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60011da177e4SLinus Torvalds }
600282069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
600382069379SAkinobu Mita 			      size_t count)
60041da177e4SLinus Torvalds {
60051da177e4SLinus Torvalds 	int n;
60061da177e4SLinus Torvalds 
60071da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6008773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
60091da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
60101da177e4SLinus Torvalds 		return count;
60111da177e4SLinus Torvalds 	}
60121da177e4SLinus Torvalds 	return -EINVAL;
60131da177e4SLinus Torvalds }
601482069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
60151da177e4SLinus Torvalds 
601682069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
60171da177e4SLinus Torvalds {
6018773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
60191da177e4SLinus Torvalds }
602082069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
60211da177e4SLinus Torvalds 
602287c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
602387c715dcSDouglas Gilbert {
602487c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
602587c715dcSDouglas Gilbert }
602687c715dcSDouglas Gilbert 
602787c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
602887c715dcSDouglas Gilbert 				    size_t count)
602987c715dcSDouglas Gilbert {
603087c715dcSDouglas Gilbert 	bool v;
603187c715dcSDouglas Gilbert 
603287c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
603387c715dcSDouglas Gilbert 		return -EINVAL;
603487c715dcSDouglas Gilbert 
603587c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
603687c715dcSDouglas Gilbert 	return count;
603787c715dcSDouglas Gilbert }
603887c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
603987c715dcSDouglas Gilbert 
604082069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
60411da177e4SLinus Torvalds {
6042773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
60431da177e4SLinus Torvalds }
604482069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
60451da177e4SLinus Torvalds 
604682069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
60471da177e4SLinus Torvalds {
6048773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
60491da177e4SLinus Torvalds }
605082069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
605182069379SAkinobu Mita 			       size_t count)
60521da177e4SLinus Torvalds {
60531da177e4SLinus Torvalds 	int nth;
60543a90a63dSDouglas Gilbert 	char work[20];
60551da177e4SLinus Torvalds 
60563a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
60573a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
60583a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
60593a90a63dSDouglas Gilbert 				goto every_nth_done;
60603a90a63dSDouglas Gilbert 		} else {
60613a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
60623a90a63dSDouglas Gilbert 				goto every_nth_done;
60633a90a63dSDouglas Gilbert 		}
60643a90a63dSDouglas Gilbert 	}
60653a90a63dSDouglas Gilbert 	return -EINVAL;
60663a90a63dSDouglas Gilbert 
60673a90a63dSDouglas Gilbert every_nth_done:
6068773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6069c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6070c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6071c4837394SDouglas Gilbert 		sdebug_statistics = true;
6072c4837394SDouglas Gilbert 	}
6073c4837394SDouglas Gilbert 	tweak_cmnd_count();
60741da177e4SLinus Torvalds 	return count;
60751da177e4SLinus Torvalds }
607682069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
60771da177e4SLinus Torvalds 
607882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
60791da177e4SLinus Torvalds {
6080773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
60811da177e4SLinus Torvalds }
608282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
608382069379SAkinobu Mita 			      size_t count)
60841da177e4SLinus Torvalds {
60851da177e4SLinus Torvalds 	int n;
608619c8ead7SEwan D. Milne 	bool changed;
60871da177e4SLinus Torvalds 
60881da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60898d039e22SDouglas Gilbert 		if (n > 256) {
60908d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
60918d039e22SDouglas Gilbert 			return -EINVAL;
60928d039e22SDouglas Gilbert 		}
6093773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6094773642d9SDouglas Gilbert 		sdebug_max_luns = n;
60951da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6096773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
609719c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
609819c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
609919c8ead7SEwan D. Milne 
610019c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
610119c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
610219c8ead7SEwan D. Milne 					    host_list) {
610319c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
610419c8ead7SEwan D. Milne 						    dev_list) {
610519c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
610619c8ead7SEwan D. Milne 						dp->uas_bm);
610719c8ead7SEwan D. Milne 				}
610819c8ead7SEwan D. Milne 			}
610919c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
611019c8ead7SEwan D. Milne 		}
61111da177e4SLinus Torvalds 		return count;
61121da177e4SLinus Torvalds 	}
61131da177e4SLinus Torvalds 	return -EINVAL;
61141da177e4SLinus Torvalds }
611582069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
61161da177e4SLinus Torvalds 
611782069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
611878d4e5a0SDouglas Gilbert {
6119773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
612078d4e5a0SDouglas Gilbert }
6121cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6122cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
612382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
612482069379SAkinobu Mita 			       size_t count)
612578d4e5a0SDouglas Gilbert {
6126c4837394SDouglas Gilbert 	int j, n, k, a;
6127c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
612878d4e5a0SDouglas Gilbert 
612978d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6130c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6131c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
6132c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6133c4837394SDouglas Gilbert 		k = 0;
6134c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6135c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6136c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6137c4837394SDouglas Gilbert 			if (a > k)
6138c4837394SDouglas Gilbert 				k = a;
6139c4837394SDouglas Gilbert 		}
6140773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6141c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6142cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6143cbf67842SDouglas Gilbert 		else if (k >= n)
6144cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6145cbf67842SDouglas Gilbert 		else
6146cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6147c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
614878d4e5a0SDouglas Gilbert 		return count;
614978d4e5a0SDouglas Gilbert 	}
615078d4e5a0SDouglas Gilbert 	return -EINVAL;
615178d4e5a0SDouglas Gilbert }
615282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
615378d4e5a0SDouglas Gilbert 
6154c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6155c10fa55fSJohn Garry {
6156c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6157c10fa55fSJohn Garry }
6158c10fa55fSJohn Garry 
6159c10fa55fSJohn Garry /*
6160c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6161c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6162c10fa55fSJohn Garry  */
6163c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6164c10fa55fSJohn Garry 
616582069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
616678d4e5a0SDouglas Gilbert {
6167773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
616878d4e5a0SDouglas Gilbert }
616982069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
617078d4e5a0SDouglas Gilbert 
617182069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
61721da177e4SLinus Torvalds {
6173773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
61741da177e4SLinus Torvalds }
617582069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
61761da177e4SLinus Torvalds 
617782069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6178c65b1445SDouglas Gilbert {
6179773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6180c65b1445SDouglas Gilbert }
618182069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
618282069379SAkinobu Mita 				size_t count)
6183c65b1445SDouglas Gilbert {
6184c65b1445SDouglas Gilbert 	int n;
61850d01c5dfSDouglas Gilbert 	bool changed;
6186c65b1445SDouglas Gilbert 
6187f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6188f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6189f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6190f0d1cf93SDouglas Gilbert 
6191c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6192773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6193773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
619428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
61950d01c5dfSDouglas Gilbert 		if (changed) {
61960d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
61970d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
619828898873SFUJITA Tomonori 
61994bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
62000d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
62010d01c5dfSDouglas Gilbert 					    host_list) {
62020d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
62030d01c5dfSDouglas Gilbert 						    dev_list) {
62040d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
62050d01c5dfSDouglas Gilbert 						dp->uas_bm);
62060d01c5dfSDouglas Gilbert 				}
62070d01c5dfSDouglas Gilbert 			}
62084bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
62090d01c5dfSDouglas Gilbert 		}
6210c65b1445SDouglas Gilbert 		return count;
6211c65b1445SDouglas Gilbert 	}
6212c65b1445SDouglas Gilbert 	return -EINVAL;
6213c65b1445SDouglas Gilbert }
621482069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6215c65b1445SDouglas Gilbert 
621682069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
62171da177e4SLinus Torvalds {
621887c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
621987c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
62201da177e4SLinus Torvalds }
62211da177e4SLinus Torvalds 
622282069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
622382069379SAkinobu Mita 			      size_t count)
62241da177e4SLinus Torvalds {
622587c715dcSDouglas Gilbert 	bool found;
622687c715dcSDouglas Gilbert 	unsigned long idx;
622787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
622887c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
62291da177e4SLinus Torvalds 	int delta_hosts;
62301da177e4SLinus Torvalds 
6231f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
62321da177e4SLinus Torvalds 		return -EINVAL;
62331da177e4SLinus Torvalds 	if (delta_hosts > 0) {
62341da177e4SLinus Torvalds 		do {
623587c715dcSDouglas Gilbert 			found = false;
623687c715dcSDouglas Gilbert 			if (want_phs) {
623787c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
623887c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
623987c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
624087c715dcSDouglas Gilbert 					found = true;
624187c715dcSDouglas Gilbert 					break;
624287c715dcSDouglas Gilbert 				}
624387c715dcSDouglas Gilbert 				if (found)	/* re-use case */
624487c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
624587c715dcSDouglas Gilbert 				else
624687c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
624787c715dcSDouglas Gilbert 			} else {
624887c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
624987c715dcSDouglas Gilbert 			}
62501da177e4SLinus Torvalds 		} while (--delta_hosts);
62511da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
62521da177e4SLinus Torvalds 		do {
625387c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
62541da177e4SLinus Torvalds 		} while (++delta_hosts);
62551da177e4SLinus Torvalds 	}
62561da177e4SLinus Torvalds 	return count;
62571da177e4SLinus Torvalds }
625882069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
62591da177e4SLinus Torvalds 
626082069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
626123183910SDouglas Gilbert {
6262773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
626323183910SDouglas Gilbert }
626482069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
626582069379SAkinobu Mita 				    size_t count)
626623183910SDouglas Gilbert {
626723183910SDouglas Gilbert 	int n;
626823183910SDouglas Gilbert 
626923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6270773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
627123183910SDouglas Gilbert 		return count;
627223183910SDouglas Gilbert 	}
627323183910SDouglas Gilbert 	return -EINVAL;
627423183910SDouglas Gilbert }
627582069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
627623183910SDouglas Gilbert 
6277c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6278c4837394SDouglas Gilbert {
6279c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6280c4837394SDouglas Gilbert }
6281c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6282c4837394SDouglas Gilbert 				size_t count)
6283c4837394SDouglas Gilbert {
6284c4837394SDouglas Gilbert 	int n;
6285c4837394SDouglas Gilbert 
6286c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6287c4837394SDouglas Gilbert 		if (n > 0)
6288c4837394SDouglas Gilbert 			sdebug_statistics = true;
6289c4837394SDouglas Gilbert 		else {
6290c4837394SDouglas Gilbert 			clear_queue_stats();
6291c4837394SDouglas Gilbert 			sdebug_statistics = false;
6292c4837394SDouglas Gilbert 		}
6293c4837394SDouglas Gilbert 		return count;
6294c4837394SDouglas Gilbert 	}
6295c4837394SDouglas Gilbert 	return -EINVAL;
6296c4837394SDouglas Gilbert }
6297c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6298c4837394SDouglas Gilbert 
629982069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6300597136abSMartin K. Petersen {
6301773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6302597136abSMartin K. Petersen }
630382069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6304597136abSMartin K. Petersen 
6305c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6306c4837394SDouglas Gilbert {
6307c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6308c4837394SDouglas Gilbert }
6309c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6310c4837394SDouglas Gilbert 
631182069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6312c6a44287SMartin K. Petersen {
6313773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6314c6a44287SMartin K. Petersen }
631582069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6316c6a44287SMartin K. Petersen 
631782069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6318c6a44287SMartin K. Petersen {
6319773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6320c6a44287SMartin K. Petersen }
632182069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6322c6a44287SMartin K. Petersen 
632382069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6324c6a44287SMartin K. Petersen {
6325773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6326c6a44287SMartin K. Petersen }
632782069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6328c6a44287SMartin K. Petersen 
632982069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6330c6a44287SMartin K. Petersen {
6331773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6332c6a44287SMartin K. Petersen }
633382069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6334c6a44287SMartin K. Petersen 
633582069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
633644d92694SMartin K. Petersen {
633787c715dcSDouglas Gilbert 	ssize_t count = 0;
633844d92694SMartin K. Petersen 
63395b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
634044d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
634144d92694SMartin K. Petersen 				 sdebug_store_sectors);
634244d92694SMartin K. Petersen 
634387c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
634487c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
634587c715dcSDouglas Gilbert 
634687c715dcSDouglas Gilbert 		if (sip)
6347c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
634887c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
634987c715dcSDouglas Gilbert 	}
635044d92694SMartin K. Petersen 	buf[count++] = '\n';
6351c7badc90STejun Heo 	buf[count] = '\0';
635244d92694SMartin K. Petersen 
635344d92694SMartin K. Petersen 	return count;
635444d92694SMartin K. Petersen }
635582069379SAkinobu Mita static DRIVER_ATTR_RO(map);
635644d92694SMartin K. Petersen 
63570c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
63580c4bc91dSDouglas Gilbert {
63590c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
63600c4bc91dSDouglas Gilbert }
63610c4bc91dSDouglas Gilbert 
63620c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
63630c4bc91dSDouglas Gilbert 			    size_t count)
63640c4bc91dSDouglas Gilbert {
63650c4bc91dSDouglas Gilbert 	bool v;
63660c4bc91dSDouglas Gilbert 
63670c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
63680c4bc91dSDouglas Gilbert 		return -EINVAL;
63690c4bc91dSDouglas Gilbert 
63700c4bc91dSDouglas Gilbert 	sdebug_random = v;
63710c4bc91dSDouglas Gilbert 	return count;
63720c4bc91dSDouglas Gilbert }
63730c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
63740c4bc91dSDouglas Gilbert 
637582069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6376d986788bSMartin Pitt {
6377773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6378d986788bSMartin Pitt }
637982069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
638082069379SAkinobu Mita 			       size_t count)
6381d986788bSMartin Pitt {
6382d986788bSMartin Pitt 	int n;
6383d986788bSMartin Pitt 
6384d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6385773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6386d986788bSMartin Pitt 		return count;
6387d986788bSMartin Pitt 	}
6388d986788bSMartin Pitt 	return -EINVAL;
6389d986788bSMartin Pitt }
639082069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6391d986788bSMartin Pitt 
6392cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6393cbf67842SDouglas Gilbert {
6394773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6395cbf67842SDouglas Gilbert }
6396185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6397cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6398cbf67842SDouglas Gilbert 			       size_t count)
6399cbf67842SDouglas Gilbert {
6400185dd232SDouglas Gilbert 	int n;
6401cbf67842SDouglas Gilbert 
6402cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6403185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6404185dd232SDouglas Gilbert 		return count;
6405cbf67842SDouglas Gilbert 	}
6406cbf67842SDouglas Gilbert 	return -EINVAL;
6407cbf67842SDouglas Gilbert }
6408cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6409cbf67842SDouglas Gilbert 
6410c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6411c2248fc9SDouglas Gilbert {
6412773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6413c2248fc9SDouglas Gilbert }
6414c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6415c2248fc9SDouglas Gilbert 			    size_t count)
6416c2248fc9SDouglas Gilbert {
6417c2248fc9SDouglas Gilbert 	int n;
6418c2248fc9SDouglas Gilbert 
6419c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6420773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6421c2248fc9SDouglas Gilbert 		return count;
6422c2248fc9SDouglas Gilbert 	}
6423c2248fc9SDouglas Gilbert 	return -EINVAL;
6424c2248fc9SDouglas Gilbert }
6425c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6426c2248fc9SDouglas Gilbert 
642709ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
642809ba24c1SDouglas Gilbert {
642909ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
643009ba24c1SDouglas Gilbert }
643109ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
643209ba24c1SDouglas Gilbert 
64339b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
64349b760fd8SDouglas Gilbert {
64359b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
64369b760fd8SDouglas Gilbert }
64379b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
64389b760fd8SDouglas Gilbert 			     size_t count)
64399b760fd8SDouglas Gilbert {
64409b760fd8SDouglas Gilbert 	int ret, n;
64419b760fd8SDouglas Gilbert 
64429b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
64439b760fd8SDouglas Gilbert 	if (ret)
64449b760fd8SDouglas Gilbert 		return ret;
64459b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
64469b760fd8SDouglas Gilbert 	all_config_cdb_len();
64479b760fd8SDouglas Gilbert 	return count;
64489b760fd8SDouglas Gilbert }
64499b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
64509b760fd8SDouglas Gilbert 
64519267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
64529267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
64539267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
64549267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
64559267e0ebSDouglas Gilbert };
64569267e0ebSDouglas Gilbert 
64579267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
64589267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
64599267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
64609267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
64619267e0ebSDouglas Gilbert };
64629267e0ebSDouglas Gilbert 
64639267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
64649267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
64659267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
64669267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
64679267e0ebSDouglas Gilbert };
64689267e0ebSDouglas Gilbert 
64699267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
64709267e0ebSDouglas Gilbert {
64719267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
64729267e0ebSDouglas Gilbert 
64739267e0ebSDouglas Gilbert 	if (res < 0) {
64749267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
64759267e0ebSDouglas Gilbert 		if (res < 0) {
64769267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
647747742bdeSDan Carpenter 			if (res < 0)
64789267e0ebSDouglas Gilbert 				return -EINVAL;
64799267e0ebSDouglas Gilbert 		}
64809267e0ebSDouglas Gilbert 	}
64819267e0ebSDouglas Gilbert 	return res;
64829267e0ebSDouglas Gilbert }
64839267e0ebSDouglas Gilbert 
64849267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
64859267e0ebSDouglas Gilbert {
64869267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
64879267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
64889267e0ebSDouglas Gilbert }
64899267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6490cbf67842SDouglas Gilbert 
649182069379SAkinobu Mita /* Note: The following array creates attribute files in the
649223183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
649323183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
649423183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
649587c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
649623183910SDouglas Gilbert  */
64976ecaff7fSRandy Dunlap 
649882069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
649982069379SAkinobu Mita 	&driver_attr_delay.attr,
650082069379SAkinobu Mita 	&driver_attr_opts.attr,
650182069379SAkinobu Mita 	&driver_attr_ptype.attr,
650282069379SAkinobu Mita 	&driver_attr_dsense.attr,
650382069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6504c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
650582069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
650682069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
650782069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
650882069379SAkinobu Mita 	&driver_attr_num_parts.attr,
650982069379SAkinobu Mita 	&driver_attr_every_nth.attr,
651082069379SAkinobu Mita 	&driver_attr_max_luns.attr,
651182069379SAkinobu Mita 	&driver_attr_max_queue.attr,
651282069379SAkinobu Mita 	&driver_attr_no_uld.attr,
651382069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
651482069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
651582069379SAkinobu Mita 	&driver_attr_add_host.attr,
651687c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
651782069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
651882069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6519c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6520c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
652182069379SAkinobu Mita 	&driver_attr_dix.attr,
652282069379SAkinobu Mita 	&driver_attr_dif.attr,
652382069379SAkinobu Mita 	&driver_attr_guard.attr,
652482069379SAkinobu Mita 	&driver_attr_ato.attr,
652582069379SAkinobu Mita 	&driver_attr_map.attr,
65260c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
652782069379SAkinobu Mita 	&driver_attr_removable.attr,
6528cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6529cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6530c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
653109ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
65329b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
65339267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
653482069379SAkinobu Mita 	NULL,
653582069379SAkinobu Mita };
653682069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
65371da177e4SLinus Torvalds 
653811ddcecaSAkinobu Mita static struct device *pseudo_primary;
65398dea0d02SFUJITA Tomonori 
65401da177e4SLinus Torvalds static int __init scsi_debug_init(void)
65411da177e4SLinus Torvalds {
654287c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
65435f2578e5SFUJITA Tomonori 	unsigned long sz;
654487c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
654587c715dcSDouglas Gilbert 	int idx = -1;
65461da177e4SLinus Torvalds 
654787c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
654887c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6549cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6550cbf67842SDouglas Gilbert 
6551773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6552c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6553773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6554773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6555c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6556cbf67842SDouglas Gilbert 
6557773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6558597136abSMartin K. Petersen 	case  512:
6559597136abSMartin K. Petersen 	case 1024:
6560597136abSMartin K. Petersen 	case 2048:
6561597136abSMartin K. Petersen 	case 4096:
6562597136abSMartin K. Petersen 		break;
6563597136abSMartin K. Petersen 	default:
6564773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6565597136abSMartin K. Petersen 		return -EINVAL;
6566597136abSMartin K. Petersen 	}
6567597136abSMartin K. Petersen 
6568773642d9SDouglas Gilbert 	switch (sdebug_dif) {
65698475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6570f46eb0e9SDouglas Gilbert 		break;
65718475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
65728475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
65738475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6574f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6575c6a44287SMartin K. Petersen 		break;
6576c6a44287SMartin K. Petersen 
6577c6a44287SMartin K. Petersen 	default:
6578c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6579c6a44287SMartin K. Petersen 		return -EINVAL;
6580c6a44287SMartin K. Petersen 	}
6581c6a44287SMartin K. Petersen 
6582aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6583aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6584aa5334c4SMaurizio Lombardi 		return -EINVAL;
6585aa5334c4SMaurizio Lombardi 	}
6586aa5334c4SMaurizio Lombardi 
6587773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6588c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6589c6a44287SMartin K. Petersen 		return -EINVAL;
6590c6a44287SMartin K. Petersen 	}
6591c6a44287SMartin K. Petersen 
6592773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6593c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6594c6a44287SMartin K. Petersen 		return -EINVAL;
6595c6a44287SMartin K. Petersen 	}
6596c6a44287SMartin K. Petersen 
6597773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6598773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6599ea61fca5SMartin K. Petersen 		return -EINVAL;
6600ea61fca5SMartin K. Petersen 	}
66018d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
66028d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
66038d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
66048d039e22SDouglas Gilbert 	}
6605ea61fca5SMartin K. Petersen 
6606773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6607773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6608ea61fca5SMartin K. Petersen 		return -EINVAL;
6609ea61fca5SMartin K. Petersen 	}
6610ea61fca5SMartin K. Petersen 
6611c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6612c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6613c4837394SDouglas Gilbert 		return -EINVAL;
6614c4837394SDouglas Gilbert 	}
6615c87bf24cSJohn Garry 
6616c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6617c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6618c87bf24cSJohn Garry 		return -EINVAL;
6619c87bf24cSJohn Garry 	}
6620c87bf24cSJohn Garry 
6621c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6622c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6623c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6624c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6625c10fa55fSJohn Garry 		return -EINVAL;
6626c10fa55fSJohn Garry 	}
6627c10fa55fSJohn Garry 
6628c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6629c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6630c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6631c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6632c10fa55fSJohn Garry 			sdebug_max_queue);
6633c10fa55fSJohn Garry 	}
6634c10fa55fSJohn Garry 
6635c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6636c4837394SDouglas Gilbert 			       GFP_KERNEL);
6637c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6638c4837394SDouglas Gilbert 		return -ENOMEM;
6639c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6640c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6641c4837394SDouglas Gilbert 
6642f0d1cf93SDouglas Gilbert 	/*
66439267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
66449267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6645f0d1cf93SDouglas Gilbert 	 */
66469267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
66479267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
66489267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
66499267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
66509267e0ebSDouglas Gilbert 		if (k < 0) {
66519267e0ebSDouglas Gilbert 			ret = k;
66529267e0ebSDouglas Gilbert 			goto free_vm;
66539267e0ebSDouglas Gilbert 		}
66549267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
66559267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
66569267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
665764e14eceSDamien Le Moal 		case BLK_ZONED_HA:
66589267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
66599267e0ebSDouglas Gilbert 			break;
66609267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
66619267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
66629267e0ebSDouglas Gilbert 			break;
66639267e0ebSDouglas Gilbert 		default:
66649267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
66659267e0ebSDouglas Gilbert 			return -EINVAL;
66669267e0ebSDouglas Gilbert 		}
66679267e0ebSDouglas Gilbert 	}
66689267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6669f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
66709267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
66719267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
66729267e0ebSDouglas Gilbert 	}
6673f0d1cf93SDouglas Gilbert 
66749267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
66759267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6676773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6677773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6678773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6679773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
668028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
66811da177e4SLinus Torvalds 
66821da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
66831da177e4SLinus Torvalds 	sdebug_heads = 8;
66841da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6685773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
66861da177e4SLinus Torvalds 		sdebug_heads = 64;
6687773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6688fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
66891da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
66901da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
66911da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
66921da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
66931da177e4SLinus Torvalds 		sdebug_heads = 255;
66941da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
66951da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
66961da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
66971da177e4SLinus Torvalds 	}
66985b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6699773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6700773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
67016014759cSMartin K. Petersen 
6702773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6703773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
67046014759cSMartin K. Petersen 
6705773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6706773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
67076014759cSMartin K. Petersen 
6708773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6709773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6710773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6711c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6712c4837394SDouglas Gilbert 			ret = -EINVAL;
671387c715dcSDouglas Gilbert 			goto free_q_arr;
671444d92694SMartin K. Petersen 		}
671544d92694SMartin K. Petersen 	}
671687c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
671787c715dcSDouglas Gilbert 	if (want_store) {
671887c715dcSDouglas Gilbert 		idx = sdebug_add_store();
671987c715dcSDouglas Gilbert 		if (idx < 0) {
672087c715dcSDouglas Gilbert 			ret = idx;
672187c715dcSDouglas Gilbert 			goto free_q_arr;
672287c715dcSDouglas Gilbert 		}
672344d92694SMartin K. Petersen 	}
672444d92694SMartin K. Petersen 
67259b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
67269b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6727c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
67289b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
67296ecaff7fSRandy Dunlap 		goto free_vm;
67306ecaff7fSRandy Dunlap 	}
67316ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
67326ecaff7fSRandy Dunlap 	if (ret < 0) {
6733c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
67346ecaff7fSRandy Dunlap 		goto dev_unreg;
67356ecaff7fSRandy Dunlap 	}
67366ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
67376ecaff7fSRandy Dunlap 	if (ret < 0) {
6738c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
67396ecaff7fSRandy Dunlap 		goto bus_unreg;
67406ecaff7fSRandy Dunlap 	}
67411da177e4SLinus Torvalds 
674287c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6743773642d9SDouglas Gilbert 	sdebug_add_host = 0;
67441da177e4SLinus Torvalds 
674587c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
674687c715dcSDouglas Gilbert 		if (want_store && k == 0) {
674787c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
674887c715dcSDouglas Gilbert 			if (ret < 0) {
674987c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
675087c715dcSDouglas Gilbert 				       k, -ret);
675187c715dcSDouglas Gilbert 				break;
675287c715dcSDouglas Gilbert 			}
675387c715dcSDouglas Gilbert 		} else {
675487c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
675587c715dcSDouglas Gilbert 						 sdebug_per_host_store);
675687c715dcSDouglas Gilbert 			if (ret < 0) {
675787c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
67581da177e4SLinus Torvalds 				break;
67591da177e4SLinus Torvalds 			}
67601da177e4SLinus Torvalds 		}
676187c715dcSDouglas Gilbert 	}
6762773642d9SDouglas Gilbert 	if (sdebug_verbose)
676387c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6764c1287970STomas Winkler 
67651da177e4SLinus Torvalds 	return 0;
67666ecaff7fSRandy Dunlap 
67676ecaff7fSRandy Dunlap bus_unreg:
67686ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
67696ecaff7fSRandy Dunlap dev_unreg:
67709b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
67716ecaff7fSRandy Dunlap free_vm:
677287c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6773c4837394SDouglas Gilbert free_q_arr:
6774c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
67756ecaff7fSRandy Dunlap 	return ret;
67761da177e4SLinus Torvalds }
67771da177e4SLinus Torvalds 
67781da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
67791da177e4SLinus Torvalds {
678087c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
67811da177e4SLinus Torvalds 
67821da177e4SLinus Torvalds 	stop_all_queued();
67831da177e4SLinus Torvalds 	for (; k; k--)
678487c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
678552ab9768SLuis Henriques 	free_all_queued();
67861da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
67871da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
67889b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
67891da177e4SLinus Torvalds 
679087c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
679187c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
67921da177e4SLinus Torvalds }
67931da177e4SLinus Torvalds 
67941da177e4SLinus Torvalds device_initcall(scsi_debug_init);
67951da177e4SLinus Torvalds module_exit(scsi_debug_exit);
67961da177e4SLinus Torvalds 
67971da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
67981da177e4SLinus Torvalds {
67991da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
68001da177e4SLinus Torvalds 
68011da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
68021da177e4SLinus Torvalds 	kfree(sdbg_host);
68031da177e4SLinus Torvalds }
68041da177e4SLinus Torvalds 
680587c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
680687c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
68071da177e4SLinus Torvalds {
680887c715dcSDouglas Gilbert 	if (idx < 0)
680987c715dcSDouglas Gilbert 		return;
681087c715dcSDouglas Gilbert 	if (!sip) {
681187c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
681287c715dcSDouglas Gilbert 			return;
681387c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
681487c715dcSDouglas Gilbert 		if (!sip)
681587c715dcSDouglas Gilbert 			return;
681687c715dcSDouglas Gilbert 	}
681787c715dcSDouglas Gilbert 	vfree(sip->map_storep);
681887c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
681987c715dcSDouglas Gilbert 	vfree(sip->storep);
682087c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
682187c715dcSDouglas Gilbert 	kfree(sip);
682287c715dcSDouglas Gilbert }
682387c715dcSDouglas Gilbert 
682487c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
682587c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
682687c715dcSDouglas Gilbert {
682787c715dcSDouglas Gilbert 	unsigned long idx;
682887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
682987c715dcSDouglas Gilbert 
683087c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
683187c715dcSDouglas Gilbert 		if (apart_from_first)
683287c715dcSDouglas Gilbert 			apart_from_first = false;
683387c715dcSDouglas Gilbert 		else
683487c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
683587c715dcSDouglas Gilbert 	}
683687c715dcSDouglas Gilbert 	if (apart_from_first)
683787c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
683887c715dcSDouglas Gilbert }
683987c715dcSDouglas Gilbert 
684087c715dcSDouglas Gilbert /*
684187c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
684287c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
684387c715dcSDouglas Gilbert  */
684487c715dcSDouglas Gilbert static int sdebug_add_store(void)
684587c715dcSDouglas Gilbert {
684687c715dcSDouglas Gilbert 	int res;
684787c715dcSDouglas Gilbert 	u32 n_idx;
684887c715dcSDouglas Gilbert 	unsigned long iflags;
684987c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
685087c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
685187c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
685287c715dcSDouglas Gilbert 
685387c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
685487c715dcSDouglas Gilbert 	if (!sip)
685587c715dcSDouglas Gilbert 		return -ENOMEM;
685687c715dcSDouglas Gilbert 
685787c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
685887c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
685987c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
686087c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
686187c715dcSDouglas Gilbert 		kfree(sip);
686287c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
686387c715dcSDouglas Gilbert 		return res;
686487c715dcSDouglas Gilbert 	}
686587c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
686687c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
686787c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
686887c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
686987c715dcSDouglas Gilbert 
687087c715dcSDouglas Gilbert 	res = -ENOMEM;
687187c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
687287c715dcSDouglas Gilbert 	if (!sip->storep) {
687387c715dcSDouglas Gilbert 		pr_err("user data oom\n");
687487c715dcSDouglas Gilbert 		goto err;
687587c715dcSDouglas Gilbert 	}
687687c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
687787c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
687887c715dcSDouglas Gilbert 
687987c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
688087c715dcSDouglas Gilbert 	if (sdebug_dix) {
688187c715dcSDouglas Gilbert 		int dif_size;
688287c715dcSDouglas Gilbert 
688387c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
688487c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
688587c715dcSDouglas Gilbert 
688687c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
688787c715dcSDouglas Gilbert 			sip->dif_storep);
688887c715dcSDouglas Gilbert 
688987c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
689087c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
689187c715dcSDouglas Gilbert 			goto err;
689287c715dcSDouglas Gilbert 		}
689387c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
689487c715dcSDouglas Gilbert 	}
689587c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
689687c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
689787c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
689887c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
689987c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
690087c715dcSDouglas Gilbert 
690187c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
690287c715dcSDouglas Gilbert 
690387c715dcSDouglas Gilbert 		if (!sip->map_storep) {
690487c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
690587c715dcSDouglas Gilbert 			goto err;
690687c715dcSDouglas Gilbert 		}
690787c715dcSDouglas Gilbert 
690887c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
690987c715dcSDouglas Gilbert 
691087c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
691187c715dcSDouglas Gilbert 		if (sdebug_num_parts)
691287c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
691387c715dcSDouglas Gilbert 	}
691487c715dcSDouglas Gilbert 
691587c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
691687c715dcSDouglas Gilbert 	return (int)n_idx;
691787c715dcSDouglas Gilbert err:
691887c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
691987c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
692087c715dcSDouglas Gilbert 	return res;
692187c715dcSDouglas Gilbert }
692287c715dcSDouglas Gilbert 
692387c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
692487c715dcSDouglas Gilbert {
692587c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
692687c715dcSDouglas Gilbert 	int error = -ENOMEM;
69271da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
69288b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
69291da177e4SLinus Torvalds 
693024669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
693187c715dcSDouglas Gilbert 	if (!sdbg_host)
69321da177e4SLinus Torvalds 		return -ENOMEM;
693387c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
693487c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
693587c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
693687c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
69371da177e4SLinus Torvalds 
69381da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
69391da177e4SLinus Torvalds 
6940773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
69411da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
69425cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
694387c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
69441da177e4SLinus Torvalds 			goto clean;
69451da177e4SLinus Torvalds 	}
69461da177e4SLinus Torvalds 
69471da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
69481da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
69491da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
69501da177e4SLinus Torvalds 
69511da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
69529b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
69531da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
695487c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
69551da177e4SLinus Torvalds 
69561da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
69571da177e4SLinus Torvalds 	if (error)
69581da177e4SLinus Torvalds 		goto clean;
69591da177e4SLinus Torvalds 
696087c715dcSDouglas Gilbert 	++sdebug_num_hosts;
696187c715dcSDouglas Gilbert 	return 0;
69621da177e4SLinus Torvalds 
69631da177e4SLinus Torvalds clean:
69648b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
69658b40228fSFUJITA Tomonori 				 dev_list) {
69661da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
6967f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
69681da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
69691da177e4SLinus Torvalds 	}
69701da177e4SLinus Torvalds 	kfree(sdbg_host);
697187c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
69721da177e4SLinus Torvalds 	return error;
69731da177e4SLinus Torvalds }
69741da177e4SLinus Torvalds 
697587c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
69761da177e4SLinus Torvalds {
697787c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
697887c715dcSDouglas Gilbert 
697987c715dcSDouglas Gilbert 	if (mk_new_store) {
698087c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
698187c715dcSDouglas Gilbert 		if (ph_idx < 0)
698287c715dcSDouglas Gilbert 			return ph_idx;
698387c715dcSDouglas Gilbert 	}
698487c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
698587c715dcSDouglas Gilbert }
698687c715dcSDouglas Gilbert 
698787c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
698887c715dcSDouglas Gilbert {
698987c715dcSDouglas Gilbert 	int idx = -1;
69901da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
699187c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
69921da177e4SLinus Torvalds 
69931da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
69941da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
69951da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
69961da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
699787c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
69981da177e4SLinus Torvalds 	}
699987c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
700087c715dcSDouglas Gilbert 		bool unique = true;
700187c715dcSDouglas Gilbert 
700287c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
700387c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
700487c715dcSDouglas Gilbert 				continue;
700587c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
700687c715dcSDouglas Gilbert 				unique = false;
700787c715dcSDouglas Gilbert 				break;
700887c715dcSDouglas Gilbert 			}
700987c715dcSDouglas Gilbert 		}
701087c715dcSDouglas Gilbert 		if (unique) {
701187c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
701287c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
701387c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
701487c715dcSDouglas Gilbert 		}
701587c715dcSDouglas Gilbert 	}
701687c715dcSDouglas Gilbert 	if (sdbg_host)
701787c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
70181da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
70191da177e4SLinus Torvalds 
70201da177e4SLinus Torvalds 	if (!sdbg_host)
70211da177e4SLinus Torvalds 		return;
70221da177e4SLinus Torvalds 
70231da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
702487c715dcSDouglas Gilbert 	--sdebug_num_hosts;
70251da177e4SLinus Torvalds }
70261da177e4SLinus Torvalds 
7027fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7028cbf67842SDouglas Gilbert {
7029cbf67842SDouglas Gilbert 	int num_in_q = 0;
7030cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
7031cbf67842SDouglas Gilbert 
7032c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
7033cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
7034cbf67842SDouglas Gilbert 	if (NULL == devip) {
7035c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
7036cbf67842SDouglas Gilbert 		return	-ENODEV;
7037cbf67842SDouglas Gilbert 	}
7038cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7039c40ecc12SChristoph Hellwig 
7040cbf67842SDouglas Gilbert 	if (qdepth < 1)
7041cbf67842SDouglas Gilbert 		qdepth = 1;
7042c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
7043c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
7044c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
7045db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
7046cbf67842SDouglas Gilbert 
7047773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7048c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7049c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7050cbf67842SDouglas Gilbert 	}
7051c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
7052cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7053cbf67842SDouglas Gilbert }
7054cbf67842SDouglas Gilbert 
7055c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7056817fd66bSDouglas Gilbert {
7057c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7058773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7059773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7060773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7061c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7062773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7063817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7064c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7065817fd66bSDouglas Gilbert 	}
7066c4837394SDouglas Gilbert 	return false;
7067817fd66bSDouglas Gilbert }
7068817fd66bSDouglas Gilbert 
7069fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7070fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7071c2248fc9SDouglas Gilbert {
7072c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7073c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7074c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7075c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7076c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7077c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7078c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7079f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7080c2248fc9SDouglas Gilbert 	int k, na;
7081c2248fc9SDouglas Gilbert 	int errsts = 0;
7082c2248fc9SDouglas Gilbert 	u32 flags;
7083c2248fc9SDouglas Gilbert 	u16 sa;
7084c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7085c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
70863a90a63dSDouglas Gilbert 	bool inject_now;
7087c2248fc9SDouglas Gilbert 
7088c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
70893a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7090c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
70913a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
70923a90a63dSDouglas Gilbert 	} else {
70933a90a63dSDouglas Gilbert 		inject_now = false;
70943a90a63dSDouglas Gilbert 	}
7095f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7096f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7097c2248fc9SDouglas Gilbert 		char b[120];
7098c2248fc9SDouglas Gilbert 		int n, len, sb;
7099c2248fc9SDouglas Gilbert 
7100c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7101c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7102c2248fc9SDouglas Gilbert 		if (len > 32)
7103c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7104c2248fc9SDouglas Gilbert 		else {
7105c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7106c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7107c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7108c2248fc9SDouglas Gilbert 		}
7109458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7110458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
7111c2248fc9SDouglas Gilbert 	}
71123a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
71137ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
711434d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7115f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
7116f46eb0e9SDouglas Gilbert 		goto err_out;
7117c2248fc9SDouglas Gilbert 
7118c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7119c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7120c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7121f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7122f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7123c2248fc9SDouglas Gilbert 		if (NULL == devip)
7124f46eb0e9SDouglas Gilbert 			goto err_out;
7125c2248fc9SDouglas Gilbert 	}
71263a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
71273a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
71283a90a63dSDouglas Gilbert 
7129c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7130c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7131c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7132c2248fc9SDouglas Gilbert 		r_oip = oip;
7133c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7134c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7135c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7136c2248fc9SDouglas Gilbert 			else
7137c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7138c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7139c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7140c2248fc9SDouglas Gilbert 					break;
7141c2248fc9SDouglas Gilbert 			}
7142c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7143c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7144c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7145c2248fc9SDouglas Gilbert 					break;
7146c2248fc9SDouglas Gilbert 			}
7147c2248fc9SDouglas Gilbert 		}
7148c2248fc9SDouglas Gilbert 		if (k > na) {
7149c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7150c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7151c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7152c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7153c2248fc9SDouglas Gilbert 			else
7154c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7155c2248fc9SDouglas Gilbert 			goto check_cond;
7156c2248fc9SDouglas Gilbert 		}
7157c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7158c2248fc9SDouglas Gilbert 	flags = oip->flags;
7159f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7160c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7161c2248fc9SDouglas Gilbert 		goto check_cond;
7162c2248fc9SDouglas Gilbert 	}
7163f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7164773642d9SDouglas Gilbert 		if (sdebug_verbose)
7165773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7166773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7167c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7168c2248fc9SDouglas Gilbert 		goto check_cond;
7169c2248fc9SDouglas Gilbert 	}
7170f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7171c2248fc9SDouglas Gilbert 		u8 rem;
7172c2248fc9SDouglas Gilbert 		int j;
7173c2248fc9SDouglas Gilbert 
7174c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7175c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7176c2248fc9SDouglas Gilbert 			if (rem) {
7177c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7178c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7179c2248fc9SDouglas Gilbert 						break;
7180c2248fc9SDouglas Gilbert 				}
7181c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7182c2248fc9SDouglas Gilbert 				goto check_cond;
7183c2248fc9SDouglas Gilbert 			}
7184c2248fc9SDouglas Gilbert 		}
7185c2248fc9SDouglas Gilbert 	}
7186f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7187b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7188b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7189f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7190c2248fc9SDouglas Gilbert 		if (errsts)
7191c2248fc9SDouglas Gilbert 			goto check_cond;
7192c2248fc9SDouglas Gilbert 	}
7193c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
7194c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7195773642d9SDouglas Gilbert 		if (sdebug_verbose)
7196c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
7197c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
7198c2248fc9SDouglas Gilbert 				    "required");
7199c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
7200c2248fc9SDouglas Gilbert 		goto fini;
7201c2248fc9SDouglas Gilbert 	}
7202773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7203c2248fc9SDouglas Gilbert 		goto fini;
7204f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7205c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7206c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7207c2248fc9SDouglas Gilbert 	}
7208f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7209f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7210f66b8517SMartin Wilck 	else
7211f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7212c2248fc9SDouglas Gilbert 
7213c2248fc9SDouglas Gilbert fini:
721467da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7215f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
721675aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
721775aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
721880c49563SDouglas Gilbert 		/*
721975aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
722075aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
722175aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
722275aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
722380c49563SDouglas Gilbert 		 */
722480c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
72254f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
722680c49563SDouglas Gilbert 
72274f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7228f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
722980c49563SDouglas Gilbert 	} else
7230f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
723110bde980SDouglas Gilbert 				     sdebug_ndelay);
7232c2248fc9SDouglas Gilbert check_cond:
7233f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7234f46eb0e9SDouglas Gilbert err_out:
7235f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7236c2248fc9SDouglas Gilbert }
7237c2248fc9SDouglas Gilbert 
72389e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7239c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7240c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
72419e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
72429e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
72439e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
72449e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
72459e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
72469e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
72479e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7248185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7249cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
72509e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
72519e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7252cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7253cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
72549e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7255c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
72569e603ca0SFUJITA Tomonori 	.this_id =		7,
725765e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7258cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
72596bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
726050c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
72619e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7262c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
72639e603ca0SFUJITA Tomonori };
72649e603ca0SFUJITA Tomonori 
72651da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
72661da177e4SLinus Torvalds {
72671da177e4SLinus Torvalds 	int error = 0;
72681da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72691da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7270f46eb0e9SDouglas Gilbert 	int hprot;
72711da177e4SLinus Torvalds 
72721da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
72731da177e4SLinus Torvalds 
7274c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
7275c10fa55fSJohn Garry 		sdebug_driver_template.can_queue = sdebug_host_max_queue;
7276c10fa55fSJohn Garry 	else
7277773642d9SDouglas Gilbert 		sdebug_driver_template.can_queue = sdebug_max_queue;
72782a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
72794af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
72804af14d11SChristoph Hellwig 
72811da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
72821da177e4SLinus Torvalds 	if (NULL == hpnt) {
7283c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
72841da177e4SLinus Torvalds 		error = -ENODEV;
72851da177e4SLinus Torvalds 		return error;
72861da177e4SLinus Torvalds 	}
7287c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
72889b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7289c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7290c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7291c4837394SDouglas Gilbert 	}
7292c10fa55fSJohn Garry 	/*
7293c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7294c10fa55fSJohn Garry 	 * following should give the same answer for each host. If the host
7295c10fa55fSJohn Garry 	 * has a limit of hostwide max commands, then do not set.
7296c10fa55fSJohn Garry 	 */
7297c10fa55fSJohn Garry 	if (!sdebug_host_max_queue)
7298c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
72991da177e4SLinus Torvalds 
73001da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
73011da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7302773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7303773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
73041da177e4SLinus Torvalds 	else
7305773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7306773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7307f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
73081da177e4SLinus Torvalds 
7309f46eb0e9SDouglas Gilbert 	hprot = 0;
7310c6a44287SMartin K. Petersen 
7311773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7312c6a44287SMartin K. Petersen 
73138475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7314f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7315773642d9SDouglas Gilbert 		if (sdebug_dix)
7316f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7317c6a44287SMartin K. Petersen 		break;
7318c6a44287SMartin K. Petersen 
73198475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7320f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7321773642d9SDouglas Gilbert 		if (sdebug_dix)
7322f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7323c6a44287SMartin K. Petersen 		break;
7324c6a44287SMartin K. Petersen 
73258475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7326f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7327773642d9SDouglas Gilbert 		if (sdebug_dix)
7328f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7329c6a44287SMartin K. Petersen 		break;
7330c6a44287SMartin K. Petersen 
7331c6a44287SMartin K. Petersen 	default:
7332773642d9SDouglas Gilbert 		if (sdebug_dix)
7333f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7334c6a44287SMartin K. Petersen 		break;
7335c6a44287SMartin K. Petersen 	}
7336c6a44287SMartin K. Petersen 
7337f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7338c6a44287SMartin K. Petersen 
7339f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7340c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7341f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7342f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7343f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7344f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7345f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7346f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7347f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7348c6a44287SMartin K. Petersen 
7349773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7350c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7351c6a44287SMartin K. Petersen 	else
7352c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7353c6a44287SMartin K. Petersen 
7354773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7355773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7356c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7357c4837394SDouglas Gilbert 		sdebug_statistics = true;
73581da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
73591da177e4SLinus Torvalds 	if (error) {
7360c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
73611da177e4SLinus Torvalds 		error = -ENODEV;
73621da177e4SLinus Torvalds 		scsi_host_put(hpnt);
736387c715dcSDouglas Gilbert 	} else {
73641da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
736587c715dcSDouglas Gilbert 	}
73661da177e4SLinus Torvalds 
73671da177e4SLinus Torvalds 	return error;
73681da177e4SLinus Torvalds }
73691da177e4SLinus Torvalds 
73701da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
73711da177e4SLinus Torvalds {
73721da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
73738b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
73741da177e4SLinus Torvalds 
73751da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
73761da177e4SLinus Torvalds 
73771da177e4SLinus Torvalds 	if (!sdbg_host) {
7378c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
73791da177e4SLinus Torvalds 		return -ENODEV;
73801da177e4SLinus Torvalds 	}
73811da177e4SLinus Torvalds 
73821da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
73831da177e4SLinus Torvalds 
73848b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73858b40228fSFUJITA Tomonori 				 dev_list) {
73861da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7387f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73881da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73891da177e4SLinus Torvalds 	}
73901da177e4SLinus Torvalds 
73911da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
73921da177e4SLinus Torvalds 	return 0;
73931da177e4SLinus Torvalds }
73941da177e4SLinus Torvalds 
73958dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
73968dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
73971da177e4SLinus Torvalds {
73988dea0d02SFUJITA Tomonori 	return 1;
73998dea0d02SFUJITA Tomonori }
74001da177e4SLinus Torvalds 
74018dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
74028dea0d02SFUJITA Tomonori 	.name = "pseudo",
74038dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
74048dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
74058dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
740682069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
74078dea0d02SFUJITA Tomonori };
7408