xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 9267e0eb)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
51da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
61da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
71da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
81da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91da177e4SLinus Torvalds  *
1048e3bf16SDouglas Gilbert  * Copyright (C) 2001 - 2020 Douglas Gilbert
111da177e4SLinus Torvalds  *
1278d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/genhd.h>
271da177e4SLinus Torvalds #include <linux/fs.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/vmalloc.h>
311da177e4SLinus Torvalds #include <linux/moduleparam.h>
32852e034dSJens Axboe #include <linux/scatterlist.h>
331da177e4SLinus Torvalds #include <linux/blkdev.h>
34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
35cbf67842SDouglas Gilbert #include <linux/spinlock.h>
36cbf67842SDouglas Gilbert #include <linux/interrupt.h>
37cbf67842SDouglas Gilbert #include <linux/atomic.h>
38cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3909ba24c1SDouglas Gilbert #include <linux/uuid.h>
406ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
411442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
420c4bc91dSDouglas Gilbert #include <linux/random.h>
4387c715dcSDouglas Gilbert #include <linux/xarray.h>
44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6348e3bf16SDouglas Gilbert #define SDEBUG_VERSION "0189"	/* format to fit INQUIRY revision field */
6448e3bf16SDouglas Gilbert static const char *sdebug_version_date = "20200421";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
101f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1021da177e4SLinus Torvalds 
1036f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1046f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1056f3cbf55SDouglas Gilbert 
1061da177e4SLinus Torvalds /* Default values for driver parameters */
1071da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1081da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1091da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1111da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1121da177e4SLinus Torvalds  */
1135b94e232SMartin K. Petersen #define DEF_ATO 1
1149b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
115c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1169267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1171da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1189267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1195b94e232SMartin K. Petersen #define DEF_DIF 0
1205b94e232SMartin K. Petersen #define DEF_DIX 0
12187c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1225b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1231da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1245b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1255b94e232SMartin K. Petersen #define DEF_GUARD 0
126cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1275b94e232SMartin K. Petersen #define DEF_LBPU 0
1285b94e232SMartin K. Petersen #define DEF_LBPWS 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS10 0
130be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1315b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
132cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1335b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1341da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1351da177e4SLinus Torvalds #define DEF_OPTS   0
13632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1375b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
139b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1400c4bc91dSDouglas Gilbert #define DEF_RANDOM false
141d986788bSMartin Pitt #define DEF_REMOVABLE false
142760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1435b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1445b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1455b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1466014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1485b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1495b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1505b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
151c2248fc9SDouglas Gilbert #define DEF_STRICT 0
152c4837394SDouglas Gilbert #define DEF_STATISTICS false
153c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
15409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
155c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1561da177e4SLinus Torvalds 
157f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
158f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
159f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
160f0d1cf93SDouglas Gilbert 
161b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
162b01f6f83SDouglas Gilbert 
163773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
164773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
165773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
166773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
167773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
168773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
169773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
170773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
171773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
172773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
173773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
174773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
175773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
176773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
177773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
178773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1797ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1807382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
181773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
182773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
183773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
184773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
185773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1867ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1877382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1887382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1891da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
190fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1911da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
192773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1936f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
194773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1957382f9d8SDouglas Gilbert  *   - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
1967382f9d8SDouglas Gilbert  *     CMD_ABORT
1971da177e4SLinus Torvalds  *
1987382f9d8SDouglas Gilbert  * When "every_nth" < 0 then after "- every_nth" commands the selected
1997382f9d8SDouglas Gilbert  * error will be injected. The error will be injected on every subsequent
2007382f9d8SDouglas Gilbert  * command until some other action occurs; for example, the user writing
2017382f9d8SDouglas Gilbert  * a new value (other than -1 or 1) to every_nth:
2027382f9d8SDouglas Gilbert  *      echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
2031da177e4SLinus Torvalds  */
2041da177e4SLinus Torvalds 
205cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
206cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
207cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
208cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
209cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
210cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
211cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2120d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
21319c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
214acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
215acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
216acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
217cbf67842SDouglas Gilbert 
218773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2191da177e4SLinus Torvalds  * sector on read commands: */
2201da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
22132f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2241da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2251da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2261da177e4SLinus Torvalds 
227c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
228c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
229c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
230c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
231c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
232c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
233c4837394SDouglas Gilbert  */
234c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
235c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
236cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
237cbf67842SDouglas Gilbert 
238fd32119bSDouglas Gilbert #define F_D_IN			1
239fd32119bSDouglas Gilbert #define F_D_OUT			2
240fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
241fd32119bSDouglas Gilbert #define F_D_UNKN		8
242fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
243fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
244fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
245fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
246fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
247fd32119bSDouglas Gilbert #define F_INV_OP		0x200
248fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
249fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
2504f2c8bf6SDouglas Gilbert #define F_SSU_DELAY		0x1000
2514f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY		0x2000
252fd32119bSDouglas Gilbert 
253fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
25446f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
255fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2564f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
257fd32119bSDouglas Gilbert 
258fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
259fd32119bSDouglas Gilbert 
260b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
261fd32119bSDouglas Gilbert 
26287c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
26387c715dcSDouglas Gilbert 
264f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
265f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
266f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
267f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
268f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
269f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
270f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
271f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
272f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
273f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
274f0d1cf93SDouglas Gilbert };
275f0d1cf93SDouglas Gilbert 
276f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
277f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
278f0d1cf93SDouglas Gilbert 	unsigned int z_size;
279f0d1cf93SDouglas Gilbert 	sector_t z_start;
280f0d1cf93SDouglas Gilbert 	sector_t z_wp;
281f0d1cf93SDouglas Gilbert };
282fd32119bSDouglas Gilbert 
283fd32119bSDouglas Gilbert struct sdebug_dev_info {
284fd32119bSDouglas Gilbert 	struct list_head dev_list;
285fd32119bSDouglas Gilbert 	unsigned int channel;
286fd32119bSDouglas Gilbert 	unsigned int target;
287fd32119bSDouglas Gilbert 	u64 lun;
288bf476433SChristoph Hellwig 	uuid_t lu_name;
289fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
290fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
291fd32119bSDouglas Gilbert 	atomic_t num_in_q;
292c4837394SDouglas Gilbert 	atomic_t stopped;
293fd32119bSDouglas Gilbert 	bool used;
294f0d1cf93SDouglas Gilbert 
295f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
296f0d1cf93SDouglas Gilbert 	unsigned int zsize;
297f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
298f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
299f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
300f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
301f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
302f0d1cf93SDouglas Gilbert 	unsigned int max_open;
303f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
304fd32119bSDouglas Gilbert };
305fd32119bSDouglas Gilbert 
306fd32119bSDouglas Gilbert struct sdebug_host_info {
307fd32119bSDouglas Gilbert 	struct list_head host_list;
30887c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
309fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
310fd32119bSDouglas Gilbert 	struct device dev;
311fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
312fd32119bSDouglas Gilbert };
313fd32119bSDouglas Gilbert 
31487c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
31587c715dcSDouglas Gilbert struct sdeb_store_info {
31687c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
31787c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
31887c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
31987c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32087c715dcSDouglas Gilbert };
32187c715dcSDouglas Gilbert 
322fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
323fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
324fd32119bSDouglas Gilbert 
32510bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
32610bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
32710bde980SDouglas Gilbert 
328fd32119bSDouglas Gilbert struct sdebug_defer {
329fd32119bSDouglas Gilbert 	struct hrtimer hrt;
330fd32119bSDouglas Gilbert 	struct execute_work ew;
331c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
332c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
333c4837394SDouglas Gilbert 	int issuing_cpu;
33410bde980SDouglas Gilbert 	bool init_hrt;
33510bde980SDouglas Gilbert 	bool init_wq;
3367382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
33710bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
338fd32119bSDouglas Gilbert };
339fd32119bSDouglas Gilbert 
340fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
341c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
342c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
343c4837394SDouglas Gilbert 	 */
344fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
345fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
346c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
347c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
348c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
349c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
350c4837394SDouglas Gilbert 	unsigned int inj_short:1;
3517ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
3527382f9d8SDouglas Gilbert 	unsigned int inj_cmd_abort:1;
353fd32119bSDouglas Gilbert };
354fd32119bSDouglas Gilbert 
355c4837394SDouglas Gilbert struct sdebug_queue {
356c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
357c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
358c4837394SDouglas Gilbert 	spinlock_t qc_lock;
359c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
360fd32119bSDouglas Gilbert };
361fd32119bSDouglas Gilbert 
362c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
363c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
364c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
365c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
366c4837394SDouglas Gilbert 
367fd32119bSDouglas Gilbert struct opcode_info_t {
368b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
369b01f6f83SDouglas Gilbert 				/* for terminating element */
370fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
371fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
372fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
373fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
374fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3759a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3769a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
377fd32119bSDouglas Gilbert };
378fd32119bSDouglas Gilbert 
379fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
380c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
381c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
382c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
383c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
384c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
385c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
386c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
387c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
388c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
389c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
390c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
391c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
392c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39346f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39446f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
395c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
396c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
397c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
398481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
399c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
400c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
401c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
402c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
403c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
404c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
405c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
406c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
407c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
408c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
409c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
410ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
411f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
412f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
413f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
414c2248fc9SDouglas Gilbert };
415c2248fc9SDouglas Gilbert 
416c4837394SDouglas Gilbert 
417c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
418c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
419c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
420c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
421c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
422c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
423c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
424c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
425c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
426c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
427c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
428c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
429ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
430c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
431c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
432c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
433c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
434c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
435c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
436c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
437fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
438c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
439c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
440c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
441c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
442c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
443c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
444c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
445f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
446f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44746f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
448c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
449c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
450c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
45146f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
45246f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
453c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
455c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
456c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
457c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
458c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
459c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
460c2248fc9SDouglas Gilbert };
461c2248fc9SDouglas Gilbert 
46280c49563SDouglas Gilbert /*
46380c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46480c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46580c49563SDouglas Gilbert  * command completion, they can mask their return value with
46680c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46780c49563SDouglas Gilbert  */
46880c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
46980c49563SDouglas Gilbert 
470c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
471c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
479481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48538d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48638d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
487c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
488c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
489c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
49038d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
491acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
49280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
493ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
494f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
495f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
496f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
497f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
498f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
499c2248fc9SDouglas Gilbert 
50087c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
50187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
50287c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50387c715dcSDouglas Gilbert static int sdebug_add_store(void);
50487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50587c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50687c715dcSDouglas Gilbert 
50746f64e70SDouglas Gilbert /*
50846f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
50946f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
51046f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
51146f64e70SDouglas Gilbert  */
51246f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
513c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
514c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
515c2248fc9SDouglas Gilbert };
516c2248fc9SDouglas Gilbert 
51746f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
518c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
519c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
520c2248fc9SDouglas Gilbert };
521c2248fc9SDouglas Gilbert 
52246f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52346f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
524b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
525c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52646f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
527c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52846f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
529b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
530c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
531c2248fc9SDouglas Gilbert };
532c2248fc9SDouglas Gilbert 
53346f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53446f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53546f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53646f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
53746f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
53846f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
53946f64e70SDouglas Gilbert 		   0, 0, 0} },
54046f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
54146f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54246f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
543c2248fc9SDouglas Gilbert };
544c2248fc9SDouglas Gilbert 
545c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
546c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
547c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
548c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
549c3e2fe92SDouglas Gilbert };
550c3e2fe92SDouglas Gilbert 
55146f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
552c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
553c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55446f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
555c2248fc9SDouglas Gilbert };
556c2248fc9SDouglas Gilbert 
55746f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
55846f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
559b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
560c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
561481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
562481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
563481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
564c2248fc9SDouglas Gilbert };
565c2248fc9SDouglas Gilbert 
56646f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
56738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
568c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
56946f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
57038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
571c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
57246f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
573c2248fc9SDouglas Gilbert };
574c2248fc9SDouglas Gilbert 
57546f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57646f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
577c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57846f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
579c2248fc9SDouglas Gilbert };
580c2248fc9SDouglas Gilbert 
58146f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
582c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
583c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
584c2248fc9SDouglas Gilbert };
585c2248fc9SDouglas Gilbert 
58646f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
587c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
588c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
589c2248fc9SDouglas Gilbert };
590c2248fc9SDouglas Gilbert 
59180c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5924f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59380c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59480c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59580c49563SDouglas Gilbert };
59680c49563SDouglas Gilbert 
597ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
598ed9f3e25SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | F_M_ACCESS, resp_pre_fetch, NULL,
599ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
600ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
601ed9f3e25SDouglas Gilbert };
602ed9f3e25SDouglas Gilbert 
603f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
604f0d1cf93SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW, resp_close_zone, NULL,
605f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
607f0d1cf93SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW, resp_finish_zone, NULL,
608f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
609f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
610f0d1cf93SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW, resp_rwp_zone, NULL,
611f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
613f0d1cf93SDouglas Gilbert };
614f0d1cf93SDouglas Gilbert 
615f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
616f0d1cf93SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN, NULL, NULL,
617f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
618f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
619f0d1cf93SDouglas Gilbert };
620f0d1cf93SDouglas Gilbert 
621c2248fc9SDouglas Gilbert 
622c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
623c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
624c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
625ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
626c2248fc9SDouglas Gilbert /* 0 */
62746f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
628c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
62946f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
630c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
631c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
632c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63346f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
634c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
635c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
636c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
637c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63846f64e70SDouglas Gilbert /* 5 */
63946f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
64046f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
64146f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64246f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64346f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64446f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64546f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
646c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
647c2248fc9SDouglas Gilbert 	     0, 0, 0} },
64846f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
649c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
650c2248fc9SDouglas Gilbert 	     0, 0} },
65146f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
65246f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65346f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
654c2248fc9SDouglas Gilbert /* 10 */
65546f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65646f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
65746f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65880c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6594f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
660c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
66146f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
66246f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66346f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66446f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
665481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
666481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
667481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
66846f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
66946f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
67046f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
67146f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
67246f64e70SDouglas Gilbert /* 15 */
673c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
674c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
675c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
676c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
677c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
678c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
67946f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
68046f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
68146f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
68246f64e70SDouglas Gilbert 	     0xff, 0xff} },
68346f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68446f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
685c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
686c2248fc9SDouglas Gilbert 	     0} },
68746f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
68846f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
689c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
690c2248fc9SDouglas Gilbert 	     0} },
691c2248fc9SDouglas Gilbert /* 20 */
692f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
693f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
694c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
695c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
696c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
697c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
698c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
699c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
70046f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
701b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
70246f64e70SDouglas Gilbert /* 25 */
703acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
704acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
705acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70646f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
70746f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
70846f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
70946f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7104f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
71180c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
712b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71380c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71446f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
715c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
716b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
717ed9f3e25SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | F_M_ACCESS,
718ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
719ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
720ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
721c2248fc9SDouglas Gilbert 
722ed9f3e25SDouglas Gilbert /* 30 */
723f0d1cf93SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW,
724f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
725f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
726f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
727f0d1cf93SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_D_IN,
728f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
729f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
730f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
731f0d1cf93SDouglas Gilbert /* sentinel */
732c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
733c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
734c2248fc9SDouglas Gilbert };
735c2248fc9SDouglas Gilbert 
73687c715dcSDouglas Gilbert static int sdebug_num_hosts;
73787c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
738773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7399b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
740c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7419267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
742773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
743773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
744773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
745773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
746773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
747773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
748773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
749773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
750c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
751d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
752d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
753cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
754c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
755773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
756773642d9SDouglas Gilbert static int sdebug_no_uld;
757773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
758773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
759773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
760773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
761773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76286e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
763b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
764773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
765773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
766773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
767773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
768773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
769773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
770773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
771773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
772773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
773773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
775773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
776773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
77709ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7780c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
77987c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
780773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
781773642d9SDouglas Gilbert static bool sdebug_clustering;
782773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
783773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
784817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
785773642d9SDouglas Gilbert static bool sdebug_verbose;
786f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7874f2c8bf6SDouglas Gilbert static bool write_since_sync;
788c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7899447b6ceSMartin K. Petersen static bool sdebug_wp;
7909267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7919267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7929267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7931da177e4SLinus Torvalds 
794c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
7951da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
7981da177e4SLinus Torvalds    may still need them */
7991da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8001da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8011da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8041da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8051da177e4SLinus Torvalds 
80687c715dcSDouglas Gilbert static struct xarray per_store_arr;
80787c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
80887c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
80987c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
81087c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8111da177e4SLinus Torvalds 
81244d92694SMartin K. Petersen static unsigned long map_size;
813cbf67842SDouglas Gilbert static int num_aborts;
814cbf67842SDouglas Gilbert static int num_dev_resets;
815cbf67842SDouglas Gilbert static int num_target_resets;
816cbf67842SDouglas Gilbert static int num_bus_resets;
817cbf67842SDouglas Gilbert static int num_host_resets;
818c6a44287SMartin K. Petersen static int dix_writes;
819c6a44287SMartin K. Petersen static int dix_reads;
820c6a44287SMartin K. Petersen static int dif_errors;
8211da177e4SLinus Torvalds 
822f0d1cf93SDouglas Gilbert /* ZBC global data */
823f0d1cf93SDouglas Gilbert static bool sdeb_zbc_in_use;		/* true when ptype=TYPE_ZBC [0x14] */
824f0d1cf93SDouglas Gilbert static const int zbc_zone_size_mb;
825f0d1cf93SDouglas Gilbert static const int zbc_max_open_zones = DEF_ZBC_MAX_OPEN_ZONES;
826f0d1cf93SDouglas Gilbert 
827c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
828c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
829fd32119bSDouglas Gilbert 
8301da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
83187c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
83287c715dcSDouglas Gilbert 
83387c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8341da177e4SLinus Torvalds 
835cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
836cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8411da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8421da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8431da177e4SLinus Torvalds };
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds static const int check_condition_result =
8461da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8471da177e4SLinus Torvalds 
848c6a44287SMartin K. Petersen static const int illegal_condition_result =
849c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
850c6a44287SMartin K. Petersen 
851cbf67842SDouglas Gilbert static const int device_qfull_result =
852cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
853cbf67842SDouglas Gilbert 
854ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
855ed9f3e25SDouglas Gilbert 
856fd32119bSDouglas Gilbert 
857760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
858760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
859760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
860760f3b03SDouglas Gilbert  */
861760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
862fd32119bSDouglas Gilbert {
863fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
864fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
865fd32119bSDouglas Gilbert }
866c65b1445SDouglas Gilbert 
86787c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
86887c715dcSDouglas Gilbert 			    unsigned long long lba)
86914faa944SAkinobu Mita {
87087c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
87114faa944SAkinobu Mita 
87287c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
87387c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
87487c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
87587c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
87687c715dcSDouglas Gilbert 	}
87787c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
87814faa944SAkinobu Mita }
87914faa944SAkinobu Mita 
88087c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
88187c715dcSDouglas Gilbert 				      sector_t sector)
88214faa944SAkinobu Mita {
88349413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
88414faa944SAkinobu Mita 
88587c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
88614faa944SAkinobu Mita }
88714faa944SAkinobu Mita 
8888dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8898dea0d02SFUJITA Tomonori {
8908dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
8918dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
8928dea0d02SFUJITA Tomonori 
8938dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
8948dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8958dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
8968dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
897773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
898773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
8998dea0d02SFUJITA Tomonori 		else
900773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
901773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
902f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9038dea0d02SFUJITA Tomonori 	}
9048dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9058dea0d02SFUJITA Tomonori }
9068dea0d02SFUJITA Tomonori 
90722017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
90822017ed2SDouglas Gilbert 
90922017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
910fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
911fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
91222017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
91322017ed2SDouglas Gilbert {
91422017ed2SDouglas Gilbert 	unsigned char *sbuff;
91522017ed2SDouglas Gilbert 	u8 sks[4];
91622017ed2SDouglas Gilbert 	int sl, asc;
91722017ed2SDouglas Gilbert 
91822017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
91922017ed2SDouglas Gilbert 	if (!sbuff) {
92022017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
92122017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
92222017ed2SDouglas Gilbert 		return;
92322017ed2SDouglas Gilbert 	}
92422017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
92522017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
926773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
92722017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
92822017ed2SDouglas Gilbert 	sks[0] = 0x80;
92922017ed2SDouglas Gilbert 	if (c_d)
93022017ed2SDouglas Gilbert 		sks[0] |= 0x40;
93122017ed2SDouglas Gilbert 	if (in_bit >= 0) {
93222017ed2SDouglas Gilbert 		sks[0] |= 0x8;
93322017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
93422017ed2SDouglas Gilbert 	}
93522017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
936773642d9SDouglas Gilbert 	if (sdebug_dsense) {
93722017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
93822017ed2SDouglas Gilbert 		sbuff[7] = sl;
93922017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
94022017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
94122017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
94222017ed2SDouglas Gilbert 	} else
94322017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
944773642d9SDouglas Gilbert 	if (sdebug_verbose)
94522017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
94622017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
94722017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
94822017ed2SDouglas Gilbert }
94922017ed2SDouglas Gilbert 
950cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9518dea0d02SFUJITA Tomonori {
9528dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
9538dea0d02SFUJITA Tomonori 
954cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
955cbf67842SDouglas Gilbert 	if (!sbuff) {
956cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
957cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
958cbf67842SDouglas Gilbert 		return;
959cbf67842SDouglas Gilbert 	}
960cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9618dea0d02SFUJITA Tomonori 
962773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9638dea0d02SFUJITA Tomonori 
964773642d9SDouglas Gilbert 	if (sdebug_verbose)
965cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
966cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
967cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9688dea0d02SFUJITA Tomonori }
9691da177e4SLinus Torvalds 
970fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
97122017ed2SDouglas Gilbert {
97222017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
97322017ed2SDouglas Gilbert }
97422017ed2SDouglas Gilbert 
9756f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9766f4e626fSNathan Chancellor 			    void __user *arg)
9771da177e4SLinus Torvalds {
978773642d9SDouglas Gilbert 	if (sdebug_verbose) {
979cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
980cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
981cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
982cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
983cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
984cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
985cbf67842SDouglas Gilbert 				    __func__);
986cbf67842SDouglas Gilbert 		else
987cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
988cbf67842SDouglas Gilbert 				    __func__, cmd);
9891da177e4SLinus Torvalds 	}
9901da177e4SLinus Torvalds 	return -EINVAL;
9911da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
9921da177e4SLinus Torvalds }
9931da177e4SLinus Torvalds 
9949b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
9959b760fd8SDouglas Gilbert {
9969b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
9979b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
9989b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
9999b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10009b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10019b760fd8SDouglas Gilbert 		break;
10029b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10039b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10049b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10059b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10069b760fd8SDouglas Gilbert 		break;
10079b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10089b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10099b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10109b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10119b760fd8SDouglas Gilbert 		break;
10129b760fd8SDouglas Gilbert 	case 16:
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10149b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10159b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10169b760fd8SDouglas Gilbert 		break;
10179b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10199b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10209b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10219b760fd8SDouglas Gilbert 		break;
10229b760fd8SDouglas Gilbert 	default:
10239b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10249b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10259b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10269b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10279b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10289b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10299b760fd8SDouglas Gilbert 		break;
10309b760fd8SDouglas Gilbert 	}
10319b760fd8SDouglas Gilbert }
10329b760fd8SDouglas Gilbert 
10339b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10349b760fd8SDouglas Gilbert {
10359b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10369b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10379b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10389b760fd8SDouglas Gilbert 
10399b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10409b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10419b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10429b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10439b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10449b760fd8SDouglas Gilbert 		}
10459b760fd8SDouglas Gilbert 	}
10469b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10479b760fd8SDouglas Gilbert }
10489b760fd8SDouglas Gilbert 
104919c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
105019c8ead7SEwan D. Milne {
105119c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
105219c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
105319c8ead7SEwan D. Milne 
105419c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
105519c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
105619c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
105719c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
105819c8ead7SEwan D. Milne 			    (devip->target == dp->target))
105919c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
106019c8ead7SEwan D. Milne 		}
106119c8ead7SEwan D. Milne 	}
106219c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
106319c8ead7SEwan D. Milne }
106419c8ead7SEwan D. Milne 
1065f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10661da177e4SLinus Torvalds {
1067cbf67842SDouglas Gilbert 	int k;
1068cbf67842SDouglas Gilbert 
1069cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1070cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1071cbf67842SDouglas Gilbert 		const char *cp = NULL;
1072cbf67842SDouglas Gilbert 
1073cbf67842SDouglas Gilbert 		switch (k) {
1074cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1075f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1076f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1077773642d9SDouglas Gilbert 			if (sdebug_verbose)
1078cbf67842SDouglas Gilbert 				cp = "power on reset";
1079cbf67842SDouglas Gilbert 			break;
1080cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1081f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1082f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1083773642d9SDouglas Gilbert 			if (sdebug_verbose)
1084cbf67842SDouglas Gilbert 				cp = "bus reset";
1085cbf67842SDouglas Gilbert 			break;
1086cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1087f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1088f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1089773642d9SDouglas Gilbert 			if (sdebug_verbose)
1090cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1091cbf67842SDouglas Gilbert 			break;
10920d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1093f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1094f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1095773642d9SDouglas Gilbert 			if (sdebug_verbose)
10960d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1097f49accf1SEwan D. Milne 			break;
1098acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1099f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1100b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1101b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1102773642d9SDouglas Gilbert 			if (sdebug_verbose)
1103acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1104acafd0b9SEwan D. Milne 			break;
1105acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1106f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1107acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1108acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1109773642d9SDouglas Gilbert 			if (sdebug_verbose)
1110acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1111acafd0b9SEwan D. Milne 			break;
111219c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
111319c8ead7SEwan D. Milne 			/*
111419c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
111519c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
111619c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
111719c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1118773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
111919c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
112019c8ead7SEwan D. Milne 			 */
1121773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
112219c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1123f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
112419c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
112519c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1126773642d9SDouglas Gilbert 			if (sdebug_verbose)
112719c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
112819c8ead7SEwan D. Milne 			break;
1129cbf67842SDouglas Gilbert 		default:
1130773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1131773642d9SDouglas Gilbert 			if (sdebug_verbose)
1132cbf67842SDouglas Gilbert 				cp = "unknown";
1133cbf67842SDouglas Gilbert 			break;
1134cbf67842SDouglas Gilbert 		}
1135cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1136773642d9SDouglas Gilbert 		if (sdebug_verbose)
1137f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1138cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1139cbf67842SDouglas Gilbert 				   my_name, cp);
11401da177e4SLinus Torvalds 		return check_condition_result;
11411da177e4SLinus Torvalds 	}
11421da177e4SLinus Torvalds 	return 0;
11431da177e4SLinus Torvalds }
11441da177e4SLinus Torvalds 
1145fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11461da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11471da177e4SLinus Torvalds 				int arr_len)
11481da177e4SLinus Torvalds {
114921a61829SFUJITA Tomonori 	int act_len;
1150ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11511da177e4SLinus Torvalds 
1152072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11531da177e4SLinus Torvalds 		return 0;
1154ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1155773642d9SDouglas Gilbert 		return DID_ERROR << 16;
115621a61829SFUJITA Tomonori 
115721a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
115821a61829SFUJITA Tomonori 				      arr, arr_len);
115942d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
116021a61829SFUJITA Tomonori 
11611da177e4SLinus Torvalds 	return 0;
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds 
1164fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1165fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1166fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1167fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1168fb0cc8d1SDouglas Gilbert  */
1169fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1170fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1171fb0cc8d1SDouglas Gilbert {
11729237f04eSDamien Le Moal 	unsigned int act_len, n;
1173ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1174fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1175fb0cc8d1SDouglas Gilbert 
1176fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1177fb0cc8d1SDouglas Gilbert 		return 0;
1178ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1179fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1180fb0cc8d1SDouglas Gilbert 
1181fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1182fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1183fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
118442d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
118542d387beSBart Van Assche 		 scsi_get_resid(scp));
11869237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
118787c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1188fb0cc8d1SDouglas Gilbert 	return 0;
1189fb0cc8d1SDouglas Gilbert }
1190fb0cc8d1SDouglas Gilbert 
1191fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1192fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1193fb0cc8d1SDouglas Gilbert  */
11941da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
119521a61829SFUJITA Tomonori 			       int arr_len)
11961da177e4SLinus Torvalds {
119721a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
11981da177e4SLinus Torvalds 		return 0;
1199ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12001da177e4SLinus Torvalds 		return -1;
120121a61829SFUJITA Tomonori 
120221a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12031da177e4SLinus Torvalds }
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 
1206e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1207e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12089b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12091b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12101b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12111b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12121b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12131da177e4SLinus Torvalds 
1214cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1215760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12165a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
121709ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1218bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12191da177e4SLinus Torvalds {
1220c65b1445SDouglas Gilbert 	int num, port_a;
1221c65b1445SDouglas Gilbert 	char b[32];
12221da177e4SLinus Torvalds 
1223c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12241da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12251da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12261da177e4SLinus Torvalds 	arr[1] = 0x1;
12271da177e4SLinus Torvalds 	arr[2] = 0x0;
1228e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1229e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12301da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12311da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12321da177e4SLinus Torvalds 	arr[3] = num;
12331da177e4SLinus Torvalds 	num += 4;
1234c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
123509ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
123609ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
123709ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
123809ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
123909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124009ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
124109ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
124209ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124309ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
124409ba24c1SDouglas Gilbert 			num += 16;
124509ba24c1SDouglas Gilbert 		} else {
12461b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1247c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1248c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1249c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1250c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12511b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1252773642d9SDouglas Gilbert 			num += 8;
125309ba24c1SDouglas Gilbert 		}
1254c65b1445SDouglas Gilbert 		/* Target relative port number */
1255c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1256c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1257c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1258c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1259c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1260c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1261c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1262c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1263c65b1445SDouglas Gilbert 	}
12641b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1265c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1266c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1267c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1268c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12691b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1270773642d9SDouglas Gilbert 	num += 8;
12711b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12725a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12735a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12745a09e398SHannes Reinecke 	arr[num++] = 0x0;
12755a09e398SHannes Reinecke 	arr[num++] = 0x4;
12765a09e398SHannes Reinecke 	arr[num++] = 0;
12775a09e398SHannes Reinecke 	arr[num++] = 0;
1278773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1279773642d9SDouglas Gilbert 	num += 2;
12801b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1281c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1282c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1283c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1284c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12851b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1286773642d9SDouglas Gilbert 	num += 8;
1287c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1288c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1289c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1290c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1291c65b1445SDouglas Gilbert 	arr[num++] = 24;
12921b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1293c65b1445SDouglas Gilbert 	num += 12;
1294c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1295c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1296c65b1445SDouglas Gilbert 	num += 8;
1297c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1298c65b1445SDouglas Gilbert 	num += 4;
1299c65b1445SDouglas Gilbert 	return num;
1300c65b1445SDouglas Gilbert }
1301c65b1445SDouglas Gilbert 
1302c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1303c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1304c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1305c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1306c65b1445SDouglas Gilbert };
1307c65b1445SDouglas Gilbert 
1308cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1309760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1310c65b1445SDouglas Gilbert {
1311c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1312c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1313c65b1445SDouglas Gilbert }
1314c65b1445SDouglas Gilbert 
1315cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1316760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1317c65b1445SDouglas Gilbert {
1318c65b1445SDouglas Gilbert 	int num = 0;
1319c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1320c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1321c65b1445SDouglas Gilbert 	int plen, olen;
1322c65b1445SDouglas Gilbert 
1323c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1324c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1325c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1326c65b1445SDouglas Gilbert 	olen = strlen(na1);
1327c65b1445SDouglas Gilbert 	plen = olen + 1;
1328c65b1445SDouglas Gilbert 	if (plen % 4)
1329c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1330c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1331c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1332c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1333c65b1445SDouglas Gilbert 	num += plen;
1334c65b1445SDouglas Gilbert 
1335c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1336c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1337c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1338c65b1445SDouglas Gilbert 	olen = strlen(na2);
1339c65b1445SDouglas Gilbert 	plen = olen + 1;
1340c65b1445SDouglas Gilbert 	if (plen % 4)
1341c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1342c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1343c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1344c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1345c65b1445SDouglas Gilbert 	num += plen;
1346c65b1445SDouglas Gilbert 
1347c65b1445SDouglas Gilbert 	return num;
1348c65b1445SDouglas Gilbert }
1349c65b1445SDouglas Gilbert 
1350c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1351760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1352c65b1445SDouglas Gilbert {
1353c65b1445SDouglas Gilbert 	int num = 0;
1354c65b1445SDouglas Gilbert 	int port_a, port_b;
1355c65b1445SDouglas Gilbert 
1356c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1357c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1358c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1359c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1360c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1361c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1362c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1363c65b1445SDouglas Gilbert 	num += 6;
1364c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1365c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1366c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1367c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1368c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1369c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1370c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13711b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1372773642d9SDouglas Gilbert 	num += 8;
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1374c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1375c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1376c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1377c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1378c65b1445SDouglas Gilbert 	num += 6;
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1380c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1381c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1385c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13861b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1387773642d9SDouglas Gilbert 	num += 8;
1388c65b1445SDouglas Gilbert 
1389c65b1445SDouglas Gilbert 	return num;
1390c65b1445SDouglas Gilbert }
1391c65b1445SDouglas Gilbert 
1392c65b1445SDouglas Gilbert 
1393c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1394c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1395c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1396c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1397c65b1445SDouglas Gilbert '1','2','3','4',
1398c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1399c65b1445SDouglas Gilbert 0xec,0,0,0,
1400c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1401c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1402c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1403c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1404c65b1445SDouglas Gilbert 0x53,0x41,
1405c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1406c65b1445SDouglas Gilbert 0x20,0x20,
1407c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1408c65b1445SDouglas Gilbert 0x10,0x80,
1409c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1410c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1411c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1412c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1413c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1414c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1415c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1416c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1417c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1418c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1419c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1420c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1421c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1422c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1435c65b1445SDouglas Gilbert };
1436c65b1445SDouglas Gilbert 
1437cbf67842SDouglas Gilbert /* ATA Information VPD page */
1438760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1439c65b1445SDouglas Gilbert {
1440c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1441c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1442c65b1445SDouglas Gilbert }
1443c65b1445SDouglas Gilbert 
1444c65b1445SDouglas Gilbert 
1445c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14461e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14471e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14481e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14491e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1450c65b1445SDouglas Gilbert };
1451c65b1445SDouglas Gilbert 
1452cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1453760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1454c65b1445SDouglas Gilbert {
1455ea61fca5SMartin K. Petersen 	unsigned int gran;
1456ea61fca5SMartin K. Petersen 
1457c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1458e308b3d1SMartin K. Petersen 
1459e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
146086e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
146186e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
146286e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
146386e6828aSLukas Herbolt 	else
1464773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1465773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1466e308b3d1SMartin K. Petersen 
1467e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1468773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1469773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
147044d92694SMartin K. Petersen 
1471e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1472773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1473e308b3d1SMartin K. Petersen 
1474773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1475e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1476773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1477e308b3d1SMartin K. Petersen 
1478e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1479773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
148044d92694SMartin K. Petersen 	}
148144d92694SMartin K. Petersen 
1482e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1483773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1484773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
148544d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
148644d92694SMartin K. Petersen 	}
148744d92694SMartin K. Petersen 
1488e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1489773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14906014759cSMartin K. Petersen 
14915b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1492773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
14935b94e232SMartin K. Petersen 
14945b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
149544d92694SMartin K. Petersen 
1496c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
14971da177e4SLinus Torvalds }
14981da177e4SLinus Torvalds 
14991e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1500760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1501eac6e8e4SMatthew Wilcox {
1502eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1503eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15041e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15051e49f785SDouglas Gilbert 	arr[2] = 0;
15061e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
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]);
1543f0d1cf93SDouglas Gilbert 	if (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);
1566d36da305SDouglas Gilbert 	is_zbc = (sdebug_ptype == TYPE_ZBC);
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 */
1611d36da305SDouglas Gilbert 				else 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 */
1660760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&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 
1715fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1716fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1717fd32119bSDouglas Gilbert 
17181da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17191da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17201da177e4SLinus Torvalds {
17211da177e4SLinus Torvalds 	unsigned char *sbuff;
172201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1723cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
17242492fc09STomas Winkler 	bool dsense;
17251da177e4SLinus Torvalds 	int len = 18;
17261da177e4SLinus Torvalds 
1727c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1728c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1729cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1730c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1731c2248fc9SDouglas Gilbert 		if (dsense) {
1732c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1733c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1734c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1735c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1736c2248fc9SDouglas Gilbert 			len = 8;
1737c65b1445SDouglas Gilbert 		} else {
1738c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1739c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1740c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1741c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1742c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1743c65b1445SDouglas Gilbert 		}
1744c65b1445SDouglas Gilbert 	} else {
1745cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1746773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1747c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1748c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1749c2248fc9SDouglas Gilbert 			if (dsense) {
1750c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1751c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1752c2248fc9SDouglas Gilbert 				len = 8;
1753c2248fc9SDouglas Gilbert 			} else {
1754c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1755c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1756c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1757c2248fc9SDouglas Gilbert 			}
1758c2248fc9SDouglas Gilbert 		} else if (dsense) {
1759c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
17601da177e4SLinus Torvalds 			arr[0] = 0x72;
17611da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
17621da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
17631da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
17641da177e4SLinus Torvalds 			len = 8;
1765c2248fc9SDouglas Gilbert 		} else {
1766c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1767c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1768c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1769c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1770c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1771c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1772c65b1445SDouglas Gilbert 		}
1773c2248fc9SDouglas Gilbert 
1774c65b1445SDouglas Gilbert 	}
1775cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
17761da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
17771da177e4SLinus Torvalds }
17781da177e4SLinus Torvalds 
1779c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1780c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1781c65b1445SDouglas Gilbert {
178201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1783c4837394SDouglas Gilbert 	int power_cond, stop;
17844f2c8bf6SDouglas Gilbert 	bool changing;
1785c65b1445SDouglas Gilbert 
1786c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1787c65b1445SDouglas Gilbert 	if (power_cond) {
178822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1789c65b1445SDouglas Gilbert 		return check_condition_result;
1790c65b1445SDouglas Gilbert 	}
1791c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
17924f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1793c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
17944f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
17954f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
17964f2c8bf6SDouglas Gilbert 	else
17974f2c8bf6SDouglas Gilbert 		return 0;
1798c65b1445SDouglas Gilbert }
1799c65b1445SDouglas Gilbert 
180028898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
180128898873SFUJITA Tomonori {
1802773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1803773642d9SDouglas Gilbert 
1804773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1805773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1806773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
180728898873SFUJITA Tomonori 	else
180828898873SFUJITA Tomonori 		return sdebug_store_sectors;
180928898873SFUJITA Tomonori }
181028898873SFUJITA Tomonori 
18111da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18121da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18131da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18141da177e4SLinus Torvalds {
18151da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1816c65b1445SDouglas Gilbert 	unsigned int capac;
18171da177e4SLinus Torvalds 
1818c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
181928898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18201da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1821c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1822c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1823773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1824773642d9SDouglas Gilbert 	} else
1825773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1826773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18271da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18281da177e4SLinus Torvalds }
18291da177e4SLinus Torvalds 
1830c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1831c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1832c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1833c65b1445SDouglas Gilbert {
183401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1835c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1836773642d9SDouglas Gilbert 	int alloc_len;
1837c65b1445SDouglas Gilbert 
1838773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1839c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
184028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1841c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1842773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1843773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1844773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1845773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
184644d92694SMartin K. Petersen 
1847be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18485b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1849760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1850760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1851760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1852760f3b03SDouglas Gilbert 		 */
1853760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1854760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1855be1dd78dSEric Sandeen 	}
185644d92694SMartin K. Petersen 
1857773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1858c6a44287SMartin K. Petersen 
1859760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1860773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1861c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1862c6a44287SMartin K. Petersen 	}
1863c6a44287SMartin K. Petersen 
1864c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
186587c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1866c65b1445SDouglas Gilbert }
1867c65b1445SDouglas Gilbert 
18685a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18695a09e398SHannes Reinecke 
18705a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18715a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18725a09e398SHannes Reinecke {
187301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
18745a09e398SHannes Reinecke 	unsigned char *arr;
18755a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
18765a09e398SHannes Reinecke 	int n, ret, alen, rlen;
18775a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
18785a09e398SHannes Reinecke 
1879773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
18806f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
18816f3cbf55SDouglas Gilbert 	if (! arr)
18826f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
18835a09e398SHannes Reinecke 	/*
18845a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
18855a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
18865a09e398SHannes Reinecke 	 * So we create two port groups with one port each
18875a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
18885a09e398SHannes Reinecke 	 */
18895a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
18905a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
18915a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
18925a09e398SHannes Reinecke 			(devip->channel & 0x7f);
18935a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
18945a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
18955a09e398SHannes Reinecke 
18965a09e398SHannes Reinecke 	/*
18975a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
18985a09e398SHannes Reinecke 	 */
18995a09e398SHannes Reinecke 	n = 4;
1900b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19015a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19025a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19035a09e398SHannes Reinecke 	} else {
19045a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1905773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19065a09e398SHannes Reinecke 	}
1907773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1908773642d9SDouglas Gilbert 	n += 2;
19095a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19105a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19115a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19125a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19135a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19145a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1915773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1916773642d9SDouglas Gilbert 	n += 2;
19175a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19185a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1919773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1920773642d9SDouglas Gilbert 	n += 2;
19215a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19225a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19235a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19245a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19255a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19265a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1927773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1928773642d9SDouglas Gilbert 	n += 2;
19295a09e398SHannes Reinecke 
19305a09e398SHannes Reinecke 	rlen = n - 4;
1931773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19325a09e398SHannes Reinecke 
19335a09e398SHannes Reinecke 	/*
19345a09e398SHannes Reinecke 	 * Return the smallest value of either
19355a09e398SHannes Reinecke 	 * - The allocated length
19365a09e398SHannes Reinecke 	 * - The constructed command length
19375a09e398SHannes Reinecke 	 * - The maximum array size
19385a09e398SHannes Reinecke 	 */
193987c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
19405a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
194187c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19425a09e398SHannes Reinecke 	kfree(arr);
19435a09e398SHannes Reinecke 	return ret;
19445a09e398SHannes Reinecke }
19455a09e398SHannes Reinecke 
1946fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1947fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
194838d5c833SDouglas Gilbert {
194938d5c833SDouglas Gilbert 	bool rctd;
195038d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
195138d5c833SDouglas Gilbert 	u16 req_sa, u;
195238d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
195338d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
195438d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
195538d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
195638d5c833SDouglas Gilbert 	u8 *arr;
195738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
195838d5c833SDouglas Gilbert 
195938d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
196038d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
196138d5c833SDouglas Gilbert 	req_opcode = cmd[3];
196238d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
196338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19646d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
196538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
196638d5c833SDouglas Gilbert 		return check_condition_result;
196738d5c833SDouglas Gilbert 	}
196838d5c833SDouglas Gilbert 	if (alloc_len > 8192)
196938d5c833SDouglas Gilbert 		a_len = 8192;
197038d5c833SDouglas Gilbert 	else
197138d5c833SDouglas Gilbert 		a_len = alloc_len;
197299531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
197338d5c833SDouglas Gilbert 	if (NULL == arr) {
197438d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
197538d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
197638d5c833SDouglas Gilbert 		return check_condition_result;
197738d5c833SDouglas Gilbert 	}
197838d5c833SDouglas Gilbert 	switch (reporting_opts) {
197938d5c833SDouglas Gilbert 	case 0:	/* all commands */
198038d5c833SDouglas Gilbert 		/* count number of commands */
198138d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
198238d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
198338d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
198438d5c833SDouglas Gilbert 				continue;
198538d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
198638d5c833SDouglas Gilbert 		}
198738d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
198838d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
198938d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
199038d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
199138d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
199238d5c833SDouglas Gilbert 				continue;
199338d5c833SDouglas Gilbert 			na = oip->num_attached;
199438d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
199538d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
199638d5c833SDouglas Gilbert 			if (rctd)
199738d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
199838d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
199938d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
200038d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
200138d5c833SDouglas Gilbert 			if (rctd)
200238d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
200338d5c833SDouglas Gilbert 			r_oip = oip;
200438d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
200538d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
200638d5c833SDouglas Gilbert 					continue;
200738d5c833SDouglas Gilbert 				offset += bump;
200838d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
200938d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
201038d5c833SDouglas Gilbert 				if (rctd)
201138d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
201238d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
201338d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
201438d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
201538d5c833SDouglas Gilbert 						   arr + offset + 6);
201638d5c833SDouglas Gilbert 				if (rctd)
201738d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
201838d5c833SDouglas Gilbert 							   arr + offset + 8);
201938d5c833SDouglas Gilbert 			}
202038d5c833SDouglas Gilbert 			oip = r_oip;
202138d5c833SDouglas Gilbert 			offset += bump;
202238d5c833SDouglas Gilbert 		}
202338d5c833SDouglas Gilbert 		break;
202438d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
202538d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
202638d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
202738d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
202838d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
202938d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
203038d5c833SDouglas Gilbert 			supp = 1;
203138d5c833SDouglas Gilbert 			offset = 4;
203238d5c833SDouglas Gilbert 		} else {
203338d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
203438d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
203538d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
203638d5c833SDouglas Gilbert 							     2, 2);
203738d5c833SDouglas Gilbert 					kfree(arr);
203838d5c833SDouglas Gilbert 					return check_condition_result;
203938d5c833SDouglas Gilbert 				}
204038d5c833SDouglas Gilbert 				req_sa = 0;
204138d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
204238d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
204338d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
204438d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
204538d5c833SDouglas Gilbert 				return check_condition_result;
204638d5c833SDouglas Gilbert 			}
204738d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
204838d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
204938d5c833SDouglas Gilbert 				supp = 3;
205038d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
205138d5c833SDouglas Gilbert 				na = oip->num_attached;
205238d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
205338d5c833SDouglas Gilbert 				     ++k, ++oip) {
205438d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
205538d5c833SDouglas Gilbert 						break;
205638d5c833SDouglas Gilbert 				}
205738d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
205838d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
205938d5c833SDouglas Gilbert 				na = oip->num_attached;
206038d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
206138d5c833SDouglas Gilbert 				     ++k, ++oip) {
206238d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
206338d5c833SDouglas Gilbert 						break;
206438d5c833SDouglas Gilbert 				}
206538d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
206638d5c833SDouglas Gilbert 			} else
206738d5c833SDouglas Gilbert 				supp = 3;
206838d5c833SDouglas Gilbert 			if (3 == supp) {
206938d5c833SDouglas Gilbert 				u = oip->len_mask[0];
207038d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
207138d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
207238d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
207338d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
207438d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
207538d5c833SDouglas Gilbert 				offset = 4 + u;
207638d5c833SDouglas Gilbert 			} else
207738d5c833SDouglas Gilbert 				offset = 4;
207838d5c833SDouglas Gilbert 		}
207938d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
208038d5c833SDouglas Gilbert 		if (rctd) {
208138d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
208238d5c833SDouglas Gilbert 			offset += 12;
208338d5c833SDouglas Gilbert 		}
208438d5c833SDouglas Gilbert 		break;
208538d5c833SDouglas Gilbert 	default:
208638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
208738d5c833SDouglas Gilbert 		kfree(arr);
208838d5c833SDouglas Gilbert 		return check_condition_result;
208938d5c833SDouglas Gilbert 	}
209038d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
209138d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
209238d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
209338d5c833SDouglas Gilbert 	kfree(arr);
209438d5c833SDouglas Gilbert 	return errsts;
209538d5c833SDouglas Gilbert }
209638d5c833SDouglas Gilbert 
2097fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2098fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
209938d5c833SDouglas Gilbert {
210038d5c833SDouglas Gilbert 	bool repd;
210138d5c833SDouglas Gilbert 	u32 alloc_len, len;
210238d5c833SDouglas Gilbert 	u8 arr[16];
210338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
210438d5c833SDouglas Gilbert 
210538d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
210638d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
210738d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
210838d5c833SDouglas Gilbert 	if (alloc_len < 4) {
210938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
211038d5c833SDouglas Gilbert 		return check_condition_result;
211138d5c833SDouglas Gilbert 	}
211238d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
211338d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
211438d5c833SDouglas Gilbert 	if (repd) {
211538d5c833SDouglas Gilbert 		arr[3] = 0xc;
211638d5c833SDouglas Gilbert 		len = 16;
211738d5c833SDouglas Gilbert 	} else
211838d5c833SDouglas Gilbert 		len = 4;
211938d5c833SDouglas Gilbert 
212038d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
212138d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
212238d5c833SDouglas Gilbert }
212338d5c833SDouglas Gilbert 
21241da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21251da177e4SLinus Torvalds 
21261da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21271da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21281da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21291da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21321da177e4SLinus Torvalds 	if (1 == pcontrol)
21331da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21341da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21351da177e4SLinus Torvalds }
21361da177e4SLinus Torvalds 
21371da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21381da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21391da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21401da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21431da177e4SLinus Torvalds 	if (1 == pcontrol)
21441da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21451da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21461da177e4SLinus Torvalds }
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21491da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21501da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21511da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21521da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21531da177e4SLinus Torvalds 
21541da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2155773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2156773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2157773642d9SDouglas Gilbert 	if (sdebug_removable)
21581da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21591da177e4SLinus Torvalds 	if (1 == pcontrol)
21601da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21611da177e4SLinus Torvalds 	return sizeof(format_pg);
21621da177e4SLinus Torvalds }
21631da177e4SLinus Torvalds 
2164fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2165fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2166fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2167fd32119bSDouglas Gilbert 
21681da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21691da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2170cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2171cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2172cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21731da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
21741da177e4SLinus Torvalds 
2175773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2176cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
21771da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
21781da177e4SLinus Torvalds 	if (1 == pcontrol)
2179cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2180cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2181cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
21821da177e4SLinus Torvalds 	return sizeof(caching_pg);
21831da177e4SLinus Torvalds }
21841da177e4SLinus Torvalds 
2185fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2186fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2187fd32119bSDouglas Gilbert 
21881da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
21891da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2190c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2191c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2192c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
21931da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
21941da177e4SLinus Torvalds 
2195773642d9SDouglas Gilbert 	if (sdebug_dsense)
21961da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2197c65b1445SDouglas Gilbert 	else
2198c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2199c6a44287SMartin K. Petersen 
2200773642d9SDouglas Gilbert 	if (sdebug_ato)
2201c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2202c6a44287SMartin K. Petersen 
22031da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22041da177e4SLinus Torvalds 	if (1 == pcontrol)
2205c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2206c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2207c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22081da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22091da177e4SLinus Torvalds }
22101da177e4SLinus Torvalds 
2211c65b1445SDouglas Gilbert 
22121da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22131da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2214c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22151da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2216c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2217c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2218c65b1445SDouglas Gilbert 
22191da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22201da177e4SLinus Torvalds 	if (1 == pcontrol)
2221c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2222c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2223c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22241da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22251da177e4SLinus Torvalds }
22261da177e4SLinus Torvalds 
2227c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2228c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2229c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2230c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2231c65b1445SDouglas Gilbert 
2232c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2233c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2234c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2235c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2236c65b1445SDouglas Gilbert }
2237c65b1445SDouglas Gilbert 
2238c65b1445SDouglas Gilbert 
2239c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2240c65b1445SDouglas Gilbert 			      int target_dev_id)
2241c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2242c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2243c65b1445SDouglas Gilbert 		    0, 0, 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 		    0x2, 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 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2250773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2251773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2252c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2253c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2254c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2255c65b1445SDouglas Gilbert 		};
2256c65b1445SDouglas Gilbert 	int port_a, port_b;
2257c65b1445SDouglas Gilbert 
22581b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22591b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22601b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22611b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2262c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2263c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2264c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2265773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2266773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2267c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2268c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2269c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2270c65b1445SDouglas Gilbert }
2271c65b1445SDouglas Gilbert 
2272c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2273c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2274c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2275c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2276c65b1445SDouglas Gilbert 		};
2277c65b1445SDouglas Gilbert 
2278c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2279c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2280c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2281c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2282c65b1445SDouglas Gilbert }
2283c65b1445SDouglas Gilbert 
22841da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
22851da177e4SLinus Torvalds 
2286fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2287fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
22881da177e4SLinus Torvalds {
228923183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
22901da177e4SLinus Torvalds 	unsigned char dev_spec;
2291760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2292c2248fc9SDouglas Gilbert 	int target = scp->device->id;
22931da177e4SLinus Torvalds 	unsigned char *ap;
22941da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
229501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2296d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
22971da177e4SLinus Torvalds 
2298760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
22991da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23001da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23011da177e4SLinus Torvalds 	subpcode = cmd[3];
23021da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2303760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2304760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2305d36da305SDouglas Gilbert 	is_zbc = (sdebug_ptype == TYPE_ZBC);
2306d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
230723183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
230823183910SDouglas Gilbert 	else
230923183910SDouglas Gilbert 		bd_len = 0;
2310773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23111da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23121da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2313cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23141da177e4SLinus Torvalds 		return check_condition_result;
23151da177e4SLinus Torvalds 	}
2316c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2317c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2318d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2319d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2320b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23219447b6ceSMartin K. Petersen 		if (sdebug_wp)
23229447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23239447b6ceSMartin K. Petersen 	} else
232423183910SDouglas Gilbert 		dev_spec = 0x0;
23251da177e4SLinus Torvalds 	if (msense_6) {
23261da177e4SLinus Torvalds 		arr[2] = dev_spec;
232723183910SDouglas Gilbert 		arr[3] = bd_len;
23281da177e4SLinus Torvalds 		offset = 4;
23291da177e4SLinus Torvalds 	} else {
23301da177e4SLinus Torvalds 		arr[3] = dev_spec;
233123183910SDouglas Gilbert 		if (16 == bd_len)
233223183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
233323183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23341da177e4SLinus Torvalds 		offset = 8;
23351da177e4SLinus Torvalds 	}
23361da177e4SLinus Torvalds 	ap = arr + offset;
233728898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
233828898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
233928898873SFUJITA Tomonori 
234023183910SDouglas Gilbert 	if (8 == bd_len) {
2341773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2342773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2343773642d9SDouglas Gilbert 		else
2344773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2345773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
234623183910SDouglas Gilbert 		offset += bd_len;
234723183910SDouglas Gilbert 		ap = arr + offset;
234823183910SDouglas Gilbert 	} else if (16 == bd_len) {
2349773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2350773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
235123183910SDouglas Gilbert 		offset += bd_len;
235223183910SDouglas Gilbert 		ap = arr + offset;
235323183910SDouglas Gilbert 	}
23541da177e4SLinus Torvalds 
2355c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2356c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
235722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23581da177e4SLinus Torvalds 		return check_condition_result;
23591da177e4SLinus Torvalds 	}
2360760f3b03SDouglas Gilbert 	bad_pcode = false;
2361760f3b03SDouglas Gilbert 
23621da177e4SLinus Torvalds 	switch (pcode) {
23631da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23641da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23651da177e4SLinus Torvalds 		offset += len;
23661da177e4SLinus Torvalds 		break;
23671da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23681da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23691da177e4SLinus Torvalds 		offset += len;
23701da177e4SLinus Torvalds 		break;
23711da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2372760f3b03SDouglas Gilbert 		if (is_disk) {
23731da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
23741da177e4SLinus Torvalds 			offset += len;
2375760f3b03SDouglas Gilbert 		} else
2376760f3b03SDouglas Gilbert 			bad_pcode = true;
23771da177e4SLinus Torvalds 		break;
23781da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2379d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
23801da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
23811da177e4SLinus Torvalds 			offset += len;
2382760f3b03SDouglas Gilbert 		} else
2383760f3b03SDouglas Gilbert 			bad_pcode = true;
23841da177e4SLinus Torvalds 		break;
23851da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
23861da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
23871da177e4SLinus Torvalds 		offset += len;
23881da177e4SLinus Torvalds 		break;
2389c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2390c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
239122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2392c65b1445SDouglas Gilbert 			return check_condition_result;
2393c65b1445SDouglas Gilbert 		}
2394c65b1445SDouglas Gilbert 		len = 0;
2395c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2396c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2397c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2398c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2399c65b1445SDouglas Gilbert 						  target_dev_id);
2400c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2401c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2402c65b1445SDouglas Gilbert 		offset += len;
2403c65b1445SDouglas Gilbert 		break;
24041da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24051da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24061da177e4SLinus Torvalds 		offset += len;
24071da177e4SLinus Torvalds 		break;
24081da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2409c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24101da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24111da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2412760f3b03SDouglas Gilbert 			if (is_disk) {
2413760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2414760f3b03SDouglas Gilbert 						      target);
2415760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2416760f3b03SDouglas Gilbert 						       target);
2417d36da305SDouglas Gilbert 			} else if (is_zbc) {
2418d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2419d36da305SDouglas Gilbert 						       target);
2420760f3b03SDouglas Gilbert 			}
24211da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2422c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2423c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2424c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2425c65b1445SDouglas Gilbert 						  target, target_dev_id);
2426c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2427c65b1445SDouglas Gilbert 			}
24281da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2429760f3b03SDouglas Gilbert 			offset += len;
2430c65b1445SDouglas Gilbert 		} else {
243122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2432c65b1445SDouglas Gilbert 			return check_condition_result;
2433c65b1445SDouglas Gilbert 		}
24341da177e4SLinus Torvalds 		break;
24351da177e4SLinus Torvalds 	default:
2436760f3b03SDouglas Gilbert 		bad_pcode = true;
2437760f3b03SDouglas Gilbert 		break;
2438760f3b03SDouglas Gilbert 	}
2439760f3b03SDouglas Gilbert 	if (bad_pcode) {
244022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24411da177e4SLinus Torvalds 		return check_condition_result;
24421da177e4SLinus Torvalds 	}
24431da177e4SLinus Torvalds 	if (msense_6)
24441da177e4SLinus Torvalds 		arr[0] = offset - 1;
2445773642d9SDouglas Gilbert 	else
2446773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
244787c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24481da177e4SLinus Torvalds }
24491da177e4SLinus Torvalds 
2450c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2451c65b1445SDouglas Gilbert 
2452fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2453fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2454c65b1445SDouglas Gilbert {
2455c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2456c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2457c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
245801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2459c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2460c65b1445SDouglas Gilbert 
2461c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2462c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2463c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2464773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2465c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
246622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2467c65b1445SDouglas Gilbert 		return check_condition_result;
2468c65b1445SDouglas Gilbert 	}
2469c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2470c65b1445SDouglas Gilbert 	if (-1 == res)
2471773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2472773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2473cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2474cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2475cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2476773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2477773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
247823183910SDouglas Gilbert 	if (md_len > 2) {
247922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2480c65b1445SDouglas Gilbert 		return check_condition_result;
2481c65b1445SDouglas Gilbert 	}
2482c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2483c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2484c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2485c65b1445SDouglas Gilbert 	if (ps) {
248622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2487c65b1445SDouglas Gilbert 		return check_condition_result;
2488c65b1445SDouglas Gilbert 	}
2489c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2490773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2491c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2492c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2493cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2494c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2495c65b1445SDouglas Gilbert 		return check_condition_result;
2496c65b1445SDouglas Gilbert 	}
2497c65b1445SDouglas Gilbert 	switch (mpage) {
2498cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2499cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2500cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2501cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2502cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2503cbf67842SDouglas Gilbert 		}
2504cbf67842SDouglas Gilbert 		break;
2505c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2506c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2507c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2508c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25099447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25109447b6ceSMartin K. Petersen 				sdebug_wp = true;
25119447b6ceSMartin K. Petersen 			else
25129447b6ceSMartin K. Petersen 				sdebug_wp = false;
2513773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2514cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2515c65b1445SDouglas Gilbert 		}
2516c65b1445SDouglas Gilbert 		break;
2517c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2518c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2519c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2520c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2521cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2522c65b1445SDouglas Gilbert 		}
2523c65b1445SDouglas Gilbert 		break;
2524c65b1445SDouglas Gilbert 	default:
2525c65b1445SDouglas Gilbert 		break;
2526c65b1445SDouglas Gilbert 	}
252722017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2528c65b1445SDouglas Gilbert 	return check_condition_result;
2529cbf67842SDouglas Gilbert set_mode_changed_ua:
2530cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2531cbf67842SDouglas Gilbert 	return 0;
2532c65b1445SDouglas Gilbert }
2533c65b1445SDouglas Gilbert 
2534c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2535c65b1445SDouglas Gilbert {
2536c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2537c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2538c65b1445SDouglas Gilbert 		};
2539c65b1445SDouglas Gilbert 
2540c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2541c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2542c65b1445SDouglas Gilbert }
2543c65b1445SDouglas Gilbert 
2544c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2545c65b1445SDouglas Gilbert {
2546c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2547c65b1445SDouglas Gilbert 		};
2548c65b1445SDouglas Gilbert 
2549c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2550c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2551c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2552c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2553c65b1445SDouglas Gilbert 	}
2554c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2555c65b1445SDouglas Gilbert }
2556c65b1445SDouglas Gilbert 
2557c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2558c65b1445SDouglas Gilbert 
2559c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2560c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2561c65b1445SDouglas Gilbert {
2562ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2563c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
256401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2565c65b1445SDouglas Gilbert 
2566c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2567c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2568c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2569c65b1445SDouglas Gilbert 	if (ppc || sp) {
257022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2571c65b1445SDouglas Gilbert 		return check_condition_result;
2572c65b1445SDouglas Gilbert 	}
2573c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
257423183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2575773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2576c65b1445SDouglas Gilbert 	arr[0] = pcode;
257723183910SDouglas Gilbert 	if (0 == subpcode) {
2578c65b1445SDouglas Gilbert 		switch (pcode) {
2579c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2580c65b1445SDouglas Gilbert 			n = 4;
2581c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2582c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2583c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2584c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2585c65b1445SDouglas Gilbert 			break;
2586c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2587c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2588c65b1445SDouglas Gilbert 			break;
2589c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2590c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2591c65b1445SDouglas Gilbert 			break;
2592c65b1445SDouglas Gilbert 		default:
259322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2594c65b1445SDouglas Gilbert 			return check_condition_result;
2595c65b1445SDouglas Gilbert 		}
259623183910SDouglas Gilbert 	} else if (0xff == subpcode) {
259723183910SDouglas Gilbert 		arr[0] |= 0x40;
259823183910SDouglas Gilbert 		arr[1] = subpcode;
259923183910SDouglas Gilbert 		switch (pcode) {
260023183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
260123183910SDouglas Gilbert 			n = 4;
260223183910SDouglas Gilbert 			arr[n++] = 0x0;
260323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
260423183910SDouglas Gilbert 			arr[n++] = 0x0;
260523183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
260623183910SDouglas Gilbert 			arr[n++] = 0xd;
260723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
260823183910SDouglas Gilbert 			arr[n++] = 0x2f;
260923183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
261023183910SDouglas Gilbert 			arr[3] = n - 4;
261123183910SDouglas Gilbert 			break;
261223183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
261323183910SDouglas Gilbert 			n = 4;
261423183910SDouglas Gilbert 			arr[n++] = 0xd;
261523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
261623183910SDouglas Gilbert 			arr[3] = n - 4;
261723183910SDouglas Gilbert 			break;
261823183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
261923183910SDouglas Gilbert 			n = 4;
262023183910SDouglas Gilbert 			arr[n++] = 0x2f;
262123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
262223183910SDouglas Gilbert 			arr[3] = n - 4;
262323183910SDouglas Gilbert 			break;
262423183910SDouglas Gilbert 		default:
262522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
262623183910SDouglas Gilbert 			return check_condition_result;
262723183910SDouglas Gilbert 		}
262823183910SDouglas Gilbert 	} else {
262922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
263023183910SDouglas Gilbert 		return check_condition_result;
263123183910SDouglas Gilbert 	}
263287c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2633c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
263487c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2635c65b1445SDouglas Gilbert }
2636c65b1445SDouglas Gilbert 
2637f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2638f0d1cf93SDouglas Gilbert {
2639f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2640f0d1cf93SDouglas Gilbert }
2641f0d1cf93SDouglas Gilbert 
2642f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2643f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2644f0d1cf93SDouglas Gilbert {
2645f0d1cf93SDouglas Gilbert 	unsigned int zno;
2646f0d1cf93SDouglas Gilbert 
2647f0d1cf93SDouglas Gilbert 	if (devip->zsize_shift)
2648f0d1cf93SDouglas Gilbert 		zno = lba >> devip->zsize_shift;
2649f0d1cf93SDouglas Gilbert 	else
2650f0d1cf93SDouglas Gilbert 		zno = lba / devip->zsize;
2651f0d1cf93SDouglas Gilbert 	return &devip->zstate[zno];
2652f0d1cf93SDouglas Gilbert }
2653f0d1cf93SDouglas Gilbert 
2654f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2655f0d1cf93SDouglas Gilbert {
2656f0d1cf93SDouglas Gilbert 	return zsp->z_cond == ZBC_NOT_WRITE_POINTER;
2657f0d1cf93SDouglas Gilbert }
2658f0d1cf93SDouglas Gilbert 
2659f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2660f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2661f0d1cf93SDouglas Gilbert {
2662f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2663f0d1cf93SDouglas Gilbert 
2664f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2665f0d1cf93SDouglas Gilbert 		return;
2666f0d1cf93SDouglas Gilbert 
2667f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2668f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2669f0d1cf93SDouglas Gilbert 		return;
2670f0d1cf93SDouglas Gilbert 
2671f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2672f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2673f0d1cf93SDouglas Gilbert 	else
2674f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2675f0d1cf93SDouglas Gilbert 
2676f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2677f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2678f0d1cf93SDouglas Gilbert 	} else {
2679f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2680f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2681f0d1cf93SDouglas Gilbert 	}
2682f0d1cf93SDouglas Gilbert }
2683f0d1cf93SDouglas Gilbert 
2684f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2685f0d1cf93SDouglas Gilbert {
2686f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2687f0d1cf93SDouglas Gilbert 	unsigned int i;
2688f0d1cf93SDouglas Gilbert 
2689f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2690f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2691f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2692f0d1cf93SDouglas Gilbert 			return;
2693f0d1cf93SDouglas Gilbert 		}
2694f0d1cf93SDouglas Gilbert 	}
2695f0d1cf93SDouglas Gilbert }
2696f0d1cf93SDouglas Gilbert 
2697f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2698f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2699f0d1cf93SDouglas Gilbert {
2700f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2701f0d1cf93SDouglas Gilbert 
2702f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2703f0d1cf93SDouglas Gilbert 		return;
2704f0d1cf93SDouglas Gilbert 
2705f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2706f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2707f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2708f0d1cf93SDouglas Gilbert 		return;
2709f0d1cf93SDouglas Gilbert 
2710f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2711f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2712f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2713f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2714f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2715f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2716f0d1cf93SDouglas Gilbert 
2717f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2718f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2719f0d1cf93SDouglas Gilbert 	if (explicit) {
2720f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2721f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2722f0d1cf93SDouglas Gilbert 	} else {
2723f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2724f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2725f0d1cf93SDouglas Gilbert 	}
2726f0d1cf93SDouglas Gilbert }
2727f0d1cf93SDouglas Gilbert 
2728f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2729f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2730f0d1cf93SDouglas Gilbert {
2731f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2732f0d1cf93SDouglas Gilbert 
2733f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2734f0d1cf93SDouglas Gilbert 		return;
2735f0d1cf93SDouglas Gilbert 
2736f0d1cf93SDouglas Gilbert 	zsp->z_wp += num;
2737f0d1cf93SDouglas Gilbert 	if (zsp->z_wp >= zsp->z_start + zsp->z_size)
2738f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
2739f0d1cf93SDouglas Gilbert }
2740f0d1cf93SDouglas Gilbert 
2741f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27429447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27431da177e4SLinus Torvalds {
2744f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2745f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2746f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2747f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2748f0d1cf93SDouglas Gilbert 
2749f0d1cf93SDouglas Gilbert 	if (!write) {
2750f0d1cf93SDouglas Gilbert 		/* Reads cannot cross zone types boundaries */
2751f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2752f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2753f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2754f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2755f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2756f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2757f0d1cf93SDouglas Gilbert 			return check_condition_result;
2758f0d1cf93SDouglas Gilbert 		}
2759f0d1cf93SDouglas Gilbert 		return 0;
2760f0d1cf93SDouglas Gilbert 	}
2761f0d1cf93SDouglas Gilbert 
2762f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2763f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2764f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2765f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2766f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2767f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2768f0d1cf93SDouglas Gilbert 			return check_condition_result;
2769f0d1cf93SDouglas Gilbert 		}
2770f0d1cf93SDouglas Gilbert 		return 0;
2771f0d1cf93SDouglas Gilbert 	}
2772f0d1cf93SDouglas Gilbert 
2773f0d1cf93SDouglas Gilbert 	/* Writes cannot cross sequential zone boundaries */
2774f0d1cf93SDouglas Gilbert 	if (zsp_end != zsp) {
2775f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2776f0d1cf93SDouglas Gilbert 				LBA_OUT_OF_RANGE,
2777f0d1cf93SDouglas Gilbert 				WRITE_BOUNDARY_ASCQ);
2778f0d1cf93SDouglas Gilbert 		return check_condition_result;
2779f0d1cf93SDouglas Gilbert 	}
2780f0d1cf93SDouglas Gilbert 	/* Cannot write full zones */
2781f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC5_FULL) {
2782f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2783f0d1cf93SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
2784f0d1cf93SDouglas Gilbert 		return check_condition_result;
2785f0d1cf93SDouglas Gilbert 	}
2786f0d1cf93SDouglas Gilbert 	/* Writes must be aligned to the zone WP */
2787f0d1cf93SDouglas Gilbert 	if (lba != zsp->z_wp) {
2788f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2789f0d1cf93SDouglas Gilbert 				LBA_OUT_OF_RANGE,
2790f0d1cf93SDouglas Gilbert 				UNALIGNED_WRITE_ASCQ);
2791f0d1cf93SDouglas Gilbert 		return check_condition_result;
2792f0d1cf93SDouglas Gilbert 	}
2793f0d1cf93SDouglas Gilbert 
2794f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2795f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2796f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2797f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2798f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2799f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2800f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2801f0d1cf93SDouglas Gilbert 			return check_condition_result;
2802f0d1cf93SDouglas Gilbert 		}
2803f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2804f0d1cf93SDouglas Gilbert 	}
2805f0d1cf93SDouglas Gilbert 
2806f0d1cf93SDouglas Gilbert 	return 0;
2807f0d1cf93SDouglas Gilbert }
2808f0d1cf93SDouglas Gilbert 
2809f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2810f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2811f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2812f0d1cf93SDouglas Gilbert {
2813f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2814f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2815f0d1cf93SDouglas Gilbert 
2816c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
281722017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28181da177e4SLinus Torvalds 		return check_condition_result;
28191da177e4SLinus Torvalds 	}
2820c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2821c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
282222017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2823cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2824c65b1445SDouglas Gilbert 		return check_condition_result;
2825c65b1445SDouglas Gilbert 	}
28269447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28279447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28289447b6ceSMartin K. Petersen 		return check_condition_result;
28299447b6ceSMartin K. Petersen 	}
2830f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2831f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2832f0d1cf93SDouglas Gilbert 
283319789100SFUJITA Tomonori 	return 0;
283419789100SFUJITA Tomonori }
283519789100SFUJITA Tomonori 
283687c715dcSDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip)
283787c715dcSDouglas Gilbert {
283887c715dcSDouglas Gilbert 	return sdebug_fake_rw ?
283987c715dcSDouglas Gilbert 			NULL : xa_load(per_store_ap, devip->sdbg_host->si_idx);
284087c715dcSDouglas Gilbert }
284187c715dcSDouglas Gilbert 
2842a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
284387c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
284487c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
284519789100SFUJITA Tomonori {
284619789100SFUJITA Tomonori 	int ret;
2847c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2848a4517511SAkinobu Mita 	enum dma_data_direction dir;
284987c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
285087c715dcSDouglas Gilbert 	u8 *fsp;
285119789100SFUJITA Tomonori 
2852c2248fc9SDouglas Gilbert 	if (do_write) {
2853a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
28544f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2855a4517511SAkinobu Mita 	} else {
2856a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2857a4517511SAkinobu Mita 	}
2858a4517511SAkinobu Mita 
285987c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2860a4517511SAkinobu Mita 		return 0;
286187c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2862a4517511SAkinobu Mita 		return -1;
286387c715dcSDouglas Gilbert 	fsp = sip->storep;
286419789100SFUJITA Tomonori 
286519789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
286619789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
286719789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
286819789100SFUJITA Tomonori 
2869386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
287087c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
28710a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2872773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2873a4517511SAkinobu Mita 		return ret;
2874a4517511SAkinobu Mita 
2875a4517511SAkinobu Mita 	if (rest) {
2876386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
287787c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
28780a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
28790a7e69c7SDouglas Gilbert 			    do_write);
2880a4517511SAkinobu Mita 	}
288119789100SFUJITA Tomonori 
288219789100SFUJITA Tomonori 	return ret;
288319789100SFUJITA Tomonori }
288419789100SFUJITA Tomonori 
288587c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
288687c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
288787c715dcSDouglas Gilbert {
288887c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
288987c715dcSDouglas Gilbert 
289087c715dcSDouglas Gilbert 	if (!sdb->length)
289187c715dcSDouglas Gilbert 		return 0;
289287c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
289387c715dcSDouglas Gilbert 		return -1;
289487c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
289587c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
289687c715dcSDouglas Gilbert }
289787c715dcSDouglas Gilbert 
289887c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
289987c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
290038d5c833SDouglas Gilbert  * return false. */
290187c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2902c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
290338d5c833SDouglas Gilbert {
290438d5c833SDouglas Gilbert 	bool res;
290538d5c833SDouglas Gilbert 	u64 block, rest = 0;
290638d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2907773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
290887c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
290938d5c833SDouglas Gilbert 
291038d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
291138d5c833SDouglas Gilbert 	if (block + num > store_blks)
291238d5c833SDouglas Gilbert 		rest = block + num - store_blks;
291338d5c833SDouglas Gilbert 
291487c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
291538d5c833SDouglas Gilbert 	if (!res)
291638d5c833SDouglas Gilbert 		return res;
291738d5c833SDouglas Gilbert 	if (rest)
291887c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
291938d5c833SDouglas Gilbert 			     rest * lb_size);
292038d5c833SDouglas Gilbert 	if (!res)
292138d5c833SDouglas Gilbert 		return res;
2922c3e2fe92SDouglas Gilbert 	if (compare_only)
2923c3e2fe92SDouglas Gilbert 		return true;
292438d5c833SDouglas Gilbert 	arr += num * lb_size;
292587c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
292638d5c833SDouglas Gilbert 	if (rest)
292787c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
292838d5c833SDouglas Gilbert 	return res;
292938d5c833SDouglas Gilbert }
293038d5c833SDouglas Gilbert 
293151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2932beb40ea4SAkinobu Mita {
293351d648afSAkinobu Mita 	__be16 csum;
2934beb40ea4SAkinobu Mita 
2935773642d9SDouglas Gilbert 	if (sdebug_guard)
293651d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
293751d648afSAkinobu Mita 	else
2938beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
293951d648afSAkinobu Mita 
2940beb40ea4SAkinobu Mita 	return csum;
2941beb40ea4SAkinobu Mita }
2942beb40ea4SAkinobu Mita 
29436ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2944beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2945beb40ea4SAkinobu Mita {
2946773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2947beb40ea4SAkinobu Mita 
2948beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2949c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2950beb40ea4SAkinobu Mita 			(unsigned long)sector,
2951beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2952beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2953beb40ea4SAkinobu Mita 		return 0x01;
2954beb40ea4SAkinobu Mita 	}
29558475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2956beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2957c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2958c1287970STomas Winkler 			(unsigned long)sector);
2959beb40ea4SAkinobu Mita 		return 0x03;
2960beb40ea4SAkinobu Mita 	}
29618475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2962beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2963c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2964c1287970STomas Winkler 			(unsigned long)sector);
2965beb40ea4SAkinobu Mita 		return 0x03;
2966beb40ea4SAkinobu Mita 	}
2967beb40ea4SAkinobu Mita 	return 0;
2968beb40ea4SAkinobu Mita }
2969beb40ea4SAkinobu Mita 
297087c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
297165f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2972c6a44287SMartin K. Petersen {
2973be4e11beSAkinobu Mita 	size_t resid;
2974c6a44287SMartin K. Petersen 	void *paddr;
297587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
297687c715dcSDouglas Gilbert 						scp->device->hostdata);
297787c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
297814faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2979be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2980c6a44287SMartin K. Petersen 
2981e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2982e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2983c6a44287SMartin K. Petersen 
298487c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
298587c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
2986be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2987be4e11beSAkinobu Mita 
2988be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
298987c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
299087c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
2991be4e11beSAkinobu Mita 		size_t rest = 0;
299214faa944SAkinobu Mita 
299314faa944SAkinobu Mita 		if (dif_store_end < start + len)
299414faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2995c6a44287SMartin K. Petersen 
2996be4e11beSAkinobu Mita 		paddr = miter.addr;
299714faa944SAkinobu Mita 
299865f72f2aSAkinobu Mita 		if (read)
299965f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
300065f72f2aSAkinobu Mita 		else
300165f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
300265f72f2aSAkinobu Mita 
300365f72f2aSAkinobu Mita 		if (rest) {
300465f72f2aSAkinobu Mita 			if (read)
300514faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
300665f72f2aSAkinobu Mita 			else
300765f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
300865f72f2aSAkinobu Mita 		}
3009c6a44287SMartin K. Petersen 
3010e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3011c6a44287SMartin K. Petersen 		resid -= len;
3012c6a44287SMartin K. Petersen 	}
3013be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3014bb8c063cSAkinobu Mita }
3015c6a44287SMartin K. Petersen 
301687c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3017bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3018bb8c063cSAkinobu Mita {
3019bb8c063cSAkinobu Mita 	unsigned int i;
3020bb8c063cSAkinobu Mita 	sector_t sector;
302187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
302287c715dcSDouglas Gilbert 						scp->device->hostdata);
302387c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3024bb8c063cSAkinobu Mita 
3025c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3026bb8c063cSAkinobu Mita 		int ret;
3027bb8c063cSAkinobu Mita 
3028bb8c063cSAkinobu Mita 		sector = start_sec + i;
302987c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3030bb8c063cSAkinobu Mita 
303151d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3032bb8c063cSAkinobu Mita 			continue;
3033bb8c063cSAkinobu Mita 
303487c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
303587c715dcSDouglas Gilbert 				 ei_lba);
3036bb8c063cSAkinobu Mita 		if (ret) {
3037bb8c063cSAkinobu Mita 			dif_errors++;
3038bb8c063cSAkinobu Mita 			return ret;
3039bb8c063cSAkinobu Mita 		}
3040bb8c063cSAkinobu Mita 	}
3041bb8c063cSAkinobu Mita 
304287c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3043c6a44287SMartin K. Petersen 	dix_reads++;
3044c6a44287SMartin K. Petersen 
3045c6a44287SMartin K. Petersen 	return 0;
3046c6a44287SMartin K. Petersen }
3047c6a44287SMartin K. Petersen 
3048fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
304919789100SFUJITA Tomonori {
305087c715dcSDouglas Gilbert 	bool check_prot;
3051c2248fc9SDouglas Gilbert 	u32 num;
3052c2248fc9SDouglas Gilbert 	u32 ei_lba;
305319789100SFUJITA Tomonori 	int ret;
305487c715dcSDouglas Gilbert 	u64 lba;
305587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
305687c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
305787c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
305887c715dcSDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
305919789100SFUJITA Tomonori 
3060c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3061c2248fc9SDouglas Gilbert 	case READ_16:
3062c2248fc9SDouglas Gilbert 		ei_lba = 0;
3063c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3064c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3065c2248fc9SDouglas Gilbert 		check_prot = true;
3066c2248fc9SDouglas Gilbert 		break;
3067c2248fc9SDouglas Gilbert 	case READ_10:
3068c2248fc9SDouglas Gilbert 		ei_lba = 0;
3069c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3070c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3071c2248fc9SDouglas Gilbert 		check_prot = true;
3072c2248fc9SDouglas Gilbert 		break;
3073c2248fc9SDouglas Gilbert 	case READ_6:
3074c2248fc9SDouglas Gilbert 		ei_lba = 0;
3075c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3076c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3077c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3078c2248fc9SDouglas Gilbert 		check_prot = true;
3079c2248fc9SDouglas Gilbert 		break;
3080c2248fc9SDouglas Gilbert 	case READ_12:
3081c2248fc9SDouglas Gilbert 		ei_lba = 0;
3082c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3083c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3084c2248fc9SDouglas Gilbert 		check_prot = true;
3085c2248fc9SDouglas Gilbert 		break;
3086c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3087c2248fc9SDouglas Gilbert 		ei_lba = 0;
3088c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3089c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3090c2248fc9SDouglas Gilbert 		check_prot = false;
3091c2248fc9SDouglas Gilbert 		break;
3092c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3093c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3094c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3095c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3096c2248fc9SDouglas Gilbert 		check_prot = false;
3097c2248fc9SDouglas Gilbert 		break;
3098c2248fc9SDouglas Gilbert 	}
3099f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31008475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3101c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3102c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3103c2248fc9SDouglas Gilbert 			return check_condition_result;
3104c2248fc9SDouglas Gilbert 		}
31058475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31068475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3107c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3108c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3109c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3110c2248fc9SDouglas Gilbert 	}
3111f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3112c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
3113c2248fc9SDouglas Gilbert 
3114c4837394SDouglas Gilbert 		if (sqcp) {
3115c4837394SDouglas Gilbert 			if (sqcp->inj_short)
3116c2248fc9SDouglas Gilbert 				num /= 2;
3117c2248fc9SDouglas Gilbert 		}
3118c4837394SDouglas Gilbert 	} else
3119c4837394SDouglas Gilbert 		sqcp = NULL;
3120c2248fc9SDouglas Gilbert 
31219447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31229447b6ceSMartin K. Petersen 	if (ret)
31239447b6ceSMartin K. Petersen 		return ret;
3124f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3125d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3126d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3127c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3128c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3129c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3130c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3131c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
313232f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
313332f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3134c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3135c65b1445SDouglas Gilbert 		}
3136c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
31371da177e4SLinus Torvalds 		return check_condition_result;
31381da177e4SLinus Torvalds 	}
3139c6a44287SMartin K. Petersen 
314067da413fSDouglas Gilbert 	read_lock(macc_lckp);
31416c78cc06SAkinobu Mita 
3142c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3143f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3144c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
3145c6a44287SMartin K. Petersen 
3146c6a44287SMartin K. Petersen 		if (prot_ret) {
314767da413fSDouglas Gilbert 			read_unlock(macc_lckp);
3148c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
3149c6a44287SMartin K. Petersen 			return illegal_condition_result;
3150c6a44287SMartin K. Petersen 		}
3151c6a44287SMartin K. Petersen 	}
3152c6a44287SMartin K. Petersen 
315387c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
315467da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3155f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3156a4517511SAkinobu Mita 		return DID_ERROR << 16;
3157a4517511SAkinobu Mita 
315842d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3159a4517511SAkinobu Mita 
3160c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
3161c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
3162c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
3163c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
3164c2248fc9SDouglas Gilbert 			return check_condition_result;
3165c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
3166c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
3167c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3168c2248fc9SDouglas Gilbert 			return check_condition_result;
3169c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
3170c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3171c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3172c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3173c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
3174c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3175c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3176c2248fc9SDouglas Gilbert 		}
3177c2248fc9SDouglas Gilbert 	}
3178a4517511SAkinobu Mita 	return 0;
31791da177e4SLinus Torvalds }
31801da177e4SLinus Torvalds 
318158a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
3182c6a44287SMartin K. Petersen {
3183cbf67842SDouglas Gilbert 	int i, j, n;
3184c6a44287SMartin K. Petersen 
3185cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
3186c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
3187cbf67842SDouglas Gilbert 		char b[128];
3188c6a44287SMartin K. Petersen 
3189cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
3190c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
3191c6a44287SMartin K. Petersen 
3192cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
3193cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3194cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
3195cbf67842SDouglas Gilbert 			else
3196cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3197cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
3198cbf67842SDouglas Gilbert 		}
3199cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
3200c6a44287SMartin K. Petersen 	}
3201c6a44287SMartin K. Petersen }
3202c6a44287SMartin K. Petersen 
3203c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3204395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3205c6a44287SMartin K. Petersen {
3206be4e11beSAkinobu Mita 	int ret;
32076ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3208be4e11beSAkinobu Mita 	void *daddr;
320965f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3210c6a44287SMartin K. Petersen 	int ppage_offset;
3211be4e11beSAkinobu Mita 	int dpage_offset;
3212be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3213be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3214c6a44287SMartin K. Petersen 
3215c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3216c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3217c6a44287SMartin K. Petersen 
3218be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3219be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3220be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3221be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3222be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3223c6a44287SMartin K. Petersen 
3224be4e11beSAkinobu Mita 	/* For each protection page */
3225be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3226be4e11beSAkinobu Mita 		dpage_offset = 0;
3227be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3228be4e11beSAkinobu Mita 			ret = 0x01;
3229be4e11beSAkinobu Mita 			goto out;
3230c6a44287SMartin K. Petersen 		}
3231c6a44287SMartin K. Petersen 
3232be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32336ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3234be4e11beSAkinobu Mita 			/* If we're at the end of the current
3235be4e11beSAkinobu Mita 			 * data page advance to the next one
3236be4e11beSAkinobu Mita 			 */
3237be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3238be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3239be4e11beSAkinobu Mita 					ret = 0x01;
3240be4e11beSAkinobu Mita 					goto out;
3241be4e11beSAkinobu Mita 				}
3242be4e11beSAkinobu Mita 				dpage_offset = 0;
3243be4e11beSAkinobu Mita 			}
3244c6a44287SMartin K. Petersen 
3245be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3246be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3247be4e11beSAkinobu Mita 
3248be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
3249beb40ea4SAkinobu Mita 			if (ret) {
3250773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
3251395cef03SMartin K. Petersen 				goto out;
3252395cef03SMartin K. Petersen 			}
3253395cef03SMartin K. Petersen 
3254c6a44287SMartin K. Petersen 			sector++;
3255395cef03SMartin K. Petersen 			ei_lba++;
3256773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3257c6a44287SMartin K. Petersen 		}
3258be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3259be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3260c6a44287SMartin K. Petersen 	}
3261be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3262c6a44287SMartin K. Petersen 
326365f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3264c6a44287SMartin K. Petersen 	dix_writes++;
3265c6a44287SMartin K. Petersen 
3266c6a44287SMartin K. Petersen 	return 0;
3267c6a44287SMartin K. Petersen 
3268c6a44287SMartin K. Petersen out:
3269c6a44287SMartin K. Petersen 	dif_errors++;
3270be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3271be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3272c6a44287SMartin K. Petersen 	return ret;
3273c6a44287SMartin K. Petersen }
3274c6a44287SMartin K. Petersen 
3275b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3276b90ebc3dSAkinobu Mita {
3277773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3278773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3279773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3280b90ebc3dSAkinobu Mita 	return lba;
3281b90ebc3dSAkinobu Mita }
3282b90ebc3dSAkinobu Mita 
3283b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3284b90ebc3dSAkinobu Mita {
3285773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3286a027b5b9SAkinobu Mita 
3287773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3288773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3289a027b5b9SAkinobu Mita 	return lba;
3290a027b5b9SAkinobu Mita }
3291a027b5b9SAkinobu Mita 
329287c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
329387c715dcSDouglas Gilbert 			      unsigned int *num)
329444d92694SMartin K. Petersen {
3295b90ebc3dSAkinobu Mita 	sector_t end;
3296b90ebc3dSAkinobu Mita 	unsigned int mapped;
3297b90ebc3dSAkinobu Mita 	unsigned long index;
3298b90ebc3dSAkinobu Mita 	unsigned long next;
329944d92694SMartin K. Petersen 
3300b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
330187c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
330244d92694SMartin K. Petersen 
330344d92694SMartin K. Petersen 	if (mapped)
330487c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
330544d92694SMartin K. Petersen 	else
330687c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
330744d92694SMartin K. Petersen 
3308b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
330944d92694SMartin K. Petersen 	*num = end - lba;
331044d92694SMartin K. Petersen 	return mapped;
331144d92694SMartin K. Petersen }
331244d92694SMartin K. Petersen 
331387c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
331487c715dcSDouglas Gilbert 		       unsigned int len)
331544d92694SMartin K. Petersen {
331644d92694SMartin K. Petersen 	sector_t end = lba + len;
331744d92694SMartin K. Petersen 
331844d92694SMartin K. Petersen 	while (lba < end) {
3319b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
332044d92694SMartin K. Petersen 
3321b90ebc3dSAkinobu Mita 		if (index < map_size)
332287c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
332344d92694SMartin K. Petersen 
3324b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
332544d92694SMartin K. Petersen 	}
332644d92694SMartin K. Petersen }
332744d92694SMartin K. Petersen 
332887c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
332987c715dcSDouglas Gilbert 			 unsigned int len)
333044d92694SMartin K. Petersen {
333144d92694SMartin K. Petersen 	sector_t end = lba + len;
333287c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
333344d92694SMartin K. Petersen 
333444d92694SMartin K. Petersen 	while (lba < end) {
3335b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
333644d92694SMartin K. Petersen 
3337b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3338773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3339b90ebc3dSAkinobu Mita 		    index < map_size) {
334087c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3341760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
334287c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3343760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3344773642d9SDouglas Gilbert 				       sdebug_sector_size *
3345773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3346be1dd78dSEric Sandeen 			}
334787c715dcSDouglas Gilbert 			if (sip->dif_storep) {
334887c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
334987c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3350773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3351e9926b43SAkinobu Mita 			}
3352b90ebc3dSAkinobu Mita 		}
3353b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
335444d92694SMartin K. Petersen 	}
335544d92694SMartin K. Petersen }
335644d92694SMartin K. Petersen 
3357fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
33581da177e4SLinus Torvalds {
335987c715dcSDouglas Gilbert 	bool check_prot;
3360c2248fc9SDouglas Gilbert 	u32 num;
3361c2248fc9SDouglas Gilbert 	u32 ei_lba;
336219789100SFUJITA Tomonori 	int ret;
336387c715dcSDouglas Gilbert 	u64 lba;
336487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
336587c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
336687c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
33671da177e4SLinus Torvalds 
3368c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3369c2248fc9SDouglas Gilbert 	case WRITE_16:
3370c2248fc9SDouglas Gilbert 		ei_lba = 0;
3371c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3372c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3373c2248fc9SDouglas Gilbert 		check_prot = true;
3374c2248fc9SDouglas Gilbert 		break;
3375c2248fc9SDouglas Gilbert 	case WRITE_10:
3376c2248fc9SDouglas Gilbert 		ei_lba = 0;
3377c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3378c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3379c2248fc9SDouglas Gilbert 		check_prot = true;
3380c2248fc9SDouglas Gilbert 		break;
3381c2248fc9SDouglas Gilbert 	case WRITE_6:
3382c2248fc9SDouglas Gilbert 		ei_lba = 0;
3383c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3384c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3385c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3386c2248fc9SDouglas Gilbert 		check_prot = true;
3387c2248fc9SDouglas Gilbert 		break;
3388c2248fc9SDouglas Gilbert 	case WRITE_12:
3389c2248fc9SDouglas Gilbert 		ei_lba = 0;
3390c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3391c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3392c2248fc9SDouglas Gilbert 		check_prot = true;
3393c2248fc9SDouglas Gilbert 		break;
3394c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3395c2248fc9SDouglas Gilbert 		ei_lba = 0;
3396c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3397c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3398c2248fc9SDouglas Gilbert 		check_prot = false;
3399c2248fc9SDouglas Gilbert 		break;
3400c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3401c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3402c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3403c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3404c2248fc9SDouglas Gilbert 		check_prot = false;
3405c2248fc9SDouglas Gilbert 		break;
3406c2248fc9SDouglas Gilbert 	}
3407f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34088475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3409c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3410c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3411c2248fc9SDouglas Gilbert 			return check_condition_result;
3412c2248fc9SDouglas Gilbert 		}
34138475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34148475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3415c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3416c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3417c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3418c2248fc9SDouglas Gilbert 	}
3419f0d1cf93SDouglas Gilbert 
342067da413fSDouglas Gilbert 	write_lock(macc_lckp);
3421f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3422f0d1cf93SDouglas Gilbert 	if (ret) {
3423f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3424f0d1cf93SDouglas Gilbert 		return ret;
3425f0d1cf93SDouglas Gilbert 	}
34266c78cc06SAkinobu Mita 
3427c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3428f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3429c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3430c6a44287SMartin K. Petersen 
3431c6a44287SMartin K. Petersen 		if (prot_ret) {
343267da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3433c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3434c6a44287SMartin K. Petersen 			return illegal_condition_result;
3435c6a44287SMartin K. Petersen 		}
3436c6a44287SMartin K. Petersen 	}
3437c6a44287SMartin K. Petersen 
343887c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3439f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
344087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3441f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3442f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3443f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
344467da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3445f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3446773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3447c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3448c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3449c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3450cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3451773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
345244d92694SMartin K. Petersen 
3453f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3454c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3455c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3456c2248fc9SDouglas Gilbert 
3457c4837394SDouglas Gilbert 		if (sqcp) {
3458c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3459c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3460c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3461c2248fc9SDouglas Gilbert 				return check_condition_result;
3462c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3463c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3464c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3465c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3466c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3467c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3468c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3469c2248fc9SDouglas Gilbert 			}
3470c2248fc9SDouglas Gilbert 		}
3471c4837394SDouglas Gilbert 	}
34721da177e4SLinus Torvalds 	return 0;
34731da177e4SLinus Torvalds }
34741da177e4SLinus Torvalds 
3475481b5e5cSDouglas Gilbert /*
3476481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3477481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3478481b5e5cSDouglas Gilbert  */
3479481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3480481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3481481b5e5cSDouglas Gilbert {
3482481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3483481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3484481b5e5cSDouglas Gilbert 	u8 *up;
348587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
348687c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3487481b5e5cSDouglas Gilbert 	u8 wrprotect;
3488481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3489481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3490481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3491481b5e5cSDouglas Gilbert 	u32 ei_lba;
3492481b5e5cSDouglas Gilbert 	u64 lba;
3493481b5e5cSDouglas Gilbert 	int ret, res;
3494481b5e5cSDouglas Gilbert 	bool is_16;
3495481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3496481b5e5cSDouglas Gilbert 
3497481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3498481b5e5cSDouglas Gilbert 		is_16 = false;
3499481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3500481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3501481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3502481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3503481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3504481b5e5cSDouglas Gilbert 		is_16 = true;
3505481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3506481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3507481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3508481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3509481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3510481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3511481b5e5cSDouglas Gilbert 			    wrprotect) {
3512481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3513481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3514481b5e5cSDouglas Gilbert 			}
3515481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3516481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3517481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3518481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3519481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3520481b5e5cSDouglas Gilbert 		}
3521481b5e5cSDouglas Gilbert 	}
3522481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3523481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3524481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3525481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3526481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3527481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3528481b5e5cSDouglas Gilbert 				my_name, __func__);
3529481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3530481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3531481b5e5cSDouglas Gilbert 	}
3532481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3533481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3534481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3535481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3536481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3537481b5e5cSDouglas Gilbert 				my_name, __func__);
3538481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3539481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3540481b5e5cSDouglas Gilbert 	}
3541481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3542481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3543481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3544481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3545481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3546481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3547481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3548481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3549481b5e5cSDouglas Gilbert 	if (res == -1) {
3550481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3551481b5e5cSDouglas Gilbert 		goto err_out;
3552481b5e5cSDouglas Gilbert 	}
3553481b5e5cSDouglas Gilbert 
355467da413fSDouglas Gilbert 	write_lock(macc_lckp);
3555481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3556481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3557481b5e5cSDouglas Gilbert 	cum_lb = 0;
3558481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3559481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3560481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3561481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3562481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3563481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3564481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3565481b5e5cSDouglas Gilbert 		if (num == 0)
3566481b5e5cSDouglas Gilbert 			continue;
35679447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3568481b5e5cSDouglas Gilbert 		if (ret)
3569481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3570481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3571481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3572481b5e5cSDouglas Gilbert 
3573481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3574481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3575481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3576481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3577481b5e5cSDouglas Gilbert 				    my_name, __func__);
3578481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3579481b5e5cSDouglas Gilbert 					0);
3580481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3581481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3582481b5e5cSDouglas Gilbert 		}
3583481b5e5cSDouglas Gilbert 
3584481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3585481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3586481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3587481b5e5cSDouglas Gilbert 							 ei_lba);
3588481b5e5cSDouglas Gilbert 
3589481b5e5cSDouglas Gilbert 			if (prot_ret) {
3590481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3591481b5e5cSDouglas Gilbert 						prot_ret);
3592481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3593481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3594481b5e5cSDouglas Gilbert 			}
3595481b5e5cSDouglas Gilbert 		}
3596481b5e5cSDouglas Gilbert 
359787c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3598f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3599f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3600f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3601481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
360287c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3603481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3604481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3605481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3606481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3607481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3608481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3609481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3610481b5e5cSDouglas Gilbert 
3611481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3612481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3613481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3614481b5e5cSDouglas Gilbert 
3615481b5e5cSDouglas Gilbert 			if (sqcp) {
3616481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3617481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3618481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3619481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3620481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3621481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3622481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3623481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3624481b5e5cSDouglas Gilbert 							0x10, 1);
3625481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3626481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3627481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3628481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3629481b5e5cSDouglas Gilbert 							0x10, 1);
3630481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3631481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3632481b5e5cSDouglas Gilbert 				}
3633481b5e5cSDouglas Gilbert 			}
3634481b5e5cSDouglas Gilbert 		}
3635481b5e5cSDouglas Gilbert 		sg_off += num_by;
3636481b5e5cSDouglas Gilbert 		cum_lb += num;
3637481b5e5cSDouglas Gilbert 	}
3638481b5e5cSDouglas Gilbert 	ret = 0;
3639481b5e5cSDouglas Gilbert err_out_unlock:
364067da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3641481b5e5cSDouglas Gilbert err_out:
3642481b5e5cSDouglas Gilbert 	kfree(lrdp);
3643481b5e5cSDouglas Gilbert 	return ret;
3644481b5e5cSDouglas Gilbert }
3645481b5e5cSDouglas Gilbert 
3646fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3647fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
364844d92694SMartin K. Petersen {
3649f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3650f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
365144d92694SMartin K. Petersen 	unsigned long long i;
365240d07b52SDouglas Gilbert 	u64 block, lbaa;
365387c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
365487c715dcSDouglas Gilbert 	int ret;
365587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
365687c715dcSDouglas Gilbert 						scp->device->hostdata);
365787c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
365840d07b52SDouglas Gilbert 	u8 *fs1p;
365987c715dcSDouglas Gilbert 	u8 *fsp;
366044d92694SMartin K. Petersen 
366167da413fSDouglas Gilbert 	write_lock(macc_lckp);
366244d92694SMartin K. Petersen 
3663f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3664f0d1cf93SDouglas Gilbert 	if (ret) {
3665f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3666f0d1cf93SDouglas Gilbert 		return ret;
3667f0d1cf93SDouglas Gilbert 	}
3668f0d1cf93SDouglas Gilbert 
36699ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
367087c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
367144d92694SMartin K. Petersen 		goto out;
367244d92694SMartin K. Petersen 	}
367340d07b52SDouglas Gilbert 	lbaa = lba;
367440d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3675c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
367687c715dcSDouglas Gilbert 	fsp = sip->storep;
367787c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3678c2248fc9SDouglas Gilbert 	if (ndob) {
367940d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3680c2248fc9SDouglas Gilbert 		ret = 0;
3681c2248fc9SDouglas Gilbert 	} else
368240d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
368344d92694SMartin K. Petersen 
368444d92694SMartin K. Petersen 	if (-1 == ret) {
368567da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3686773642d9SDouglas Gilbert 		return DID_ERROR << 16;
368740d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3688c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3689e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
369040d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
369144d92694SMartin K. Petersen 
369244d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
369340d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
369440d07b52SDouglas Gilbert 		lbaa = lba + i;
369540d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
369687c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
369740d07b52SDouglas Gilbert 	}
36989ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
369987c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3700f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3701f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3702f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
370344d92694SMartin K. Petersen out:
370467da413fSDouglas Gilbert 	write_unlock(macc_lckp);
370544d92694SMartin K. Petersen 
370644d92694SMartin K. Petersen 	return 0;
370744d92694SMartin K. Petersen }
370844d92694SMartin K. Petersen 
3709fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3710fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3711c2248fc9SDouglas Gilbert {
3712c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3713c2248fc9SDouglas Gilbert 	u32 lba;
3714c2248fc9SDouglas Gilbert 	u16 num;
3715c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3716c2248fc9SDouglas Gilbert 	bool unmap = false;
3717c2248fc9SDouglas Gilbert 
3718c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3719773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3720c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3721c2248fc9SDouglas Gilbert 			return check_condition_result;
3722c2248fc9SDouglas Gilbert 		} else
3723c2248fc9SDouglas Gilbert 			unmap = true;
3724c2248fc9SDouglas Gilbert 	}
3725c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3726c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3727773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3728c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3729c2248fc9SDouglas Gilbert 		return check_condition_result;
3730c2248fc9SDouglas Gilbert 	}
3731c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3732c2248fc9SDouglas Gilbert }
3733c2248fc9SDouglas Gilbert 
3734fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3735fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3736c2248fc9SDouglas Gilbert {
3737c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3738c2248fc9SDouglas Gilbert 	u64 lba;
3739c2248fc9SDouglas Gilbert 	u32 num;
3740c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3741c2248fc9SDouglas Gilbert 	bool unmap = false;
3742c2248fc9SDouglas Gilbert 	bool ndob = false;
3743c2248fc9SDouglas Gilbert 
3744c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3745773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3746c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3747c2248fc9SDouglas Gilbert 			return check_condition_result;
3748c2248fc9SDouglas Gilbert 		} else
3749c2248fc9SDouglas Gilbert 			unmap = true;
3750c2248fc9SDouglas Gilbert 	}
3751c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3752c2248fc9SDouglas Gilbert 		ndob = true;
3753c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3754c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3755773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3756c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3757c2248fc9SDouglas Gilbert 		return check_condition_result;
3758c2248fc9SDouglas Gilbert 	}
3759c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3760c2248fc9SDouglas Gilbert }
3761c2248fc9SDouglas Gilbert 
3762acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3763acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3764acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3765fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3766fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3767acafd0b9SEwan D. Milne {
3768acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3769acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3770acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3771acafd0b9SEwan D. Milne 	u8 mode;
3772acafd0b9SEwan D. Milne 
3773acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3774acafd0b9SEwan D. Milne 	switch (mode) {
3775acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3776acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3777acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3778acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3779acafd0b9SEwan D. Milne 		break;
3780acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3781acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3782acafd0b9SEwan D. Milne 		break;
3783acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3784acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3785acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3786acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3787acafd0b9SEwan D. Milne 				    dev_list)
3788acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3789acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3790acafd0b9SEwan D. Milne 				if (devip != dp)
3791acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3792acafd0b9SEwan D. Milne 						dp->uas_bm);
3793acafd0b9SEwan D. Milne 			}
3794acafd0b9SEwan D. Milne 		break;
3795acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3796acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3797acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3798acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3799acafd0b9SEwan D. Milne 				    dev_list)
3800acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3801acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3802acafd0b9SEwan D. Milne 					dp->uas_bm);
3803acafd0b9SEwan D. Milne 		break;
3804acafd0b9SEwan D. Milne 	default:
3805acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3806acafd0b9SEwan D. Milne 		break;
3807acafd0b9SEwan D. Milne 	}
3808acafd0b9SEwan D. Milne 	return 0;
3809acafd0b9SEwan D. Milne }
3810acafd0b9SEwan D. Milne 
3811fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3812fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
381338d5c833SDouglas Gilbert {
381438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
381538d5c833SDouglas Gilbert 	u8 *arr;
381687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
381787c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
381838d5c833SDouglas Gilbert 	u64 lba;
381938d5c833SDouglas Gilbert 	u32 dnum;
3820773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
382138d5c833SDouglas Gilbert 	u8 num;
382238d5c833SDouglas Gilbert 	int ret;
3823d467d31fSDouglas Gilbert 	int retval = 0;
382438d5c833SDouglas Gilbert 
3825d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
382638d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
382738d5c833SDouglas Gilbert 	if (0 == num)
382838d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38298475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
383038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
383138d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
383238d5c833SDouglas Gilbert 		return check_condition_result;
383338d5c833SDouglas Gilbert 	}
38348475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
38358475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
383638d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
383738d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
383838d5c833SDouglas Gilbert 			    "to DIF device\n");
38399447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
38409447b6ceSMartin K. Petersen 	if (ret)
38419447b6ceSMartin K. Petersen 		return ret;
3842d467d31fSDouglas Gilbert 	dnum = 2 * num;
38436396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3844d467d31fSDouglas Gilbert 	if (NULL == arr) {
3845d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3846d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3847d467d31fSDouglas Gilbert 		return check_condition_result;
3848d467d31fSDouglas Gilbert 	}
384938d5c833SDouglas Gilbert 
385067da413fSDouglas Gilbert 	write_lock(macc_lckp);
385138d5c833SDouglas Gilbert 
385287c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
385338d5c833SDouglas Gilbert 	if (ret == -1) {
3854d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3855d467d31fSDouglas Gilbert 		goto cleanup;
3856773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
385738d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
385838d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
385938d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3860c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
386138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3862d467d31fSDouglas Gilbert 		retval = check_condition_result;
3863d467d31fSDouglas Gilbert 		goto cleanup;
386438d5c833SDouglas Gilbert 	}
386538d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
386687c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3867d467d31fSDouglas Gilbert cleanup:
386867da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3869d467d31fSDouglas Gilbert 	kfree(arr);
3870d467d31fSDouglas Gilbert 	return retval;
387138d5c833SDouglas Gilbert }
387238d5c833SDouglas Gilbert 
387344d92694SMartin K. Petersen struct unmap_block_desc {
387444d92694SMartin K. Petersen 	__be64	lba;
387544d92694SMartin K. Petersen 	__be32	blocks;
387644d92694SMartin K. Petersen 	__be32	__reserved;
387744d92694SMartin K. Petersen };
387844d92694SMartin K. Petersen 
3879fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
388044d92694SMartin K. Petersen {
388144d92694SMartin K. Petersen 	unsigned char *buf;
388244d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
388387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
388487c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
388544d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
388644d92694SMartin K. Petersen 	int ret;
388744d92694SMartin K. Petersen 
3888c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3889c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3890c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3891c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
389244d92694SMartin K. Petersen 
389344d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3894773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3895c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
389644d92694SMartin K. Petersen 		return check_condition_result;
3897c2248fc9SDouglas Gilbert 	}
389844d92694SMartin K. Petersen 
3899b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3900c2248fc9SDouglas Gilbert 	if (!buf) {
3901c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3902c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3903c2248fc9SDouglas Gilbert 		return check_condition_result;
3904c2248fc9SDouglas Gilbert 	}
3905c2248fc9SDouglas Gilbert 
3906c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
390744d92694SMartin K. Petersen 
390844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
390944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
391044d92694SMartin K. Petersen 
391144d92694SMartin K. Petersen 	desc = (void *)&buf[8];
391244d92694SMartin K. Petersen 
391367da413fSDouglas Gilbert 	write_lock(macc_lckp);
39146c78cc06SAkinobu Mita 
391544d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
391644d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
391744d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
391844d92694SMartin K. Petersen 
39199447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
392044d92694SMartin K. Petersen 		if (ret)
392144d92694SMartin K. Petersen 			goto out;
392244d92694SMartin K. Petersen 
392387c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
392444d92694SMartin K. Petersen 	}
392544d92694SMartin K. Petersen 
392644d92694SMartin K. Petersen 	ret = 0;
392744d92694SMartin K. Petersen 
392844d92694SMartin K. Petersen out:
392967da413fSDouglas Gilbert 	write_unlock(macc_lckp);
393044d92694SMartin K. Petersen 	kfree(buf);
393144d92694SMartin K. Petersen 
393244d92694SMartin K. Petersen 	return ret;
393344d92694SMartin K. Petersen }
393444d92694SMartin K. Petersen 
393544d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
393644d92694SMartin K. Petersen 
3937fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3938fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
393944d92694SMartin K. Petersen {
3940c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
394187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
3942c2248fc9SDouglas Gilbert 	u64 lba;
3943c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
394444d92694SMartin K. Petersen 	int ret;
394587c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
394644d92694SMartin K. Petersen 
3947c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3948c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
394944d92694SMartin K. Petersen 
395044d92694SMartin K. Petersen 	if (alloc_len < 24)
395144d92694SMartin K. Petersen 		return 0;
395244d92694SMartin K. Petersen 
39539447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
395444d92694SMartin K. Petersen 	if (ret)
395544d92694SMartin K. Petersen 		return ret;
395644d92694SMartin K. Petersen 
3957c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
395887c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
3959c2248fc9SDouglas Gilbert 	else {
3960c2248fc9SDouglas Gilbert 		mapped = 1;
3961c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3962c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3963c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3964c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3965c2248fc9SDouglas Gilbert 		else
3966c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3967c2248fc9SDouglas Gilbert 	}
396844d92694SMartin K. Petersen 
396944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3970c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3971c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3972c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3973c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
397444d92694SMartin K. Petersen 
3975c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
397644d92694SMartin K. Petersen }
397744d92694SMartin K. Petersen 
397880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
397980c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
398080c49563SDouglas Gilbert {
39814f2c8bf6SDouglas Gilbert 	int res = 0;
398280c49563SDouglas Gilbert 	u64 lba;
398380c49563SDouglas Gilbert 	u32 num_blocks;
398480c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
398580c49563SDouglas Gilbert 
398680c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
398780c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
398880c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
398980c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
399080c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
399180c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
399280c49563SDouglas Gilbert 	}
399380c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
399480c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
399580c49563SDouglas Gilbert 		return check_condition_result;
399680c49563SDouglas Gilbert 	}
39974f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
39984f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
39994f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40004f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40014f2c8bf6SDouglas Gilbert 	return res;
400280c49563SDouglas Gilbert }
400380c49563SDouglas Gilbert 
4004ed9f3e25SDouglas Gilbert /*
4005ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4006ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4007ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4008ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4009ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4010ed9f3e25SDouglas Gilbert  */
4011ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4012ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4013ed9f3e25SDouglas Gilbert {
4014ed9f3e25SDouglas Gilbert 	int res = 0;
4015ed9f3e25SDouglas Gilbert 	u64 lba;
4016ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4017ed9f3e25SDouglas Gilbert 	u32 nblks;
4018ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4019ed9f3e25SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4020ed9f3e25SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4021ed9f3e25SDouglas Gilbert 	u8 *fsp = sip ? sip->storep : NULL;
4022ed9f3e25SDouglas Gilbert 
4023ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4024ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4025ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4026ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4027ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4028ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4029ed9f3e25SDouglas Gilbert 	}
4030ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4031ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4032ed9f3e25SDouglas Gilbert 		return check_condition_result;
4033ed9f3e25SDouglas Gilbert 	}
4034ed9f3e25SDouglas Gilbert 	if (!fsp)
4035ed9f3e25SDouglas Gilbert 		goto fini;
4036ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4037ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4038ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4039ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4040ed9f3e25SDouglas Gilbert 
4041ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4042ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4043ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4044ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4045ed9f3e25SDouglas Gilbert 	if (rest)
4046ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4047ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4048ed9f3e25SDouglas Gilbert fini:
4049ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4050ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4051ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4052ed9f3e25SDouglas Gilbert }
4053ed9f3e25SDouglas Gilbert 
4054fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4055fb0cc8d1SDouglas Gilbert 
40568d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
40578d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
40588d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
40598d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
40608d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
40618d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
40628d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
40638d039e22SDouglas Gilbert  */
40641da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
40651da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
40661da177e4SLinus Torvalds {
406701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
40688d039e22SDouglas Gilbert 	unsigned int alloc_len;
40698d039e22SDouglas Gilbert 	unsigned char select_report;
40708d039e22SDouglas Gilbert 	u64 lun;
40718d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4072fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
40738d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
40748d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
40758d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
40768d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4077fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4078fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4079fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
40801da177e4SLinus Torvalds 
408119c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
40828d039e22SDouglas Gilbert 
40838d039e22SDouglas Gilbert 	select_report = cmd[2];
40848d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
40858d039e22SDouglas Gilbert 
40868d039e22SDouglas Gilbert 	if (alloc_len < 4) {
40878d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
40888d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
40891da177e4SLinus Torvalds 		return check_condition_result;
40901da177e4SLinus Torvalds 	}
40918d039e22SDouglas Gilbert 
40928d039e22SDouglas Gilbert 	switch (select_report) {
40938d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4094773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
40958d039e22SDouglas Gilbert 		wlun_cnt = 0;
40968d039e22SDouglas Gilbert 		break;
40978d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4098c65b1445SDouglas Gilbert 		lun_cnt = 0;
40998d039e22SDouglas Gilbert 		wlun_cnt = 1;
41008d039e22SDouglas Gilbert 		break;
41018d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41028d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41038d039e22SDouglas Gilbert 		wlun_cnt = 1;
41048d039e22SDouglas Gilbert 		break;
41058d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41068d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41078d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41088d039e22SDouglas Gilbert 	default:
41098d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41108d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41118d039e22SDouglas Gilbert 		return check_condition_result;
41128d039e22SDouglas Gilbert 	}
41138d039e22SDouglas Gilbert 
41148d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4115c65b1445SDouglas Gilbert 		--lun_cnt;
41168d039e22SDouglas Gilbert 
41178d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4118fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4119fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41208d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41218d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41228d039e22SDouglas Gilbert 
4123fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41248d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4125fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4126fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4127fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4128fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4129fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4130fb0cc8d1SDouglas Gilbert 			++lun_p;
4131fb0cc8d1SDouglas Gilbert 			j = 1;
4132fb0cc8d1SDouglas Gilbert 		}
4133fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4134fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4135fb0cc8d1SDouglas Gilbert 				break;
4136fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4137fb0cc8d1SDouglas Gilbert 		}
4138fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4139fb0cc8d1SDouglas Gilbert 			break;
4140fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4141fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4142fb0cc8d1SDouglas Gilbert 		if (res)
4143fb0cc8d1SDouglas Gilbert 			return res;
4144fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4145fb0cc8d1SDouglas Gilbert 	}
4146fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4147fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4148fb0cc8d1SDouglas Gilbert 		++j;
4149fb0cc8d1SDouglas Gilbert 	}
4150fb0cc8d1SDouglas Gilbert 	if (j > 0)
4151fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
41528d039e22SDouglas Gilbert 	return res;
41531da177e4SLinus Torvalds }
41541da177e4SLinus Torvalds 
4155c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4156c3e2fe92SDouglas Gilbert {
4157c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4158c3e2fe92SDouglas Gilbert 	u8 bytchk;
4159c3e2fe92SDouglas Gilbert 	int ret, j;
4160c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4161c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4162c3e2fe92SDouglas Gilbert 	u64 lba;
4163c3e2fe92SDouglas Gilbert 	u8 *arr;
4164c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4165c3e2fe92SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4166c3e2fe92SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4167c3e2fe92SDouglas Gilbert 
4168c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4169c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4170c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4171c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4172c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4173c3e2fe92SDouglas Gilbert 		return check_condition_result;
4174c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4175c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4176c3e2fe92SDouglas Gilbert 	}
4177c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4178c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4179c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4180c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4181c3e2fe92SDouglas Gilbert 		break;
4182c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4183c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4184c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4185c3e2fe92SDouglas Gilbert 		break;
4186c3e2fe92SDouglas Gilbert 	default:
4187c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4188c3e2fe92SDouglas Gilbert 		return check_condition_result;
4189c3e2fe92SDouglas Gilbert 	}
4190c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4191c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4192c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4193c3e2fe92SDouglas Gilbert 	if (ret)
4194c3e2fe92SDouglas Gilbert 		return ret;
4195c3e2fe92SDouglas Gilbert 
4196c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4197c3e2fe92SDouglas Gilbert 	if (!arr) {
4198c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4199c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4200c3e2fe92SDouglas Gilbert 		return check_condition_result;
4201c3e2fe92SDouglas Gilbert 	}
4202c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
420367da413fSDouglas Gilbert 	read_lock(macc_lckp);
4204c3e2fe92SDouglas Gilbert 
4205c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4206c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4207c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4208c3e2fe92SDouglas Gilbert 		goto cleanup;
4209c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4210c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4211c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4212c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4213c3e2fe92SDouglas Gilbert 	}
4214c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4215c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4216c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4217c3e2fe92SDouglas Gilbert 	}
4218c3e2fe92SDouglas Gilbert 	ret = 0;
4219c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4220c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4221c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4222c3e2fe92SDouglas Gilbert 		goto cleanup;
4223c3e2fe92SDouglas Gilbert 	}
4224c3e2fe92SDouglas Gilbert cleanup:
422567da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4226c3e2fe92SDouglas Gilbert 	kfree(arr);
4227c3e2fe92SDouglas Gilbert 	return ret;
4228c3e2fe92SDouglas Gilbert }
4229c3e2fe92SDouglas Gilbert 
4230f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4231f0d1cf93SDouglas Gilbert 
4232f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4233f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4234f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4235f0d1cf93SDouglas Gilbert {
4236f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4237f0d1cf93SDouglas Gilbert 	int ret = 0;
4238f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4239f0d1cf93SDouglas Gilbert 	bool partial;
4240f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4241f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4242f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4243f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4244f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4245f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4246f0d1cf93SDouglas Gilbert 
4247f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4248f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4249f0d1cf93SDouglas Gilbert 		return check_condition_result;
4250f0d1cf93SDouglas Gilbert 	}
4251f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4252f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4253f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4254f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4255f0d1cf93SDouglas Gilbert 
4256f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4257f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4258f0d1cf93SDouglas Gilbert 		return check_condition_result;
4259f0d1cf93SDouglas Gilbert 	}
4260f0d1cf93SDouglas Gilbert 
4261f0d1cf93SDouglas Gilbert 	max_zones = devip->nr_zones - zs_lba / devip->zsize;
4262f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4263f0d1cf93SDouglas Gilbert 			    max_zones);
4264f0d1cf93SDouglas Gilbert 
4265f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4266f0d1cf93SDouglas Gilbert 	if (!arr) {
4267f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4268f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4269f0d1cf93SDouglas Gilbert 		return check_condition_result;
4270f0d1cf93SDouglas Gilbert 	}
4271f0d1cf93SDouglas Gilbert 
4272f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4273f0d1cf93SDouglas Gilbert 
4274f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4275f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4276f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4277f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4278f0d1cf93SDouglas Gilbert 			break;
4279f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4280f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4281f0d1cf93SDouglas Gilbert 		case 0x00:
4282f0d1cf93SDouglas Gilbert 			/* All zones */
4283f0d1cf93SDouglas Gilbert 			break;
4284f0d1cf93SDouglas Gilbert 		case 0x01:
4285f0d1cf93SDouglas Gilbert 			/* Empty zones */
4286f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4287f0d1cf93SDouglas Gilbert 				continue;
4288f0d1cf93SDouglas Gilbert 			break;
4289f0d1cf93SDouglas Gilbert 		case 0x02:
4290f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4291f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4292f0d1cf93SDouglas Gilbert 				continue;
4293f0d1cf93SDouglas Gilbert 			break;
4294f0d1cf93SDouglas Gilbert 		case 0x03:
4295f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4296f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4297f0d1cf93SDouglas Gilbert 				continue;
4298f0d1cf93SDouglas Gilbert 			break;
4299f0d1cf93SDouglas Gilbert 		case 0x04:
4300f0d1cf93SDouglas Gilbert 			/* Closed zones */
4301f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4302f0d1cf93SDouglas Gilbert 				continue;
4303f0d1cf93SDouglas Gilbert 			break;
4304f0d1cf93SDouglas Gilbert 		case 0x05:
4305f0d1cf93SDouglas Gilbert 			/* Full zones */
4306f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4307f0d1cf93SDouglas Gilbert 				continue;
4308f0d1cf93SDouglas Gilbert 			break;
4309f0d1cf93SDouglas Gilbert 		case 0x06:
4310f0d1cf93SDouglas Gilbert 		case 0x07:
4311f0d1cf93SDouglas Gilbert 		case 0x10:
4312f0d1cf93SDouglas Gilbert 		case 0x11:
4313f0d1cf93SDouglas Gilbert 			/*
4314f0d1cf93SDouglas Gilbert 			 * Read-only, offline, reset WP recommended and
4315f0d1cf93SDouglas Gilbert 			 * non-seq-resource-used are not emulated: no zones
4316f0d1cf93SDouglas Gilbert 			 * to report;
4317f0d1cf93SDouglas Gilbert 			 */
4318f0d1cf93SDouglas Gilbert 			continue;
4319f0d1cf93SDouglas Gilbert 		case 0x3f:
4320f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4321f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4322f0d1cf93SDouglas Gilbert 				continue;
4323f0d1cf93SDouglas Gilbert 			break;
4324f0d1cf93SDouglas Gilbert 		default:
4325f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4326f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4327f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4328f0d1cf93SDouglas Gilbert 			goto fini;
4329f0d1cf93SDouglas Gilbert 		}
4330f0d1cf93SDouglas Gilbert 
4331f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4332f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
4333f0d1cf93SDouglas Gilbert 			if (zbc_zone_is_conv(zsp))
4334f0d1cf93SDouglas Gilbert 				desc[0] = 0x1;
4335f0d1cf93SDouglas Gilbert 			else
4336f0d1cf93SDouglas Gilbert 				desc[0] = 0x2;
4337f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
4338f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4339f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4340f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4341f0d1cf93SDouglas Gilbert 			desc += 64;
4342f0d1cf93SDouglas Gilbert 		}
4343f0d1cf93SDouglas Gilbert 
4344f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4345f0d1cf93SDouglas Gilbert 			break;
4346f0d1cf93SDouglas Gilbert 
4347f0d1cf93SDouglas Gilbert 		nrz++;
4348f0d1cf93SDouglas Gilbert 	}
4349f0d1cf93SDouglas Gilbert 
4350f0d1cf93SDouglas Gilbert 	/* Report header */
4351f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4352f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4353f0d1cf93SDouglas Gilbert 
4354f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4355f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4356f0d1cf93SDouglas Gilbert 
4357f0d1cf93SDouglas Gilbert fini:
4358f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4359f0d1cf93SDouglas Gilbert 	kfree(arr);
4360f0d1cf93SDouglas Gilbert 	return ret;
4361f0d1cf93SDouglas Gilbert }
4362f0d1cf93SDouglas Gilbert 
4363f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4364f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4365f0d1cf93SDouglas Gilbert {
4366f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4367f0d1cf93SDouglas Gilbert 	unsigned int i;
4368f0d1cf93SDouglas Gilbert 
4369f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4370f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4371f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4372f0d1cf93SDouglas Gilbert 	}
4373f0d1cf93SDouglas Gilbert }
4374f0d1cf93SDouglas Gilbert 
4375f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4376f0d1cf93SDouglas Gilbert {
4377f0d1cf93SDouglas Gilbert 	int res = 0;
4378f0d1cf93SDouglas Gilbert 	u64 z_id;
4379f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4380f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4381f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4382f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4383f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4384f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4385f0d1cf93SDouglas Gilbert 
4386f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4387f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4388f0d1cf93SDouglas Gilbert 		return check_condition_result;
4389f0d1cf93SDouglas Gilbert 	}
4390f0d1cf93SDouglas Gilbert 
4391f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4392f0d1cf93SDouglas Gilbert 
4393f0d1cf93SDouglas Gilbert 	if (all) {
4394f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4395f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4396f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4397f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4398f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4399f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4400f0d1cf93SDouglas Gilbert 			goto fini;
4401f0d1cf93SDouglas Gilbert 		}
4402f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4403f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4404f0d1cf93SDouglas Gilbert 		goto fini;
4405f0d1cf93SDouglas Gilbert 	}
4406f0d1cf93SDouglas Gilbert 
4407f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4408f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4409f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4410f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4411f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4412f0d1cf93SDouglas Gilbert 		goto fini;
4413f0d1cf93SDouglas Gilbert 	}
4414f0d1cf93SDouglas Gilbert 
4415f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4416f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4417f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4418f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4419f0d1cf93SDouglas Gilbert 		goto fini;
4420f0d1cf93SDouglas Gilbert 	}
4421f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4422f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4423f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4424f0d1cf93SDouglas Gilbert 		goto fini;
4425f0d1cf93SDouglas Gilbert 	}
4426f0d1cf93SDouglas Gilbert 
4427f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4428f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4429f0d1cf93SDouglas Gilbert 		goto fini;
4430f0d1cf93SDouglas Gilbert 
4431f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4432f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4433f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4434f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4435f0d1cf93SDouglas Gilbert 		goto fini;
4436f0d1cf93SDouglas Gilbert 	}
4437f0d1cf93SDouglas Gilbert 
4438f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
4439f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4440f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4441f0d1cf93SDouglas Gilbert fini:
4442f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4443f0d1cf93SDouglas Gilbert 	return res;
4444f0d1cf93SDouglas Gilbert }
4445f0d1cf93SDouglas Gilbert 
4446f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4447f0d1cf93SDouglas Gilbert {
4448f0d1cf93SDouglas Gilbert 	unsigned int i;
4449f0d1cf93SDouglas Gilbert 
4450f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4451f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4452f0d1cf93SDouglas Gilbert }
4453f0d1cf93SDouglas Gilbert 
4454f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4455f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4456f0d1cf93SDouglas Gilbert {
4457f0d1cf93SDouglas Gilbert 	int res = 0;
4458f0d1cf93SDouglas Gilbert 	u64 z_id;
4459f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4460f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4461f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4462f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4463f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4464f0d1cf93SDouglas Gilbert 
4465f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4466f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4467f0d1cf93SDouglas Gilbert 		return check_condition_result;
4468f0d1cf93SDouglas Gilbert 	}
4469f0d1cf93SDouglas Gilbert 
4470f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4471f0d1cf93SDouglas Gilbert 
4472f0d1cf93SDouglas Gilbert 	if (all) {
4473f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4474f0d1cf93SDouglas Gilbert 		goto fini;
4475f0d1cf93SDouglas Gilbert 	}
4476f0d1cf93SDouglas Gilbert 
4477f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4478f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4479f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4480f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4481f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4482f0d1cf93SDouglas Gilbert 		goto fini;
4483f0d1cf93SDouglas Gilbert 	}
4484f0d1cf93SDouglas Gilbert 
4485f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4486f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4487f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4488f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4489f0d1cf93SDouglas Gilbert 		goto fini;
4490f0d1cf93SDouglas Gilbert 	}
4491f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4492f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4493f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4494f0d1cf93SDouglas Gilbert 		goto fini;
4495f0d1cf93SDouglas Gilbert 	}
4496f0d1cf93SDouglas Gilbert 
4497f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4498f0d1cf93SDouglas Gilbert fini:
4499f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4500f0d1cf93SDouglas Gilbert 	return res;
4501f0d1cf93SDouglas Gilbert }
4502f0d1cf93SDouglas Gilbert 
4503f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4504f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4505f0d1cf93SDouglas Gilbert {
4506f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4507f0d1cf93SDouglas Gilbert 
4508f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4509f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4510f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4511f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4512f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4513f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4514f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4515f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4516f0d1cf93SDouglas Gilbert 	}
4517f0d1cf93SDouglas Gilbert }
4518f0d1cf93SDouglas Gilbert 
4519f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4520f0d1cf93SDouglas Gilbert {
4521f0d1cf93SDouglas Gilbert 	unsigned int i;
4522f0d1cf93SDouglas Gilbert 
4523f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4524f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4525f0d1cf93SDouglas Gilbert }
4526f0d1cf93SDouglas Gilbert 
4527f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4528f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4529f0d1cf93SDouglas Gilbert {
4530f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4531f0d1cf93SDouglas Gilbert 	int res = 0;
4532f0d1cf93SDouglas Gilbert 	u64 z_id;
4533f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4534f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4535f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4536f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4537f0d1cf93SDouglas Gilbert 
4538f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4539f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4540f0d1cf93SDouglas Gilbert 		return check_condition_result;
4541f0d1cf93SDouglas Gilbert 	}
4542f0d1cf93SDouglas Gilbert 
4543f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4544f0d1cf93SDouglas Gilbert 
4545f0d1cf93SDouglas Gilbert 	if (all) {
4546f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4547f0d1cf93SDouglas Gilbert 		goto fini;
4548f0d1cf93SDouglas Gilbert 	}
4549f0d1cf93SDouglas Gilbert 
4550f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4551f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4552f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4553f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4554f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4555f0d1cf93SDouglas Gilbert 		goto fini;
4556f0d1cf93SDouglas Gilbert 	}
4557f0d1cf93SDouglas Gilbert 
4558f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4559f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4560f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4561f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4562f0d1cf93SDouglas Gilbert 		goto fini;
4563f0d1cf93SDouglas Gilbert 	}
4564f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4565f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4566f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4567f0d1cf93SDouglas Gilbert 		goto fini;
4568f0d1cf93SDouglas Gilbert 	}
4569f0d1cf93SDouglas Gilbert 
4570f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4571f0d1cf93SDouglas Gilbert fini:
4572f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4573f0d1cf93SDouglas Gilbert 	return res;
4574f0d1cf93SDouglas Gilbert }
4575f0d1cf93SDouglas Gilbert 
4576f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4577f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4578f0d1cf93SDouglas Gilbert {
4579f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4580f0d1cf93SDouglas Gilbert 
4581f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4582f0d1cf93SDouglas Gilbert 		return;
4583f0d1cf93SDouglas Gilbert 
4584f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4585f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4586f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4587f0d1cf93SDouglas Gilbert 
4588f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4589f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4590f0d1cf93SDouglas Gilbert 
4591f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4592f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4593f0d1cf93SDouglas Gilbert }
4594f0d1cf93SDouglas Gilbert 
4595f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4596f0d1cf93SDouglas Gilbert {
4597f0d1cf93SDouglas Gilbert 	unsigned int i;
4598f0d1cf93SDouglas Gilbert 
4599f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4600f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4601f0d1cf93SDouglas Gilbert }
4602f0d1cf93SDouglas Gilbert 
4603f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4604f0d1cf93SDouglas Gilbert {
4605f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4606f0d1cf93SDouglas Gilbert 	int res = 0;
4607f0d1cf93SDouglas Gilbert 	u64 z_id;
4608f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4609f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4610f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4611f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4612f0d1cf93SDouglas Gilbert 
4613f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4614f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4615f0d1cf93SDouglas Gilbert 		return check_condition_result;
4616f0d1cf93SDouglas Gilbert 	}
4617f0d1cf93SDouglas Gilbert 
4618f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4619f0d1cf93SDouglas Gilbert 
4620f0d1cf93SDouglas Gilbert 	if (all) {
4621f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4622f0d1cf93SDouglas Gilbert 		goto fini;
4623f0d1cf93SDouglas Gilbert 	}
4624f0d1cf93SDouglas Gilbert 
4625f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4626f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4627f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4628f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4629f0d1cf93SDouglas Gilbert 		goto fini;
4630f0d1cf93SDouglas Gilbert 	}
4631f0d1cf93SDouglas Gilbert 
4632f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4633f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4634f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4635f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4636f0d1cf93SDouglas Gilbert 		goto fini;
4637f0d1cf93SDouglas Gilbert 	}
4638f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4639f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4640f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4641f0d1cf93SDouglas Gilbert 		goto fini;
4642f0d1cf93SDouglas Gilbert 	}
4643f0d1cf93SDouglas Gilbert 
4644f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4645f0d1cf93SDouglas Gilbert fini:
4646f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4647f0d1cf93SDouglas Gilbert 	return res;
4648f0d1cf93SDouglas Gilbert }
4649f0d1cf93SDouglas Gilbert 
4650c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4651c4837394SDouglas Gilbert {
4652c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
4653c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
4654c4837394SDouglas Gilbert 
4655458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4656458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4657458df78bSBart Van Assche 		hwq = 0;
4658458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4659c4837394SDouglas Gilbert }
4660c4837394SDouglas Gilbert 
4661c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4662fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
46631da177e4SLinus Torvalds {
46647382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4665c4837394SDouglas Gilbert 	int qc_idx;
4666cbf67842SDouglas Gilbert 	int retiring = 0;
46671da177e4SLinus Torvalds 	unsigned long iflags;
4668c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4669cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4670cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4671cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
46721da177e4SLinus Torvalds 
467310bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
46747382f9d8SDouglas Gilbert 	if (unlikely(aborted))
46757382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4676c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4677c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4678c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4679cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4680c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4681c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4682c4837394SDouglas Gilbert 	}
4683c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4684c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
46851da177e4SLinus Torvalds 		return;
46861da177e4SLinus Torvalds 	}
4687c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4688c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4689cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4690b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4691c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4692c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
4693c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
46941da177e4SLinus Torvalds 		return;
46951da177e4SLinus Torvalds 	}
4696cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4697f46eb0e9SDouglas Gilbert 	if (likely(devip))
4698cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4699cbf67842SDouglas Gilbert 	else
4700c1287970STomas Winkler 		pr_err("devip=NULL\n");
4701f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4702cbf67842SDouglas Gilbert 		retiring = 1;
4703cbf67842SDouglas Gilbert 
4704cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4705c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4706c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4707c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4708cbf67842SDouglas Gilbert 		return;
47091da177e4SLinus Torvalds 	}
47101da177e4SLinus Torvalds 
4711cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4712cbf67842SDouglas Gilbert 		int k, retval;
4713cbf67842SDouglas Gilbert 
4714cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4715c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4716c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4717c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4718cbf67842SDouglas Gilbert 			return;
4719cbf67842SDouglas Gilbert 		}
4720c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4721773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4722cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4723cbf67842SDouglas Gilbert 		else
4724cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4725cbf67842SDouglas Gilbert 	}
4726c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47277382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
47287382f9d8SDouglas Gilbert 		if (sdebug_verbose)
47297382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
47307382f9d8SDouglas Gilbert 		return;
47317382f9d8SDouglas Gilbert 	}
4732cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4733cbf67842SDouglas Gilbert }
4734cbf67842SDouglas Gilbert 
4735cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4736fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4737cbf67842SDouglas Gilbert {
4738a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4739a10bc12aSDouglas Gilbert 						  hrt);
4740a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4741cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4742cbf67842SDouglas Gilbert }
47431da177e4SLinus Torvalds 
4744a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4745fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4746a10bc12aSDouglas Gilbert {
4747a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4748a10bc12aSDouglas Gilbert 						  ew.work);
4749a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4750a10bc12aSDouglas Gilbert }
4751a10bc12aSDouglas Gilbert 
475209ba24c1SDouglas Gilbert static bool got_shared_uuid;
4753bf476433SChristoph Hellwig static uuid_t shared_uuid;
475409ba24c1SDouglas Gilbert 
4755f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4756f0d1cf93SDouglas Gilbert {
4757f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4758f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4759f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4760f0d1cf93SDouglas Gilbert 	unsigned int i;
4761f0d1cf93SDouglas Gilbert 
4762f0d1cf93SDouglas Gilbert 	/*
4763f0d1cf93SDouglas Gilbert 	 * Set the zone size: if zbc_zone_size_mb is not set, figure out a
4764f0d1cf93SDouglas Gilbert 	 * zone size allowing for at least 4 zones on the device. Otherwise,
4765f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4766f0d1cf93SDouglas Gilbert 	 * created for the device.
4767f0d1cf93SDouglas Gilbert 	 */
4768f0d1cf93SDouglas Gilbert 	if (!zbc_zone_size_mb) {
4769f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4770f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4771f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4772f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4773f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4774f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4775f0d1cf93SDouglas Gilbert 			return -EINVAL;
4776f0d1cf93SDouglas Gilbert 		}
4777f0d1cf93SDouglas Gilbert 	} else {
4778f0d1cf93SDouglas Gilbert 		devip->zsize = (zbc_zone_size_mb * SZ_1M)
4779f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4780f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4781f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4782f0d1cf93SDouglas Gilbert 			return -EINVAL;
4783f0d1cf93SDouglas Gilbert 		}
4784f0d1cf93SDouglas Gilbert 	}
4785f0d1cf93SDouglas Gilbert 
4786f0d1cf93SDouglas Gilbert 	if (is_power_of_2(devip->zsize))
4787f0d1cf93SDouglas Gilbert 		devip->zsize_shift = ilog2(devip->zsize);
4788f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4789f0d1cf93SDouglas Gilbert 
4790f0d1cf93SDouglas Gilbert 	/* zbc_max_open_zones can be 0, meaning "not reported" (no limit) */
4791f0d1cf93SDouglas Gilbert 	if (zbc_max_open_zones >= devip->nr_zones - 1)
4792f0d1cf93SDouglas Gilbert 		devip->max_open = (devip->nr_zones - 1) / 2;
4793f0d1cf93SDouglas Gilbert 	else
4794f0d1cf93SDouglas Gilbert 		devip->max_open = zbc_max_open_zones;
4795f0d1cf93SDouglas Gilbert 
4796f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4797f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4798f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4799f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4800f0d1cf93SDouglas Gilbert 
4801f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4802f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4803f0d1cf93SDouglas Gilbert 
4804f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4805f0d1cf93SDouglas Gilbert 
4806f0d1cf93SDouglas Gilbert 		if (i == 0) {
4807f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4808f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4809f0d1cf93SDouglas Gilbert 		} else {
4810f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4811f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4812f0d1cf93SDouglas Gilbert 		}
4813f0d1cf93SDouglas Gilbert 
4814f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4815f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4816f0d1cf93SDouglas Gilbert 		else
4817f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4818f0d1cf93SDouglas Gilbert 
4819f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4820f0d1cf93SDouglas Gilbert 	}
4821f0d1cf93SDouglas Gilbert 
4822f0d1cf93SDouglas Gilbert 	return 0;
4823f0d1cf93SDouglas Gilbert }
4824f0d1cf93SDouglas Gilbert 
4825fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4826fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
48275cb2fc06SFUJITA Tomonori {
48285cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
48295cb2fc06SFUJITA Tomonori 
48305cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
48315cb2fc06SFUJITA Tomonori 	if (devip) {
483209ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4833bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
483409ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
483509ba24c1SDouglas Gilbert 			if (got_shared_uuid)
483609ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
483709ba24c1SDouglas Gilbert 			else {
4838bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
483909ba24c1SDouglas Gilbert 				got_shared_uuid = true;
484009ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
484109ba24c1SDouglas Gilbert 			}
484209ba24c1SDouglas Gilbert 		}
48435cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4844f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
4845f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4846f0d1cf93SDouglas Gilbert 				kfree(devip);
4847f0d1cf93SDouglas Gilbert 				return NULL;
4848f0d1cf93SDouglas Gilbert 			}
4849f0d1cf93SDouglas Gilbert 		}
4850f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
48515cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
48525cb2fc06SFUJITA Tomonori 	}
48535cb2fc06SFUJITA Tomonori 	return devip;
48545cb2fc06SFUJITA Tomonori }
48555cb2fc06SFUJITA Tomonori 
4856f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
48571da177e4SLinus Torvalds {
48581da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
48591da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4860f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
48611da177e4SLinus Torvalds 
4862d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
48631da177e4SLinus Torvalds 	if (!sdbg_host) {
4864c1287970STomas Winkler 		pr_err("Host info NULL\n");
48651da177e4SLinus Torvalds 		return NULL;
48661da177e4SLinus Torvalds 	}
48671da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
48681da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
48691da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
48701da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
48711da177e4SLinus Torvalds 			return devip;
48721da177e4SLinus Torvalds 		else {
48731da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
48741da177e4SLinus Torvalds 				open_devip = devip;
48751da177e4SLinus Torvalds 		}
48761da177e4SLinus Torvalds 	}
48775cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
48785cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
48795cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4880c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
48811da177e4SLinus Torvalds 			return NULL;
48821da177e4SLinus Torvalds 		}
48831da177e4SLinus Torvalds 	}
4884a75869d1SFUJITA Tomonori 
48851da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
48861da177e4SLinus Torvalds 	open_devip->target = sdev->id;
48871da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
48881da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4889cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4890cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4891c2248fc9SDouglas Gilbert 	open_devip->used = true;
48921da177e4SLinus Torvalds 	return open_devip;
48931da177e4SLinus Torvalds }
48941da177e4SLinus Torvalds 
48958dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
48961da177e4SLinus Torvalds {
4897773642d9SDouglas Gilbert 	if (sdebug_verbose)
4898c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
48998dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49008dea0d02SFUJITA Tomonori 	return 0;
49018dea0d02SFUJITA Tomonori }
49021da177e4SLinus Torvalds 
49038dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
49048dea0d02SFUJITA Tomonori {
4905f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4906f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4907a34c4e98SFUJITA Tomonori 
4908773642d9SDouglas Gilbert 	if (sdebug_verbose)
4909c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
49108dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4911b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4912b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4913b01f6f83SDouglas Gilbert 	if (devip == NULL) {
4914f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
4915b01f6f83SDouglas Gilbert 		if (devip == NULL)
49168dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
4917f46eb0e9SDouglas Gilbert 	}
4918c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
4919773642d9SDouglas Gilbert 	if (sdebug_no_uld)
492078d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
49219b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
49228dea0d02SFUJITA Tomonori 	return 0;
49238dea0d02SFUJITA Tomonori }
49248dea0d02SFUJITA Tomonori 
49258dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
49268dea0d02SFUJITA Tomonori {
49278dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
49288dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
49298dea0d02SFUJITA Tomonori 
4930773642d9SDouglas Gilbert 	if (sdebug_verbose)
4931c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
49328dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49338dea0d02SFUJITA Tomonori 	if (devip) {
493425985edcSLucas De Marchi 		/* make this slot available for re-use */
4935c2248fc9SDouglas Gilbert 		devip->used = false;
49368dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
49378dea0d02SFUJITA Tomonori 	}
49388dea0d02SFUJITA Tomonori }
49398dea0d02SFUJITA Tomonori 
494010bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
494110bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
4942c4837394SDouglas Gilbert {
4943c4837394SDouglas Gilbert 	if (!sd_dp)
4944c4837394SDouglas Gilbert 		return;
494510bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
4946c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
494710bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
4948c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
4949c4837394SDouglas Gilbert }
4950c4837394SDouglas Gilbert 
4951a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
4952a10bc12aSDouglas Gilbert    returns false */
4953a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
49548dea0d02SFUJITA Tomonori {
49558dea0d02SFUJITA Tomonori 	unsigned long iflags;
4956c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
495710bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4958c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
49598dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4960cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4961a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
49628dea0d02SFUJITA Tomonori 
4963c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4964c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4965773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
4966cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
4967cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
4968cbf67842SDouglas Gilbert 			qmax = r_qmax;
4969cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
4970c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4971c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4972a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
4973a10bc12aSDouglas Gilbert 					continue;
4974c4837394SDouglas Gilbert 				/* found */
4975db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4976db525fceSDouglas Gilbert 						cmnd->device->hostdata;
4977db525fceSDouglas Gilbert 				if (devip)
4978db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4979db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4980a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
498110bde980SDouglas Gilbert 				if (sd_dp) {
498210bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
498310bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
498410bde980SDouglas Gilbert 				} else
498510bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4986c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
498710bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4988c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4989a10bc12aSDouglas Gilbert 				return true;
49908dea0d02SFUJITA Tomonori 			}
4991cbf67842SDouglas Gilbert 		}
4992c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4993c4837394SDouglas Gilbert 	}
4994a10bc12aSDouglas Gilbert 	return false;
49958dea0d02SFUJITA Tomonori }
49968dea0d02SFUJITA Tomonori 
4997a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
49988dea0d02SFUJITA Tomonori static void stop_all_queued(void)
49998dea0d02SFUJITA Tomonori {
50008dea0d02SFUJITA Tomonori 	unsigned long iflags;
5001c4837394SDouglas Gilbert 	int j, k;
500210bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5003c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50048dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5005cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5006a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50078dea0d02SFUJITA Tomonori 
5008c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5009c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5010c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5011c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5012c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5013c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5014a10bc12aSDouglas Gilbert 					continue;
5015db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5016db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5017db525fceSDouglas Gilbert 				if (devip)
5018db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5019db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5020a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
502110bde980SDouglas Gilbert 				if (sd_dp) {
502210bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
502310bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
502410bde980SDouglas Gilbert 				} else
502510bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5026c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
502710bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5028c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5029c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
50308dea0d02SFUJITA Tomonori 			}
50318dea0d02SFUJITA Tomonori 		}
5032c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5033c4837394SDouglas Gilbert 	}
5034cbf67842SDouglas Gilbert }
5035cbf67842SDouglas Gilbert 
5036cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5037cbf67842SDouglas Gilbert static void free_all_queued(void)
5038cbf67842SDouglas Gilbert {
5039c4837394SDouglas Gilbert 	int j, k;
5040c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5041cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5042cbf67842SDouglas Gilbert 
5043c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5044c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5045c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5046a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5047a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5048cbf67842SDouglas Gilbert 		}
50491da177e4SLinus Torvalds 	}
5050c4837394SDouglas Gilbert }
50511da177e4SLinus Torvalds 
50521da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
50531da177e4SLinus Torvalds {
5054a10bc12aSDouglas Gilbert 	bool ok;
5055a10bc12aSDouglas Gilbert 
50561da177e4SLinus Torvalds 	++num_aborts;
5057cbf67842SDouglas Gilbert 	if (SCpnt) {
5058a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5059a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5060a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5061a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5062a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5063cbf67842SDouglas Gilbert 	}
50641da177e4SLinus Torvalds 	return SUCCESS;
50651da177e4SLinus Torvalds }
50661da177e4SLinus Torvalds 
50671da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
50681da177e4SLinus Torvalds {
50691da177e4SLinus Torvalds 	++num_dev_resets;
5070cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5071cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5072f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5073f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5074cbf67842SDouglas Gilbert 
5075773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5076cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
50771da177e4SLinus Torvalds 		if (devip)
5078cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
50791da177e4SLinus Torvalds 	}
50801da177e4SLinus Torvalds 	return SUCCESS;
50811da177e4SLinus Torvalds }
50821da177e4SLinus Torvalds 
5083cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5084cbf67842SDouglas Gilbert {
5085cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5086cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5087cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5088cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5089cbf67842SDouglas Gilbert 	int k = 0;
5090cbf67842SDouglas Gilbert 
5091cbf67842SDouglas Gilbert 	++num_target_resets;
5092cbf67842SDouglas Gilbert 	if (!SCpnt)
5093cbf67842SDouglas Gilbert 		goto lie;
5094cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5095cbf67842SDouglas Gilbert 	if (!sdp)
5096cbf67842SDouglas Gilbert 		goto lie;
5097773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5098cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5099cbf67842SDouglas Gilbert 	hp = sdp->host;
5100cbf67842SDouglas Gilbert 	if (!hp)
5101cbf67842SDouglas Gilbert 		goto lie;
5102cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5103cbf67842SDouglas Gilbert 	if (sdbg_host) {
5104cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5105cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5106cbf67842SDouglas Gilbert 				    dev_list)
5107cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5108cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5109cbf67842SDouglas Gilbert 				++k;
5110cbf67842SDouglas Gilbert 			}
5111cbf67842SDouglas Gilbert 	}
5112773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5113cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5114cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5115cbf67842SDouglas Gilbert lie:
5116cbf67842SDouglas Gilbert 	return SUCCESS;
5117cbf67842SDouglas Gilbert }
5118cbf67842SDouglas Gilbert 
51191da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
51201da177e4SLinus Torvalds {
51211da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5122cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
51231da177e4SLinus Torvalds 	struct scsi_device *sdp;
51241da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5125cbf67842SDouglas Gilbert 	int k = 0;
51261da177e4SLinus Torvalds 
51271da177e4SLinus Torvalds 	++num_bus_resets;
5128cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5129cbf67842SDouglas Gilbert 		goto lie;
5130cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5131773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5132cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5133cbf67842SDouglas Gilbert 	hp = sdp->host;
5134cbf67842SDouglas Gilbert 	if (hp) {
5135d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
51361da177e4SLinus Torvalds 		if (sdbg_host) {
5137cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
51381da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5139cbf67842SDouglas Gilbert 					    dev_list) {
5140cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5141cbf67842SDouglas Gilbert 				++k;
51421da177e4SLinus Torvalds 			}
51431da177e4SLinus Torvalds 		}
5144cbf67842SDouglas Gilbert 	}
5145773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5146cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5147cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5148cbf67842SDouglas Gilbert lie:
51491da177e4SLinus Torvalds 	return SUCCESS;
51501da177e4SLinus Torvalds }
51511da177e4SLinus Torvalds 
51521da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
51531da177e4SLinus Torvalds {
51541da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5155cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5156cbf67842SDouglas Gilbert 	int k = 0;
51571da177e4SLinus Torvalds 
51581da177e4SLinus Torvalds 	++num_host_resets;
5159773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5160cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
51611da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
51621da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5163cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5164cbf67842SDouglas Gilbert 				    dev_list) {
5165cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5166cbf67842SDouglas Gilbert 			++k;
5167cbf67842SDouglas Gilbert 		}
51681da177e4SLinus Torvalds 	}
51691da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
51701da177e4SLinus Torvalds 	stop_all_queued();
5171773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5172cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5173cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
51741da177e4SLinus Torvalds 	return SUCCESS;
51751da177e4SLinus Torvalds }
51761da177e4SLinus Torvalds 
517787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
51781da177e4SLinus Torvalds {
51791442f76dSChristoph Hellwig 	struct msdos_partition *pp;
51801da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
51811da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
51821da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
51831da177e4SLinus Torvalds 
51841da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5185773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
51861da177e4SLinus Torvalds 		return;
5187773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5188773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5189c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
51901da177e4SLinus Torvalds 	}
5191c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
51921da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5193773642d9SDouglas Gilbert 			   / sdebug_num_parts;
51941da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
51951da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5196773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
51971da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
51981da177e4SLinus Torvalds 			    * heads_by_sects;
5199773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5200773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
52011da177e4SLinus Torvalds 
52021da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
52031da177e4SLinus Torvalds 	ramp[511] = 0xAA;
52041442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
52051da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
52061da177e4SLinus Torvalds 		start_sec = starts[k];
52071da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
52081da177e4SLinus Torvalds 		pp->boot_ind = 0;
52091da177e4SLinus Torvalds 
52101da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
52111da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
52121da177e4SLinus Torvalds 			   / sdebug_sectors_per;
52131da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
52141da177e4SLinus Torvalds 
52151da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
52161da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
52171da177e4SLinus Torvalds 			       / sdebug_sectors_per;
52181da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
52191da177e4SLinus Torvalds 
5220150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5221150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
52221da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
52231da177e4SLinus Torvalds 	}
52241da177e4SLinus Torvalds }
52251da177e4SLinus Torvalds 
5226c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5227c4837394SDouglas Gilbert {
5228c4837394SDouglas Gilbert 	int j;
5229c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5230c4837394SDouglas Gilbert 
5231c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5232c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5233c4837394SDouglas Gilbert }
5234c4837394SDouglas Gilbert 
5235c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5236c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5237c4837394SDouglas Gilbert  */
5238c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5239c4837394SDouglas Gilbert {
5240c4837394SDouglas Gilbert 	int count, modulo;
5241c4837394SDouglas Gilbert 
5242c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5243c4837394SDouglas Gilbert 	if (modulo < 2)
5244c4837394SDouglas Gilbert 		return;
5245c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5246c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5247c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5248c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5249c4837394SDouglas Gilbert }
5250c4837394SDouglas Gilbert 
5251c4837394SDouglas Gilbert static void clear_queue_stats(void)
5252c4837394SDouglas Gilbert {
5253c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5254c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5255c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5256c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5257c4837394SDouglas Gilbert }
5258c4837394SDouglas Gilbert 
5259c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
5260c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
5261c4837394SDouglas Gilbert {
5262f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
5263f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
5264f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
5265f9ba7af8SMartin Wilck 				= sqcp->inj_dif
52667382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
52677382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
5268c4837394SDouglas Gilbert 		return;
5269f9ba7af8SMartin Wilck 	}
5270c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
5271c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
5272c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
5273c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
5274c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
52757ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
52767382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
5277c4837394SDouglas Gilbert }
5278c4837394SDouglas Gilbert 
5279a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5280a2aede97SDouglas Gilbert 
5281c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5282c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5283c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5284c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5285c4837394SDouglas Gilbert  */
5286fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5287f66b8517SMartin Wilck 			 int scsi_result,
5288f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5289f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5290f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
52911da177e4SLinus Torvalds {
5292a2aede97SDouglas Gilbert 	bool new_sd_dp;
5293cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
5294a2aede97SDouglas Gilbert 	unsigned long iflags;
5295a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5296c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5297c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5298299b6c07STomas Winkler 	struct scsi_device *sdp;
5299a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53001da177e4SLinus Torvalds 
5301b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5302b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5303f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5304f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
53051da177e4SLinus Torvalds 	}
5306299b6c07STomas Winkler 	sdp = cmnd->device;
5307299b6c07STomas Winkler 
5308cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5309cd62b7daSDouglas Gilbert 		goto respond_in_thread;
53101da177e4SLinus Torvalds 
5311c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5312c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5313c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5314c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5315c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5316c4837394SDouglas Gilbert 	}
5317cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5318cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5319cbf67842SDouglas Gilbert 	inject = 0;
5320f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5321cd62b7daSDouglas Gilbert 		if (scsi_result) {
5322c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5323cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5324cd62b7daSDouglas Gilbert 		} else
5325cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5326c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5327773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5328f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5329cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5330cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5331773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5332cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
5333cbf67842SDouglas Gilbert 			inject = 1;
5334cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
53351da177e4SLinus Torvalds 		}
5336cbf67842SDouglas Gilbert 	}
5337cbf67842SDouglas Gilbert 
5338c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5339f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5340c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5341cd62b7daSDouglas Gilbert 		if (scsi_result)
5342cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5343773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5344cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5345773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5346cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5347cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5348773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5349cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5350cbf67842SDouglas Gilbert 						    "report: host busy"));
5351cd62b7daSDouglas Gilbert 		if (scsi_result)
5352cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5353cd62b7daSDouglas Gilbert 		else
5354cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
53551da177e4SLinus Torvalds 	}
5356c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
5357cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5358c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
53591da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5360c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5361a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5362c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5363c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
5364c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
536510bde980SDouglas Gilbert 	if (sd_dp == NULL) {
536610bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
536710bde980SDouglas Gilbert 		if (sd_dp == NULL)
536810bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
5369a2aede97SDouglas Gilbert 		new_sd_dp = true;
5370a2aede97SDouglas Gilbert 	} else {
5371a2aede97SDouglas Gilbert 		new_sd_dp = false;
537210bde980SDouglas Gilbert 	}
5373f66b8517SMartin Wilck 
5374a2aede97SDouglas Gilbert 	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
5375a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5376a2aede97SDouglas Gilbert 
5377a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
5378f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5379f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5380f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5381f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5382f66b8517SMartin Wilck 	}
5383f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5384f66b8517SMartin Wilck 		cmnd->result = scsi_result;
5385f66b8517SMartin Wilck 
5386f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5387f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5388f66b8517SMartin Wilck 			    __func__, cmnd->result);
5389f66b8517SMartin Wilck 
539010bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5391b333a819SDouglas Gilbert 		ktime_t kt;
5392cbf67842SDouglas Gilbert 
5393b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
53940c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
53950c4bc91dSDouglas Gilbert 
53960c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
53970c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
53980c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
53990c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
54000c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
54010c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
54020c4bc91dSDouglas Gilbert 				ns <<= 12;
54030c4bc91dSDouglas Gilbert 			}
54040c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
54050c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
54060c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
54070c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5408a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5409a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5410a2aede97SDouglas Gilbert 
5411a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5412a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5413a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5414a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5415a2aede97SDouglas Gilbert 					if (new_sd_dp)
5416a2aede97SDouglas Gilbert 						kfree(sd_dp);
5417a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
5418a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
5419a2aede97SDouglas Gilbert 					return 0;
5420a2aede97SDouglas Gilbert 				}
5421a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5422a2aede97SDouglas Gilbert 				kt -= d;
5423a2aede97SDouglas Gilbert 			}
54240c4bc91dSDouglas Gilbert 		}
542510bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
542610bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
5427a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5428a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5429c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
5430a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5431c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5432c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5433cbf67842SDouglas Gilbert 		}
5434c4837394SDouglas Gilbert 		if (sdebug_statistics)
5435c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
543610bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
5437a2aede97SDouglas Gilbert 		/* schedule the invocation of scsi_done() for a later time */
5438c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
5439c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
544010bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
544110bde980SDouglas Gilbert 			sd_dp->init_wq = true;
5442a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5443c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5444c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5445a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5446cbf67842SDouglas Gilbert 		}
5447c4837394SDouglas Gilbert 		if (sdebug_statistics)
5448c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
544910bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
54507382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
54517382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
5452a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
54537382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
54547382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
54557382f9d8SDouglas Gilbert 				    cmnd->request->tag);
54567382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
54577382f9d8SDouglas Gilbert 		}
5458cbf67842SDouglas Gilbert 	}
5459f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
5460f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
5461cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5462cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
5463cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
5464cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
54651da177e4SLinus Torvalds 	return 0;
5466cd62b7daSDouglas Gilbert 
5467cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5468f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5469f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5470f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5471cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
5472cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
5473cd62b7daSDouglas Gilbert 	return 0;
54741da177e4SLinus Torvalds }
5475cbf67842SDouglas Gilbert 
547623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
547723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
547823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
547923183910SDouglas Gilbert    as it can when the corresponding attribute in the
548023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
548123183910SDouglas Gilbert  */
5482773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5483773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
54849b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5485773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5486c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5487773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5488773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5489773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5490773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5491773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5492773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5493773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5494773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5495e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5496e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5497e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5498e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
54995d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
55005d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
55015d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5502773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5503773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5504773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5505773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5506773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5507773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
55085d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
55095d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
55105d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
55115d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5512773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5513773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5514773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5515773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5516773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5517773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
55185d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5519773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
552087c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
552187c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5522773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5523773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
55240c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5525773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5526773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5527773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5528c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5529773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5530c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5531773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5532773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5533773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5534773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
553509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
55365d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5537773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
553823183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
55399447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5540773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
55415b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
55429267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
55431da177e4SLinus Torvalds 
55441da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
55451da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
55461da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5547b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
55481da177e4SLinus Torvalds 
55495d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
55505b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
55519b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
55520759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5553cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5554c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
55555b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
55565b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5557c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5558beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
555923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
55605b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5561185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5562e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
55639b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
55649b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
55655d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
55665d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
55675d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
55685b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
55695b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
55705b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
55715b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5572c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5573cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5574d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
55755d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5576cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5577c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
557878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
55791da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5580c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
558132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
558286e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
55835d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
55845d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
55855d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
55861da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
55870c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5588d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5589760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5590ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5591c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5592c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5593c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
55945b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
55955b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
55966014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
55976014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
559809ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
559909ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5600c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
56015b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
56029447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
56035b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
56049267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
56051da177e4SLinus Torvalds 
5606760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5607760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
56081da177e4SLinus Torvalds 
56091da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
56101da177e4SLinus Torvalds {
5611c4837394SDouglas Gilbert 	int k;
5612c4837394SDouglas Gilbert 
5613760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5614760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5615760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5616c4837394SDouglas Gilbert 		return sdebug_info;
5617760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5618760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5619760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5620760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
56211da177e4SLinus Torvalds 	return sdebug_info;
56221da177e4SLinus Torvalds }
56231da177e4SLinus Torvalds 
5624cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5625fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5626fd32119bSDouglas Gilbert 				 int length)
56271da177e4SLinus Torvalds {
56281da177e4SLinus Torvalds 	char arr[16];
5629c8ed555aSAl Viro 	int opts;
56301da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
56311da177e4SLinus Torvalds 
56321da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
56331da177e4SLinus Torvalds 		return -EACCES;
56341da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
56351da177e4SLinus Torvalds 	arr[minLen] = '\0';
5636c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
56371da177e4SLinus Torvalds 		return -EINVAL;
5638773642d9SDouglas Gilbert 	sdebug_opts = opts;
5639773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5640773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5641773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5642c4837394SDouglas Gilbert 		tweak_cmnd_count();
56431da177e4SLinus Torvalds 	return length;
56441da177e4SLinus Torvalds }
5645c8ed555aSAl Viro 
5646cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5647cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5648cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5649c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5650c8ed555aSAl Viro {
5651c4837394SDouglas Gilbert 	int f, j, l;
5652c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
565387c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5654cbf67842SDouglas Gilbert 
5655c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5656c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5657c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5658c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5659c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5660c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5661c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5662c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5663c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5664c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5665c4837394SDouglas Gilbert 		   num_aborts);
5666c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5667c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5668c4837394SDouglas Gilbert 		   num_host_resets);
5669c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5670c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5671458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5672458df78bSBart Van Assche 		   sdebug_statistics);
5673c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
5674c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5675c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5676c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
5677c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
5678cbf67842SDouglas Gilbert 
5679c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5680c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5681c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5682c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5683773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5684c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5685c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5686c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5687c4837394SDouglas Gilbert 		}
5688cbf67842SDouglas Gilbert 	}
568987c715dcSDouglas Gilbert 
569087c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
569187c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
569287c715dcSDouglas Gilbert 		bool niu;
569387c715dcSDouglas Gilbert 		int idx;
569487c715dcSDouglas Gilbert 		unsigned long l_idx;
569587c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
569687c715dcSDouglas Gilbert 
569787c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
569887c715dcSDouglas Gilbert 		j = 0;
569987c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
570087c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
570187c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
570287c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
570387c715dcSDouglas Gilbert 			++j;
570487c715dcSDouglas Gilbert 		}
570587c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
570687c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
570787c715dcSDouglas Gilbert 		j = 0;
570887c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
570987c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
571087c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
571187c715dcSDouglas Gilbert 			idx = (int)l_idx;
571287c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
571387c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
571487c715dcSDouglas Gilbert 			++j;
571587c715dcSDouglas Gilbert 		}
571687c715dcSDouglas Gilbert 	}
5717c8ed555aSAl Viro 	return 0;
57181da177e4SLinus Torvalds }
57191da177e4SLinus Torvalds 
572082069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
57211da177e4SLinus Torvalds {
5722c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
57231da177e4SLinus Torvalds }
5724c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5725c4837394SDouglas Gilbert  * of delay is jiffies.
5726c4837394SDouglas Gilbert  */
572782069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
572882069379SAkinobu Mita 			   size_t count)
57291da177e4SLinus Torvalds {
5730c2206098SDouglas Gilbert 	int jdelay, res;
57311da177e4SLinus Torvalds 
5732b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5733cbf67842SDouglas Gilbert 		res = count;
5734c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5735c4837394SDouglas Gilbert 			int j, k;
5736c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5737cbf67842SDouglas Gilbert 
5738c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5739c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5740c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5741c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5742c4837394SDouglas Gilbert 						   sdebug_max_queue);
5743c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5744c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5745c4837394SDouglas Gilbert 					break;
5746c4837394SDouglas Gilbert 				}
5747c4837394SDouglas Gilbert 			}
5748c4837394SDouglas Gilbert 			if (res > 0) {
5749c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5750773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
57511da177e4SLinus Torvalds 			}
5752c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5753cbf67842SDouglas Gilbert 		}
5754cbf67842SDouglas Gilbert 		return res;
57551da177e4SLinus Torvalds 	}
57561da177e4SLinus Torvalds 	return -EINVAL;
57571da177e4SLinus Torvalds }
575882069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
57591da177e4SLinus Torvalds 
5760cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5761cbf67842SDouglas Gilbert {
5762773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5763cbf67842SDouglas Gilbert }
5764cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5765c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5766cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5767cbf67842SDouglas Gilbert 			    size_t count)
5768cbf67842SDouglas Gilbert {
5769c4837394SDouglas Gilbert 	int ndelay, res;
5770cbf67842SDouglas Gilbert 
5771cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5772c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5773cbf67842SDouglas Gilbert 		res = count;
5774773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5775c4837394SDouglas Gilbert 			int j, k;
5776c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5777c4837394SDouglas Gilbert 
5778c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5779c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5780c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5781c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5782c4837394SDouglas Gilbert 						   sdebug_max_queue);
5783c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5784c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5785c4837394SDouglas Gilbert 					break;
5786c4837394SDouglas Gilbert 				}
5787c4837394SDouglas Gilbert 			}
5788c4837394SDouglas Gilbert 			if (res > 0) {
5789773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5790c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5791c2206098SDouglas Gilbert 							: DEF_JDELAY;
5792cbf67842SDouglas Gilbert 			}
5793c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5794cbf67842SDouglas Gilbert 		}
5795cbf67842SDouglas Gilbert 		return res;
5796cbf67842SDouglas Gilbert 	}
5797cbf67842SDouglas Gilbert 	return -EINVAL;
5798cbf67842SDouglas Gilbert }
5799cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5800cbf67842SDouglas Gilbert 
580182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
58021da177e4SLinus Torvalds {
5803773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
58041da177e4SLinus Torvalds }
58051da177e4SLinus Torvalds 
580682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
580782069379SAkinobu Mita 			  size_t count)
58081da177e4SLinus Torvalds {
58091da177e4SLinus Torvalds 	int opts;
58101da177e4SLinus Torvalds 	char work[20];
58111da177e4SLinus Torvalds 
58129a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
58139a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
58149a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
58151da177e4SLinus Torvalds 				goto opts_done;
58161da177e4SLinus Torvalds 		} else {
58179a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
58181da177e4SLinus Torvalds 				goto opts_done;
58191da177e4SLinus Torvalds 		}
58201da177e4SLinus Torvalds 	}
58211da177e4SLinus Torvalds 	return -EINVAL;
58221da177e4SLinus Torvalds opts_done:
5823773642d9SDouglas Gilbert 	sdebug_opts = opts;
5824773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5825773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5826c4837394SDouglas Gilbert 	tweak_cmnd_count();
58271da177e4SLinus Torvalds 	return count;
58281da177e4SLinus Torvalds }
582982069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
58301da177e4SLinus Torvalds 
583182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
58321da177e4SLinus Torvalds {
5833773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
58341da177e4SLinus Torvalds }
583582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
583682069379SAkinobu Mita 			   size_t count)
58371da177e4SLinus Torvalds {
58381da177e4SLinus Torvalds 	int n;
58391da177e4SLinus Torvalds 
5840f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5841f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5842f0d1cf93SDouglas Gilbert 		return -EINVAL;
5843f0d1cf93SDouglas Gilbert 
58441da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5845f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
5846f0d1cf93SDouglas Gilbert 			return -EINVAL;
5847773642d9SDouglas Gilbert 		sdebug_ptype = n;
58481da177e4SLinus Torvalds 		return count;
58491da177e4SLinus Torvalds 	}
58501da177e4SLinus Torvalds 	return -EINVAL;
58511da177e4SLinus Torvalds }
585282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
58531da177e4SLinus Torvalds 
585482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
58551da177e4SLinus Torvalds {
5856773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
58571da177e4SLinus Torvalds }
585882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
585982069379SAkinobu Mita 			    size_t count)
58601da177e4SLinus Torvalds {
58611da177e4SLinus Torvalds 	int n;
58621da177e4SLinus Torvalds 
58631da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5864773642d9SDouglas Gilbert 		sdebug_dsense = n;
58651da177e4SLinus Torvalds 		return count;
58661da177e4SLinus Torvalds 	}
58671da177e4SLinus Torvalds 	return -EINVAL;
58681da177e4SLinus Torvalds }
586982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
58701da177e4SLinus Torvalds 
587182069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
587223183910SDouglas Gilbert {
5873773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
587423183910SDouglas Gilbert }
587582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
587682069379SAkinobu Mita 			     size_t count)
587723183910SDouglas Gilbert {
587887c715dcSDouglas Gilbert 	int n, idx;
587923183910SDouglas Gilbert 
588023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
588187c715dcSDouglas Gilbert 		bool want_store = (n == 0);
588287c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
588387c715dcSDouglas Gilbert 
5884cbf67842SDouglas Gilbert 		n = (n > 0);
5885773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
588687c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
588787c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
5888cbf67842SDouglas Gilbert 
588987c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
589087c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
589187c715dcSDouglas Gilbert 				idx = sdebug_add_store();
589287c715dcSDouglas Gilbert 				if (idx < 0)
589387c715dcSDouglas Gilbert 					return idx;
589487c715dcSDouglas Gilbert 			} else {
589587c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
589687c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
589787c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
5898cbf67842SDouglas Gilbert 			}
589987c715dcSDouglas Gilbert 			/* make all hosts use same store */
590087c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
590187c715dcSDouglas Gilbert 					    host_list) {
590287c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
590387c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
590487c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
590587c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
590687c715dcSDouglas Gilbert 				}
590787c715dcSDouglas Gilbert 			}
590887c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
590987c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
591087c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
5911cbf67842SDouglas Gilbert 		}
5912773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
591323183910SDouglas Gilbert 		return count;
591423183910SDouglas Gilbert 	}
591523183910SDouglas Gilbert 	return -EINVAL;
591623183910SDouglas Gilbert }
591782069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
591823183910SDouglas Gilbert 
591982069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
5920c65b1445SDouglas Gilbert {
5921773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
5922c65b1445SDouglas Gilbert }
592382069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
592482069379SAkinobu Mita 			      size_t count)
5925c65b1445SDouglas Gilbert {
5926c65b1445SDouglas Gilbert 	int n;
5927c65b1445SDouglas Gilbert 
5928c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5929773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
5930c65b1445SDouglas Gilbert 		return count;
5931c65b1445SDouglas Gilbert 	}
5932c65b1445SDouglas Gilbert 	return -EINVAL;
5933c65b1445SDouglas Gilbert }
593482069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
5935c65b1445SDouglas Gilbert 
593682069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
59371da177e4SLinus Torvalds {
5938773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
59391da177e4SLinus Torvalds }
594082069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
594182069379SAkinobu Mita 			      size_t count)
59421da177e4SLinus Torvalds {
59431da177e4SLinus Torvalds 	int n;
59441da177e4SLinus Torvalds 
59451da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5946773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
59471da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
59481da177e4SLinus Torvalds 		return count;
59491da177e4SLinus Torvalds 	}
59501da177e4SLinus Torvalds 	return -EINVAL;
59511da177e4SLinus Torvalds }
595282069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
59531da177e4SLinus Torvalds 
595482069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
59551da177e4SLinus Torvalds {
5956773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
59571da177e4SLinus Torvalds }
595882069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
59591da177e4SLinus Torvalds 
596087c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
596187c715dcSDouglas Gilbert {
596287c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
596387c715dcSDouglas Gilbert }
596487c715dcSDouglas Gilbert 
596587c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
596687c715dcSDouglas Gilbert 				    size_t count)
596787c715dcSDouglas Gilbert {
596887c715dcSDouglas Gilbert 	bool v;
596987c715dcSDouglas Gilbert 
597087c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
597187c715dcSDouglas Gilbert 		return -EINVAL;
597287c715dcSDouglas Gilbert 
597387c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
597487c715dcSDouglas Gilbert 	return count;
597587c715dcSDouglas Gilbert }
597687c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
597787c715dcSDouglas Gilbert 
597882069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
59791da177e4SLinus Torvalds {
5980773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
59811da177e4SLinus Torvalds }
598282069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
59831da177e4SLinus Torvalds 
598482069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
59851da177e4SLinus Torvalds {
5986773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
59871da177e4SLinus Torvalds }
598882069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
598982069379SAkinobu Mita 			       size_t count)
59901da177e4SLinus Torvalds {
59911da177e4SLinus Torvalds 	int nth;
59921da177e4SLinus Torvalds 
59931da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
5994773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
5995c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
5996c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
5997c4837394SDouglas Gilbert 			sdebug_statistics = true;
5998c4837394SDouglas Gilbert 		}
5999c4837394SDouglas Gilbert 		tweak_cmnd_count();
60001da177e4SLinus Torvalds 		return count;
60011da177e4SLinus Torvalds 	}
60021da177e4SLinus Torvalds 	return -EINVAL;
60031da177e4SLinus Torvalds }
600482069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
60051da177e4SLinus Torvalds 
600682069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
60071da177e4SLinus Torvalds {
6008773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
60091da177e4SLinus Torvalds }
601082069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
601182069379SAkinobu Mita 			      size_t count)
60121da177e4SLinus Torvalds {
60131da177e4SLinus Torvalds 	int n;
601419c8ead7SEwan D. Milne 	bool changed;
60151da177e4SLinus Torvalds 
60161da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60178d039e22SDouglas Gilbert 		if (n > 256) {
60188d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
60198d039e22SDouglas Gilbert 			return -EINVAL;
60208d039e22SDouglas Gilbert 		}
6021773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6022773642d9SDouglas Gilbert 		sdebug_max_luns = n;
60231da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6024773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
602519c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
602619c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
602719c8ead7SEwan D. Milne 
602819c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
602919c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
603019c8ead7SEwan D. Milne 					    host_list) {
603119c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
603219c8ead7SEwan D. Milne 						    dev_list) {
603319c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
603419c8ead7SEwan D. Milne 						dp->uas_bm);
603519c8ead7SEwan D. Milne 				}
603619c8ead7SEwan D. Milne 			}
603719c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
603819c8ead7SEwan D. Milne 		}
60391da177e4SLinus Torvalds 		return count;
60401da177e4SLinus Torvalds 	}
60411da177e4SLinus Torvalds 	return -EINVAL;
60421da177e4SLinus Torvalds }
604382069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
60441da177e4SLinus Torvalds 
604582069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
604678d4e5a0SDouglas Gilbert {
6047773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
604878d4e5a0SDouglas Gilbert }
6049cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6050cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
605182069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
605282069379SAkinobu Mita 			       size_t count)
605378d4e5a0SDouglas Gilbert {
6054c4837394SDouglas Gilbert 	int j, n, k, a;
6055c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
605678d4e5a0SDouglas Gilbert 
605778d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6058c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
6059c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6060c4837394SDouglas Gilbert 		k = 0;
6061c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6062c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6063c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6064c4837394SDouglas Gilbert 			if (a > k)
6065c4837394SDouglas Gilbert 				k = a;
6066c4837394SDouglas Gilbert 		}
6067773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6068c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6069cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6070cbf67842SDouglas Gilbert 		else if (k >= n)
6071cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6072cbf67842SDouglas Gilbert 		else
6073cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6074c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
607578d4e5a0SDouglas Gilbert 		return count;
607678d4e5a0SDouglas Gilbert 	}
607778d4e5a0SDouglas Gilbert 	return -EINVAL;
607878d4e5a0SDouglas Gilbert }
607982069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
608078d4e5a0SDouglas Gilbert 
608182069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
608278d4e5a0SDouglas Gilbert {
6083773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
608478d4e5a0SDouglas Gilbert }
608582069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
608678d4e5a0SDouglas Gilbert 
608782069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
60881da177e4SLinus Torvalds {
6089773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
60901da177e4SLinus Torvalds }
609182069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
60921da177e4SLinus Torvalds 
609382069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6094c65b1445SDouglas Gilbert {
6095773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6096c65b1445SDouglas Gilbert }
609782069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
609882069379SAkinobu Mita 				size_t count)
6099c65b1445SDouglas Gilbert {
6100c65b1445SDouglas Gilbert 	int n;
61010d01c5dfSDouglas Gilbert 	bool changed;
6102c65b1445SDouglas Gilbert 
6103f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6104f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6105f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6106f0d1cf93SDouglas Gilbert 
6107c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6108773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6109773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
611028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
61110d01c5dfSDouglas Gilbert 		if (changed) {
61120d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
61130d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
611428898873SFUJITA Tomonori 
61154bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
61160d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
61170d01c5dfSDouglas Gilbert 					    host_list) {
61180d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
61190d01c5dfSDouglas Gilbert 						    dev_list) {
61200d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
61210d01c5dfSDouglas Gilbert 						dp->uas_bm);
61220d01c5dfSDouglas Gilbert 				}
61230d01c5dfSDouglas Gilbert 			}
61244bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
61250d01c5dfSDouglas Gilbert 		}
6126c65b1445SDouglas Gilbert 		return count;
6127c65b1445SDouglas Gilbert 	}
6128c65b1445SDouglas Gilbert 	return -EINVAL;
6129c65b1445SDouglas Gilbert }
613082069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6131c65b1445SDouglas Gilbert 
613282069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
61331da177e4SLinus Torvalds {
613487c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
613587c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
61361da177e4SLinus Torvalds }
61371da177e4SLinus Torvalds 
613882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
613982069379SAkinobu Mita 			      size_t count)
61401da177e4SLinus Torvalds {
614187c715dcSDouglas Gilbert 	bool found;
614287c715dcSDouglas Gilbert 	unsigned long idx;
614387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
614487c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
61451da177e4SLinus Torvalds 	int delta_hosts;
61461da177e4SLinus Torvalds 
6147f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
61481da177e4SLinus Torvalds 		return -EINVAL;
61491da177e4SLinus Torvalds 	if (delta_hosts > 0) {
61501da177e4SLinus Torvalds 		do {
615187c715dcSDouglas Gilbert 			found = false;
615287c715dcSDouglas Gilbert 			if (want_phs) {
615387c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
615487c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
615587c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
615687c715dcSDouglas Gilbert 					found = true;
615787c715dcSDouglas Gilbert 					break;
615887c715dcSDouglas Gilbert 				}
615987c715dcSDouglas Gilbert 				if (found)	/* re-use case */
616087c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
616187c715dcSDouglas Gilbert 				else
616287c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
616387c715dcSDouglas Gilbert 			} else {
616487c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
616587c715dcSDouglas Gilbert 			}
61661da177e4SLinus Torvalds 		} while (--delta_hosts);
61671da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
61681da177e4SLinus Torvalds 		do {
616987c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
61701da177e4SLinus Torvalds 		} while (++delta_hosts);
61711da177e4SLinus Torvalds 	}
61721da177e4SLinus Torvalds 	return count;
61731da177e4SLinus Torvalds }
617482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
61751da177e4SLinus Torvalds 
617682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
617723183910SDouglas Gilbert {
6178773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
617923183910SDouglas Gilbert }
618082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
618182069379SAkinobu Mita 				    size_t count)
618223183910SDouglas Gilbert {
618323183910SDouglas Gilbert 	int n;
618423183910SDouglas Gilbert 
618523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6186773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
618723183910SDouglas Gilbert 		return count;
618823183910SDouglas Gilbert 	}
618923183910SDouglas Gilbert 	return -EINVAL;
619023183910SDouglas Gilbert }
619182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
619223183910SDouglas Gilbert 
6193c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6194c4837394SDouglas Gilbert {
6195c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6196c4837394SDouglas Gilbert }
6197c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6198c4837394SDouglas Gilbert 				size_t count)
6199c4837394SDouglas Gilbert {
6200c4837394SDouglas Gilbert 	int n;
6201c4837394SDouglas Gilbert 
6202c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6203c4837394SDouglas Gilbert 		if (n > 0)
6204c4837394SDouglas Gilbert 			sdebug_statistics = true;
6205c4837394SDouglas Gilbert 		else {
6206c4837394SDouglas Gilbert 			clear_queue_stats();
6207c4837394SDouglas Gilbert 			sdebug_statistics = false;
6208c4837394SDouglas Gilbert 		}
6209c4837394SDouglas Gilbert 		return count;
6210c4837394SDouglas Gilbert 	}
6211c4837394SDouglas Gilbert 	return -EINVAL;
6212c4837394SDouglas Gilbert }
6213c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6214c4837394SDouglas Gilbert 
621582069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6216597136abSMartin K. Petersen {
6217773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6218597136abSMartin K. Petersen }
621982069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6220597136abSMartin K. Petersen 
6221c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6222c4837394SDouglas Gilbert {
6223c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6224c4837394SDouglas Gilbert }
6225c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6226c4837394SDouglas Gilbert 
622782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6228c6a44287SMartin K. Petersen {
6229773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6230c6a44287SMartin K. Petersen }
623182069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6232c6a44287SMartin K. Petersen 
623382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6234c6a44287SMartin K. Petersen {
6235773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6236c6a44287SMartin K. Petersen }
623782069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6238c6a44287SMartin K. Petersen 
623982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6240c6a44287SMartin K. Petersen {
6241773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6242c6a44287SMartin K. Petersen }
624382069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6244c6a44287SMartin K. Petersen 
624582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6246c6a44287SMartin K. Petersen {
6247773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6248c6a44287SMartin K. Petersen }
624982069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6250c6a44287SMartin K. Petersen 
625182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
625244d92694SMartin K. Petersen {
625387c715dcSDouglas Gilbert 	ssize_t count = 0;
625444d92694SMartin K. Petersen 
62555b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
625644d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
625744d92694SMartin K. Petersen 				 sdebug_store_sectors);
625844d92694SMartin K. Petersen 
625987c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
626087c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
626187c715dcSDouglas Gilbert 
626287c715dcSDouglas Gilbert 		if (sip)
6263c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
626487c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
626587c715dcSDouglas Gilbert 	}
626644d92694SMartin K. Petersen 	buf[count++] = '\n';
6267c7badc90STejun Heo 	buf[count] = '\0';
626844d92694SMartin K. Petersen 
626944d92694SMartin K. Petersen 	return count;
627044d92694SMartin K. Petersen }
627182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
627244d92694SMartin K. Petersen 
62730c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
62740c4bc91dSDouglas Gilbert {
62750c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
62760c4bc91dSDouglas Gilbert }
62770c4bc91dSDouglas Gilbert 
62780c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
62790c4bc91dSDouglas Gilbert 			    size_t count)
62800c4bc91dSDouglas Gilbert {
62810c4bc91dSDouglas Gilbert 	bool v;
62820c4bc91dSDouglas Gilbert 
62830c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
62840c4bc91dSDouglas Gilbert 		return -EINVAL;
62850c4bc91dSDouglas Gilbert 
62860c4bc91dSDouglas Gilbert 	sdebug_random = v;
62870c4bc91dSDouglas Gilbert 	return count;
62880c4bc91dSDouglas Gilbert }
62890c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
62900c4bc91dSDouglas Gilbert 
629182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6292d986788bSMartin Pitt {
6293773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6294d986788bSMartin Pitt }
629582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
629682069379SAkinobu Mita 			       size_t count)
6297d986788bSMartin Pitt {
6298d986788bSMartin Pitt 	int n;
6299d986788bSMartin Pitt 
6300d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6301773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6302d986788bSMartin Pitt 		return count;
6303d986788bSMartin Pitt 	}
6304d986788bSMartin Pitt 	return -EINVAL;
6305d986788bSMartin Pitt }
630682069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6307d986788bSMartin Pitt 
6308cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6309cbf67842SDouglas Gilbert {
6310773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6311cbf67842SDouglas Gilbert }
6312185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6313cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6314cbf67842SDouglas Gilbert 			       size_t count)
6315cbf67842SDouglas Gilbert {
6316185dd232SDouglas Gilbert 	int n;
6317cbf67842SDouglas Gilbert 
6318cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6319185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6320185dd232SDouglas Gilbert 		return count;
6321cbf67842SDouglas Gilbert 	}
6322cbf67842SDouglas Gilbert 	return -EINVAL;
6323cbf67842SDouglas Gilbert }
6324cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6325cbf67842SDouglas Gilbert 
6326c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6327c2248fc9SDouglas Gilbert {
6328773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6329c2248fc9SDouglas Gilbert }
6330c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6331c2248fc9SDouglas Gilbert 			    size_t count)
6332c2248fc9SDouglas Gilbert {
6333c2248fc9SDouglas Gilbert 	int n;
6334c2248fc9SDouglas Gilbert 
6335c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6336773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6337c2248fc9SDouglas Gilbert 		return count;
6338c2248fc9SDouglas Gilbert 	}
6339c2248fc9SDouglas Gilbert 	return -EINVAL;
6340c2248fc9SDouglas Gilbert }
6341c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6342c2248fc9SDouglas Gilbert 
634309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
634409ba24c1SDouglas Gilbert {
634509ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
634609ba24c1SDouglas Gilbert }
634709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
634809ba24c1SDouglas Gilbert 
63499b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
63509b760fd8SDouglas Gilbert {
63519b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
63529b760fd8SDouglas Gilbert }
63539b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
63549b760fd8SDouglas Gilbert 			     size_t count)
63559b760fd8SDouglas Gilbert {
63569b760fd8SDouglas Gilbert 	int ret, n;
63579b760fd8SDouglas Gilbert 
63589b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
63599b760fd8SDouglas Gilbert 	if (ret)
63609b760fd8SDouglas Gilbert 		return ret;
63619b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
63629b760fd8SDouglas Gilbert 	all_config_cdb_len();
63639b760fd8SDouglas Gilbert 	return count;
63649b760fd8SDouglas Gilbert }
63659b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
63669b760fd8SDouglas Gilbert 
63679267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
63689267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
63699267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
63709267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
63719267e0ebSDouglas Gilbert };
63729267e0ebSDouglas Gilbert 
63739267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
63749267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
63759267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
63769267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
63779267e0ebSDouglas Gilbert };
63789267e0ebSDouglas Gilbert 
63799267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
63809267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
63819267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
63829267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
63839267e0ebSDouglas Gilbert };
63849267e0ebSDouglas Gilbert 
63859267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
63869267e0ebSDouglas Gilbert {
63879267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
63889267e0ebSDouglas Gilbert 
63899267e0ebSDouglas Gilbert 	if (res < 0) {
63909267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
63919267e0ebSDouglas Gilbert 		if (res < 0) {
63929267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
63939267e0ebSDouglas Gilbert 			if (sdeb_zbc_model < 0)
63949267e0ebSDouglas Gilbert 				return -EINVAL;
63959267e0ebSDouglas Gilbert 		}
63969267e0ebSDouglas Gilbert 	}
63979267e0ebSDouglas Gilbert 	return res;
63989267e0ebSDouglas Gilbert }
63999267e0ebSDouglas Gilbert 
64009267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
64019267e0ebSDouglas Gilbert {
64029267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
64039267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
64049267e0ebSDouglas Gilbert }
64059267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6406cbf67842SDouglas Gilbert 
640782069379SAkinobu Mita /* Note: The following array creates attribute files in the
640823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
640923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
641023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
641187c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
641223183910SDouglas Gilbert  */
64136ecaff7fSRandy Dunlap 
641482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
641582069379SAkinobu Mita 	&driver_attr_delay.attr,
641682069379SAkinobu Mita 	&driver_attr_opts.attr,
641782069379SAkinobu Mita 	&driver_attr_ptype.attr,
641882069379SAkinobu Mita 	&driver_attr_dsense.attr,
641982069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
642082069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
642182069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
642282069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
642382069379SAkinobu Mita 	&driver_attr_num_parts.attr,
642482069379SAkinobu Mita 	&driver_attr_every_nth.attr,
642582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
642682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
642782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
642882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
642982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
643082069379SAkinobu Mita 	&driver_attr_add_host.attr,
643187c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
643282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
643382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6434c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6435c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
643682069379SAkinobu Mita 	&driver_attr_dix.attr,
643782069379SAkinobu Mita 	&driver_attr_dif.attr,
643882069379SAkinobu Mita 	&driver_attr_guard.attr,
643982069379SAkinobu Mita 	&driver_attr_ato.attr,
644082069379SAkinobu Mita 	&driver_attr_map.attr,
64410c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
644282069379SAkinobu Mita 	&driver_attr_removable.attr,
6443cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6444cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6445c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
644609ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
64479b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
64489267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
644982069379SAkinobu Mita 	NULL,
645082069379SAkinobu Mita };
645182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
64521da177e4SLinus Torvalds 
645311ddcecaSAkinobu Mita static struct device *pseudo_primary;
64548dea0d02SFUJITA Tomonori 
64551da177e4SLinus Torvalds static int __init scsi_debug_init(void)
64561da177e4SLinus Torvalds {
645787c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
64585f2578e5SFUJITA Tomonori 	unsigned long sz;
645987c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
646087c715dcSDouglas Gilbert 	int idx = -1;
64611da177e4SLinus Torvalds 
646287c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
646387c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6464cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6465cbf67842SDouglas Gilbert 
6466773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6467c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6468773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6469773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6470c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6471cbf67842SDouglas Gilbert 
6472773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6473597136abSMartin K. Petersen 	case  512:
6474597136abSMartin K. Petersen 	case 1024:
6475597136abSMartin K. Petersen 	case 2048:
6476597136abSMartin K. Petersen 	case 4096:
6477597136abSMartin K. Petersen 		break;
6478597136abSMartin K. Petersen 	default:
6479773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6480597136abSMartin K. Petersen 		return -EINVAL;
6481597136abSMartin K. Petersen 	}
6482597136abSMartin K. Petersen 
6483773642d9SDouglas Gilbert 	switch (sdebug_dif) {
64848475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6485f46eb0e9SDouglas Gilbert 		break;
64868475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
64878475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
64888475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6489f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6490c6a44287SMartin K. Petersen 		break;
6491c6a44287SMartin K. Petersen 
6492c6a44287SMartin K. Petersen 	default:
6493c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6494c6a44287SMartin K. Petersen 		return -EINVAL;
6495c6a44287SMartin K. Petersen 	}
6496c6a44287SMartin K. Petersen 
6497aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6498aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6499aa5334c4SMaurizio Lombardi 		return -EINVAL;
6500aa5334c4SMaurizio Lombardi 	}
6501aa5334c4SMaurizio Lombardi 
6502773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6503c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6504c6a44287SMartin K. Petersen 		return -EINVAL;
6505c6a44287SMartin K. Petersen 	}
6506c6a44287SMartin K. Petersen 
6507773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6508c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6509c6a44287SMartin K. Petersen 		return -EINVAL;
6510c6a44287SMartin K. Petersen 	}
6511c6a44287SMartin K. Petersen 
6512773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6513773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6514ea61fca5SMartin K. Petersen 		return -EINVAL;
6515ea61fca5SMartin K. Petersen 	}
65168d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
65178d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
65188d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
65198d039e22SDouglas Gilbert 	}
6520ea61fca5SMartin K. Petersen 
6521773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6522773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6523ea61fca5SMartin K. Petersen 		return -EINVAL;
6524ea61fca5SMartin K. Petersen 	}
6525ea61fca5SMartin K. Petersen 
6526c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6527c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6528c4837394SDouglas Gilbert 		return -EINVAL;
6529c4837394SDouglas Gilbert 	}
6530c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6531c4837394SDouglas Gilbert 			       GFP_KERNEL);
6532c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6533c4837394SDouglas Gilbert 		return -ENOMEM;
6534c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6535c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6536c4837394SDouglas Gilbert 
6537f0d1cf93SDouglas Gilbert 	/*
65389267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
65399267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6540f0d1cf93SDouglas Gilbert 	 */
65419267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
65429267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
65439267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
65449267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
65459267e0ebSDouglas Gilbert 		if (k < 0) {
65469267e0ebSDouglas Gilbert 			ret = k;
65479267e0ebSDouglas Gilbert 			goto free_vm;
65489267e0ebSDouglas Gilbert 		}
65499267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
65509267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
65519267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
65529267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
65539267e0ebSDouglas Gilbert 			break;
65549267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
65559267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
65569267e0ebSDouglas Gilbert 			break;
65579267e0ebSDouglas Gilbert 		case BLK_ZONED_HA:
65589267e0ebSDouglas Gilbert 		default:
65599267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
65609267e0ebSDouglas Gilbert 			return -EINVAL;
65619267e0ebSDouglas Gilbert 		}
65629267e0ebSDouglas Gilbert 	}
65639267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6564f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
65659267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
65669267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
65679267e0ebSDouglas Gilbert 	}
6568f0d1cf93SDouglas Gilbert 
65699267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
65709267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6571773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6572773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6573773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6574773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
657528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
65761da177e4SLinus Torvalds 
65771da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
65781da177e4SLinus Torvalds 	sdebug_heads = 8;
65791da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6580773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
65811da177e4SLinus Torvalds 		sdebug_heads = 64;
6582773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6583fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
65841da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
65851da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
65861da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
65871da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
65881da177e4SLinus Torvalds 		sdebug_heads = 255;
65891da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
65901da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
65911da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
65921da177e4SLinus Torvalds 	}
65935b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6594773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6595773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
65966014759cSMartin K. Petersen 
6597773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6598773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
65996014759cSMartin K. Petersen 
6600773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6601773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
66026014759cSMartin K. Petersen 
6603773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6604773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6605773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6606c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6607c4837394SDouglas Gilbert 			ret = -EINVAL;
660887c715dcSDouglas Gilbert 			goto free_q_arr;
660944d92694SMartin K. Petersen 		}
661044d92694SMartin K. Petersen 	}
661187c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
661287c715dcSDouglas Gilbert 	if (want_store) {
661387c715dcSDouglas Gilbert 		idx = sdebug_add_store();
661487c715dcSDouglas Gilbert 		if (idx < 0) {
661587c715dcSDouglas Gilbert 			ret = idx;
661687c715dcSDouglas Gilbert 			goto free_q_arr;
661787c715dcSDouglas Gilbert 		}
661844d92694SMartin K. Petersen 	}
661944d92694SMartin K. Petersen 
66209b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
66219b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6622c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
66239b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
66246ecaff7fSRandy Dunlap 		goto free_vm;
66256ecaff7fSRandy Dunlap 	}
66266ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
66276ecaff7fSRandy Dunlap 	if (ret < 0) {
6628c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
66296ecaff7fSRandy Dunlap 		goto dev_unreg;
66306ecaff7fSRandy Dunlap 	}
66316ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
66326ecaff7fSRandy Dunlap 	if (ret < 0) {
6633c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
66346ecaff7fSRandy Dunlap 		goto bus_unreg;
66356ecaff7fSRandy Dunlap 	}
66361da177e4SLinus Torvalds 
663787c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6638773642d9SDouglas Gilbert 	sdebug_add_host = 0;
66391da177e4SLinus Torvalds 
664087c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
664187c715dcSDouglas Gilbert 		if (want_store && k == 0) {
664287c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
664387c715dcSDouglas Gilbert 			if (ret < 0) {
664487c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
664587c715dcSDouglas Gilbert 				       k, -ret);
664687c715dcSDouglas Gilbert 				break;
664787c715dcSDouglas Gilbert 			}
664887c715dcSDouglas Gilbert 		} else {
664987c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
665087c715dcSDouglas Gilbert 						 sdebug_per_host_store);
665187c715dcSDouglas Gilbert 			if (ret < 0) {
665287c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
66531da177e4SLinus Torvalds 				break;
66541da177e4SLinus Torvalds 			}
66551da177e4SLinus Torvalds 		}
665687c715dcSDouglas Gilbert 	}
6657773642d9SDouglas Gilbert 	if (sdebug_verbose)
665887c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6659c1287970STomas Winkler 
66601da177e4SLinus Torvalds 	return 0;
66616ecaff7fSRandy Dunlap 
66626ecaff7fSRandy Dunlap bus_unreg:
66636ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
66646ecaff7fSRandy Dunlap dev_unreg:
66659b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
66666ecaff7fSRandy Dunlap free_vm:
666787c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6668c4837394SDouglas Gilbert free_q_arr:
6669c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
66706ecaff7fSRandy Dunlap 	return ret;
66711da177e4SLinus Torvalds }
66721da177e4SLinus Torvalds 
66731da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
66741da177e4SLinus Torvalds {
667587c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
66761da177e4SLinus Torvalds 
66771da177e4SLinus Torvalds 	stop_all_queued();
66781da177e4SLinus Torvalds 	for (; k; k--)
667987c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
668052ab9768SLuis Henriques 	free_all_queued();
66811da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
66821da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
66839b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
66841da177e4SLinus Torvalds 
668587c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
668687c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
66871da177e4SLinus Torvalds }
66881da177e4SLinus Torvalds 
66891da177e4SLinus Torvalds device_initcall(scsi_debug_init);
66901da177e4SLinus Torvalds module_exit(scsi_debug_exit);
66911da177e4SLinus Torvalds 
66921da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
66931da177e4SLinus Torvalds {
66941da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
66951da177e4SLinus Torvalds 
66961da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
66971da177e4SLinus Torvalds 	kfree(sdbg_host);
66981da177e4SLinus Torvalds }
66991da177e4SLinus Torvalds 
670087c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
670187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
67021da177e4SLinus Torvalds {
670387c715dcSDouglas Gilbert 	if (idx < 0)
670487c715dcSDouglas Gilbert 		return;
670587c715dcSDouglas Gilbert 	if (!sip) {
670687c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
670787c715dcSDouglas Gilbert 			return;
670887c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
670987c715dcSDouglas Gilbert 		if (!sip)
671087c715dcSDouglas Gilbert 			return;
671187c715dcSDouglas Gilbert 	}
671287c715dcSDouglas Gilbert 	vfree(sip->map_storep);
671387c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
671487c715dcSDouglas Gilbert 	vfree(sip->storep);
671587c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
671687c715dcSDouglas Gilbert 	kfree(sip);
671787c715dcSDouglas Gilbert }
671887c715dcSDouglas Gilbert 
671987c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
672087c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
672187c715dcSDouglas Gilbert {
672287c715dcSDouglas Gilbert 	unsigned long idx;
672387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
672487c715dcSDouglas Gilbert 
672587c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
672687c715dcSDouglas Gilbert 		if (apart_from_first)
672787c715dcSDouglas Gilbert 			apart_from_first = false;
672887c715dcSDouglas Gilbert 		else
672987c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
673087c715dcSDouglas Gilbert 	}
673187c715dcSDouglas Gilbert 	if (apart_from_first)
673287c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
673387c715dcSDouglas Gilbert }
673487c715dcSDouglas Gilbert 
673587c715dcSDouglas Gilbert /*
673687c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
673787c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
673887c715dcSDouglas Gilbert  */
673987c715dcSDouglas Gilbert static int sdebug_add_store(void)
674087c715dcSDouglas Gilbert {
674187c715dcSDouglas Gilbert 	int res;
674287c715dcSDouglas Gilbert 	u32 n_idx;
674387c715dcSDouglas Gilbert 	unsigned long iflags;
674487c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
674587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
674687c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
674787c715dcSDouglas Gilbert 
674887c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
674987c715dcSDouglas Gilbert 	if (!sip)
675087c715dcSDouglas Gilbert 		return -ENOMEM;
675187c715dcSDouglas Gilbert 
675287c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
675387c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
675487c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
675587c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
675687c715dcSDouglas Gilbert 		kfree(sip);
675787c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
675887c715dcSDouglas Gilbert 		return res;
675987c715dcSDouglas Gilbert 	}
676087c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
676187c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
676287c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
676387c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
676487c715dcSDouglas Gilbert 
676587c715dcSDouglas Gilbert 	res = -ENOMEM;
676687c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
676787c715dcSDouglas Gilbert 	if (!sip->storep) {
676887c715dcSDouglas Gilbert 		pr_err("user data oom\n");
676987c715dcSDouglas Gilbert 		goto err;
677087c715dcSDouglas Gilbert 	}
677187c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
677287c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
677387c715dcSDouglas Gilbert 
677487c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
677587c715dcSDouglas Gilbert 	if (sdebug_dix) {
677687c715dcSDouglas Gilbert 		int dif_size;
677787c715dcSDouglas Gilbert 
677887c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
677987c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
678087c715dcSDouglas Gilbert 
678187c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
678287c715dcSDouglas Gilbert 			sip->dif_storep);
678387c715dcSDouglas Gilbert 
678487c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
678587c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
678687c715dcSDouglas Gilbert 			goto err;
678787c715dcSDouglas Gilbert 		}
678887c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
678987c715dcSDouglas Gilbert 	}
679087c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
679187c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
679287c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
679387c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
679487c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
679587c715dcSDouglas Gilbert 
679687c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
679787c715dcSDouglas Gilbert 
679887c715dcSDouglas Gilbert 		if (!sip->map_storep) {
679987c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
680087c715dcSDouglas Gilbert 			goto err;
680187c715dcSDouglas Gilbert 		}
680287c715dcSDouglas Gilbert 
680387c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
680487c715dcSDouglas Gilbert 
680587c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
680687c715dcSDouglas Gilbert 		if (sdebug_num_parts)
680787c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
680887c715dcSDouglas Gilbert 	}
680987c715dcSDouglas Gilbert 
681087c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
681187c715dcSDouglas Gilbert 	return (int)n_idx;
681287c715dcSDouglas Gilbert err:
681387c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
681487c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
681587c715dcSDouglas Gilbert 	return res;
681687c715dcSDouglas Gilbert }
681787c715dcSDouglas Gilbert 
681887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
681987c715dcSDouglas Gilbert {
682087c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
682187c715dcSDouglas Gilbert 	int error = -ENOMEM;
68221da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
68238b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
68241da177e4SLinus Torvalds 
682524669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
682687c715dcSDouglas Gilbert 	if (!sdbg_host)
68271da177e4SLinus Torvalds 		return -ENOMEM;
682887c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
682987c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
683087c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
683187c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
68321da177e4SLinus Torvalds 
68331da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
68341da177e4SLinus Torvalds 
6835773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
68361da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
68375cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
683887c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
68391da177e4SLinus Torvalds 			goto clean;
68401da177e4SLinus Torvalds 	}
68411da177e4SLinus Torvalds 
68421da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
68431da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
68441da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
68451da177e4SLinus Torvalds 
68461da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
68479b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
68481da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
684987c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
68501da177e4SLinus Torvalds 
68511da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
68521da177e4SLinus Torvalds 	if (error)
68531da177e4SLinus Torvalds 		goto clean;
68541da177e4SLinus Torvalds 
685587c715dcSDouglas Gilbert 	++sdebug_num_hosts;
685687c715dcSDouglas Gilbert 	return 0;
68571da177e4SLinus Torvalds 
68581da177e4SLinus Torvalds clean:
68598b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
68608b40228fSFUJITA Tomonori 				 dev_list) {
68611da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
6862f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
68631da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
68641da177e4SLinus Torvalds 	}
68651da177e4SLinus Torvalds 	kfree(sdbg_host);
686687c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
68671da177e4SLinus Torvalds 	return error;
68681da177e4SLinus Torvalds }
68691da177e4SLinus Torvalds 
687087c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
68711da177e4SLinus Torvalds {
687287c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
687387c715dcSDouglas Gilbert 
687487c715dcSDouglas Gilbert 	if (mk_new_store) {
687587c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
687687c715dcSDouglas Gilbert 		if (ph_idx < 0)
687787c715dcSDouglas Gilbert 			return ph_idx;
687887c715dcSDouglas Gilbert 	}
687987c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
688087c715dcSDouglas Gilbert }
688187c715dcSDouglas Gilbert 
688287c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
688387c715dcSDouglas Gilbert {
688487c715dcSDouglas Gilbert 	int idx = -1;
68851da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
688687c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
68871da177e4SLinus Torvalds 
68881da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
68891da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
68901da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
68911da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
689287c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
68931da177e4SLinus Torvalds 	}
689487c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
689587c715dcSDouglas Gilbert 		bool unique = true;
689687c715dcSDouglas Gilbert 
689787c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
689887c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
689987c715dcSDouglas Gilbert 				continue;
690087c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
690187c715dcSDouglas Gilbert 				unique = false;
690287c715dcSDouglas Gilbert 				break;
690387c715dcSDouglas Gilbert 			}
690487c715dcSDouglas Gilbert 		}
690587c715dcSDouglas Gilbert 		if (unique) {
690687c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
690787c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
690887c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
690987c715dcSDouglas Gilbert 		}
691087c715dcSDouglas Gilbert 	}
691187c715dcSDouglas Gilbert 	if (sdbg_host)
691287c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
69131da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
69141da177e4SLinus Torvalds 
69151da177e4SLinus Torvalds 	if (!sdbg_host)
69161da177e4SLinus Torvalds 		return;
69171da177e4SLinus Torvalds 
69181da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
691987c715dcSDouglas Gilbert 	--sdebug_num_hosts;
69201da177e4SLinus Torvalds }
69211da177e4SLinus Torvalds 
6922fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
6923cbf67842SDouglas Gilbert {
6924cbf67842SDouglas Gilbert 	int num_in_q = 0;
6925cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
6926cbf67842SDouglas Gilbert 
6927c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
6928cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
6929cbf67842SDouglas Gilbert 	if (NULL == devip) {
6930c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
6931cbf67842SDouglas Gilbert 		return	-ENODEV;
6932cbf67842SDouglas Gilbert 	}
6933cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
6934c40ecc12SChristoph Hellwig 
6935cbf67842SDouglas Gilbert 	if (qdepth < 1)
6936cbf67842SDouglas Gilbert 		qdepth = 1;
6937c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
6938c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
6939c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
6940db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
6941cbf67842SDouglas Gilbert 
6942773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
6943c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
6944c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
6945cbf67842SDouglas Gilbert 	}
6946c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
6947cbf67842SDouglas Gilbert 	return sdev->queue_depth;
6948cbf67842SDouglas Gilbert }
6949cbf67842SDouglas Gilbert 
6950c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
6951817fd66bSDouglas Gilbert {
6952c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
6953773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
6954773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
6955773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
6956c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
6957773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
6958817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
6959c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
6960817fd66bSDouglas Gilbert 	}
6961c4837394SDouglas Gilbert 	return false;
6962817fd66bSDouglas Gilbert }
6963817fd66bSDouglas Gilbert 
69647ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
69657ee6d1b4SBart Van Assche {
69667ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
69677ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
69687ee6d1b4SBart Van Assche }
69697ee6d1b4SBart Van Assche 
6970fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
6971fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
6972c2248fc9SDouglas Gilbert {
6973c2248fc9SDouglas Gilbert 	u8 sdeb_i;
6974c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
6975c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
6976c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
6977c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
697887c715dcSDouglas Gilbert 
6979c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
6980c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
6981f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
6982c2248fc9SDouglas Gilbert 	int k, na;
6983c2248fc9SDouglas Gilbert 	int errsts = 0;
6984c2248fc9SDouglas Gilbert 	u32 flags;
6985c2248fc9SDouglas Gilbert 	u16 sa;
6986c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
6987c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
6988c2248fc9SDouglas Gilbert 
6989c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
6990c4837394SDouglas Gilbert 	if (sdebug_statistics)
6991c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
6992f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
6993f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
6994c2248fc9SDouglas Gilbert 		char b[120];
6995c2248fc9SDouglas Gilbert 		int n, len, sb;
6996c2248fc9SDouglas Gilbert 
6997c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
6998c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
6999c2248fc9SDouglas Gilbert 		if (len > 32)
7000c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7001c2248fc9SDouglas Gilbert 		else {
7002c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7003c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7004c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7005c2248fc9SDouglas Gilbert 		}
7006458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7007458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
7008c2248fc9SDouglas Gilbert 	}
70097ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
70107ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
701134d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7012f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
7013f46eb0e9SDouglas Gilbert 		goto err_out;
7014c2248fc9SDouglas Gilbert 
7015c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7016c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7017c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7018f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7019f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7020c2248fc9SDouglas Gilbert 		if (NULL == devip)
7021f46eb0e9SDouglas Gilbert 			goto err_out;
7022c2248fc9SDouglas Gilbert 	}
7023c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7024c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7025c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7026c2248fc9SDouglas Gilbert 		r_oip = oip;
7027c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7028c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7029c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7030c2248fc9SDouglas Gilbert 			else
7031c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7032c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7033c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7034c2248fc9SDouglas Gilbert 					break;
7035c2248fc9SDouglas Gilbert 			}
7036c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7037c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7038c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7039c2248fc9SDouglas Gilbert 					break;
7040c2248fc9SDouglas Gilbert 			}
7041c2248fc9SDouglas Gilbert 		}
7042c2248fc9SDouglas Gilbert 		if (k > na) {
7043c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7044c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7045c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7046c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7047c2248fc9SDouglas Gilbert 			else
7048c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7049c2248fc9SDouglas Gilbert 			goto check_cond;
7050c2248fc9SDouglas Gilbert 		}
7051c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7052c2248fc9SDouglas Gilbert 	flags = oip->flags;
7053f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7054c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7055c2248fc9SDouglas Gilbert 		goto check_cond;
7056c2248fc9SDouglas Gilbert 	}
7057f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7058773642d9SDouglas Gilbert 		if (sdebug_verbose)
7059773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7060773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7061c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7062c2248fc9SDouglas Gilbert 		goto check_cond;
7063c2248fc9SDouglas Gilbert 	}
7064f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7065c2248fc9SDouglas Gilbert 		u8 rem;
7066c2248fc9SDouglas Gilbert 		int j;
7067c2248fc9SDouglas Gilbert 
7068c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7069c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7070c2248fc9SDouglas Gilbert 			if (rem) {
7071c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7072c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7073c2248fc9SDouglas Gilbert 						break;
7074c2248fc9SDouglas Gilbert 				}
7075c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7076c2248fc9SDouglas Gilbert 				goto check_cond;
7077c2248fc9SDouglas Gilbert 			}
7078c2248fc9SDouglas Gilbert 		}
7079c2248fc9SDouglas Gilbert 	}
7080f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7081b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7082b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7083f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7084c2248fc9SDouglas Gilbert 		if (errsts)
7085c2248fc9SDouglas Gilbert 			goto check_cond;
7086c2248fc9SDouglas Gilbert 	}
7087c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
7088c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7089773642d9SDouglas Gilbert 		if (sdebug_verbose)
7090c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
7091c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
7092c2248fc9SDouglas Gilbert 				    "required");
7093c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
7094c2248fc9SDouglas Gilbert 		goto fini;
7095c2248fc9SDouglas Gilbert 	}
7096773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7097c2248fc9SDouglas Gilbert 		goto fini;
7098f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7099c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7100c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7101c2248fc9SDouglas Gilbert 	}
7102f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7103f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7104f66b8517SMartin Wilck 	else
7105f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7106c2248fc9SDouglas Gilbert 
7107c2248fc9SDouglas Gilbert fini:
710867da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7109f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
711075aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
711175aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
711280c49563SDouglas Gilbert 		/*
711375aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
711475aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
711575aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
711675aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
711780c49563SDouglas Gilbert 		 */
711880c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
71194f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
712080c49563SDouglas Gilbert 
71214f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7122f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
712380c49563SDouglas Gilbert 	} else
7124f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
712510bde980SDouglas Gilbert 				     sdebug_ndelay);
7126c2248fc9SDouglas Gilbert check_cond:
7127f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7128f46eb0e9SDouglas Gilbert err_out:
7129f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7130c2248fc9SDouglas Gilbert }
7131c2248fc9SDouglas Gilbert 
71329e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7133c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7134c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
71359e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
71369e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
71379e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
71389e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
71399e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
71409e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
71419e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7142185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7143cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
71449e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
71459e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7146cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7147cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
71489e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7149c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
71509e603ca0SFUJITA Tomonori 	.this_id =		7,
715165e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7152cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
71536bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
715450c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
71559e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7156c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
71579e603ca0SFUJITA Tomonori };
71589e603ca0SFUJITA Tomonori 
71591da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
71601da177e4SLinus Torvalds {
71611da177e4SLinus Torvalds 	int error = 0;
71621da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71631da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7164f46eb0e9SDouglas Gilbert 	int hprot;
71651da177e4SLinus Torvalds 
71661da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
71671da177e4SLinus Torvalds 
7168773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
71692a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
71704af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
71714af14d11SChristoph Hellwig 
71721da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
71731da177e4SLinus Torvalds 	if (NULL == hpnt) {
7174c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
71751da177e4SLinus Torvalds 		error = -ENODEV;
71761da177e4SLinus Torvalds 		return error;
71771da177e4SLinus Torvalds 	}
7178c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
71799b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7180c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7181c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7182c4837394SDouglas Gilbert 	}
7183c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
7184c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
7185c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
71861da177e4SLinus Torvalds 
71871da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
71881da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7189773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7190773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
71911da177e4SLinus Torvalds 	else
7192773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7193773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7194f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
71951da177e4SLinus Torvalds 
7196f46eb0e9SDouglas Gilbert 	hprot = 0;
7197c6a44287SMartin K. Petersen 
7198773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7199c6a44287SMartin K. Petersen 
72008475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7201f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7202773642d9SDouglas Gilbert 		if (sdebug_dix)
7203f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7204c6a44287SMartin K. Petersen 		break;
7205c6a44287SMartin K. Petersen 
72068475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7207f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7208773642d9SDouglas Gilbert 		if (sdebug_dix)
7209f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7210c6a44287SMartin K. Petersen 		break;
7211c6a44287SMartin K. Petersen 
72128475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7213f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7214773642d9SDouglas Gilbert 		if (sdebug_dix)
7215f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7216c6a44287SMartin K. Petersen 		break;
7217c6a44287SMartin K. Petersen 
7218c6a44287SMartin K. Petersen 	default:
7219773642d9SDouglas Gilbert 		if (sdebug_dix)
7220f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7221c6a44287SMartin K. Petersen 		break;
7222c6a44287SMartin K. Petersen 	}
7223c6a44287SMartin K. Petersen 
7224f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7225c6a44287SMartin K. Petersen 
7226f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7227c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7228f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7229f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7230f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7231f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7232f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7233f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7234f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7235c6a44287SMartin K. Petersen 
7236773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7237c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7238c6a44287SMartin K. Petersen 	else
7239c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7240c6a44287SMartin K. Petersen 
7241773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7242773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7243c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7244c4837394SDouglas Gilbert 		sdebug_statistics = true;
72451da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
72461da177e4SLinus Torvalds 	if (error) {
7247c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
72481da177e4SLinus Torvalds 		error = -ENODEV;
72491da177e4SLinus Torvalds 		scsi_host_put(hpnt);
725087c715dcSDouglas Gilbert 	} else {
72511da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
725287c715dcSDouglas Gilbert 	}
72531da177e4SLinus Torvalds 
72541da177e4SLinus Torvalds 	return error;
72551da177e4SLinus Torvalds }
72561da177e4SLinus Torvalds 
72571da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
72581da177e4SLinus Torvalds {
72591da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72608b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
72611da177e4SLinus Torvalds 
72621da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
72631da177e4SLinus Torvalds 
72641da177e4SLinus Torvalds 	if (!sdbg_host) {
7265c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
72661da177e4SLinus Torvalds 		return -ENODEV;
72671da177e4SLinus Torvalds 	}
72681da177e4SLinus Torvalds 
72691da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
72701da177e4SLinus Torvalds 
72718b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
72728b40228fSFUJITA Tomonori 				 dev_list) {
72731da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7274f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
72751da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
72761da177e4SLinus Torvalds 	}
72771da177e4SLinus Torvalds 
72781da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
72791da177e4SLinus Torvalds 	return 0;
72801da177e4SLinus Torvalds }
72811da177e4SLinus Torvalds 
72828dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
72838dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
72841da177e4SLinus Torvalds {
72858dea0d02SFUJITA Tomonori 	return 1;
72868dea0d02SFUJITA Tomonori }
72871da177e4SLinus Torvalds 
72888dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
72898dea0d02SFUJITA Tomonori 	.name = "pseudo",
72908dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
72918dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
72928dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
729382069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
72948dea0d02SFUJITA Tomonori };
7295