xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 600d9ead)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
51da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
61da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
71da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
81da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91da177e4SLinus Torvalds  *
10500d0d24SDouglas Gilbert  * Copyright (C) 2001 - 2021 Douglas Gilbert
111da177e4SLinus Torvalds  *
1230f67481SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
194a5fc1c6SDamien Le Moal #include <linux/align.h>
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/fs.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/proc_fs.h>
291da177e4SLinus Torvalds #include <linux/vmalloc.h>
301da177e4SLinus Torvalds #include <linux/moduleparam.h>
31852e034dSJens Axboe #include <linux/scatterlist.h>
321da177e4SLinus Torvalds #include <linux/blkdev.h>
33c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
34cbf67842SDouglas Gilbert #include <linux/spinlock.h>
35cbf67842SDouglas Gilbert #include <linux/interrupt.h>
36cbf67842SDouglas Gilbert #include <linux/atomic.h>
37cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3809ba24c1SDouglas Gilbert #include <linux/uuid.h>
396ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
401442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
410c4bc91dSDouglas Gilbert #include <linux/random.h>
4287c715dcSDouglas Gilbert #include <linux/xarray.h>
43ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
44c6a44287SMartin K. Petersen 
45c6a44287SMartin K. Petersen #include <net/checksum.h>
469ff26eefSFUJITA Tomonori 
4744d92694SMartin K. Petersen #include <asm/unaligned.h>
4844d92694SMartin K. Petersen 
499ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
521da177e4SLinus Torvalds #include <scsi/scsi_host.h>
531da177e4SLinus Torvalds #include <scsi/scsicam.h>
54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
62500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191"	/* format to fit INQUIRY revision field */
63500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520";
64cbf67842SDouglas Gilbert 
65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
661da177e4SLinus Torvalds 
676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
779447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
85500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
1014a5fc1c6SDamien Le Moal #define ATTEMPT_ACCESS_GAP 0x9
102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1031da177e4SLinus Torvalds 
1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1066f3cbf55SDouglas Gilbert 
1071da177e4SLinus Torvalds /* Default values for driver parameters */
1081da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1091da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1101da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1121da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1131da177e4SLinus Torvalds  */
1145b94e232SMartin K. Petersen #define DEF_ATO 1
1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
116c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1205b94e232SMartin K. Petersen #define DEF_DIF 0
1215b94e232SMartin K. Petersen #define DEF_DIX 0
12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1235b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1241da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1255b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1265b94e232SMartin K. Petersen #define DEF_GUARD 0
127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1285b94e232SMartin K. Petersen #define DEF_LBPU 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS 0
1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0
131be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
133cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1351da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1361da177e4SLinus Torvalds #define DEF_OPTS   0
13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
140b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false
142d986788bSMartin Pitt #define DEF_REMOVABLE false
143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
152c2248fc9SDouglas Gilbert #define DEF_STRICT 0
153c4837394SDouglas Gilbert #define DEF_STATISTICS false
154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1581da177e4SLinus Torvalds 
159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
163f0d1cf93SDouglas Gilbert 
164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
165b01f6f83SDouglas Gilbert 
166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
1777d5a129bSDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400	/* ignore */
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
179773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
180773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
181773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1827ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1837382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
185773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
186773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
187773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
188773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1897ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1907382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1917382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1923a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1933a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1941da177e4SLinus Torvalds 
195cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
196cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
197cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
198cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
200500d0d24SDouglas Gilbert #define SDEBUG_UA_POOCCUR 1	/* Power on occurred */
201500d0d24SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 2
202500d0d24SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 3
203500d0d24SDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 4
204500d0d24SDouglas Gilbert #define SDEBUG_UA_LUNS_CHANGED 5
205500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED 6	/* simulate firmware change */
206500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7
207500d0d24SDouglas Gilbert #define SDEBUG_NUM_UAS 8
208cbf67842SDouglas Gilbert 
209773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2101da177e4SLinus Torvalds  * sector on read commands: */
2111da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2131da177e4SLinus Torvalds 
214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
216c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
220c4837394SDouglas Gilbert  */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
223fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN  SDEBUG_CANQUEUE
224cbf67842SDouglas Gilbert 
225b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
226b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
227b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
228fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
229fd32119bSDouglas Gilbert #define F_D_UNKN		8
230b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
231b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
232b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
233b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
234b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
235b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
236b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
237b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
238b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
239b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
240fd32119bSDouglas Gilbert 
241b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
242fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24346f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
244fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2454f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
246fd32119bSDouglas Gilbert 
247fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
248fd32119bSDouglas Gilbert 
249b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
250fd32119bSDouglas Gilbert 
25187c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25287c715dcSDouglas Gilbert 
2531107c7b2SJohn Garry static struct kmem_cache *queued_cmd_cache;
2541107c7b2SJohn Garry 
2551107c7b2SJohn Garry #define TO_QUEUED_CMD(scmd)  ((void *)(scmd)->host_scribble)
2561107c7b2SJohn Garry #define ASSIGN_QUEUED_CMD(scmnd, qc) { (scmnd)->host_scribble = (void *) qc; }
2571107c7b2SJohn Garry 
25864e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25964e14eceSDamien Le Moal enum sdebug_z_type {
26035dbe2b9SDamien Le Moal 	ZBC_ZTYPE_CNV	= 0x1,
26135dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWR	= 0x2,
26235dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWP	= 0x3,
2634a5fc1c6SDamien Le Moal 	/* ZBC_ZTYPE_SOBR = 0x4, */
2644a5fc1c6SDamien Le Moal 	ZBC_ZTYPE_GAP	= 0x5,
26564e14eceSDamien Le Moal };
26664e14eceSDamien Le Moal 
267f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
268f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
269f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
270f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
271f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
272f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
273f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
274f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
275f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
276f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
277f0d1cf93SDouglas Gilbert };
278f0d1cf93SDouglas Gilbert 
279f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
28064e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
281f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
28264e14eceSDamien Le Moal 	bool z_non_seq_resource;
283f0d1cf93SDouglas Gilbert 	unsigned int z_size;
284f0d1cf93SDouglas Gilbert 	sector_t z_start;
285f0d1cf93SDouglas Gilbert 	sector_t z_wp;
286f0d1cf93SDouglas Gilbert };
287fd32119bSDouglas Gilbert 
288fd32119bSDouglas Gilbert struct sdebug_dev_info {
289fd32119bSDouglas Gilbert 	struct list_head dev_list;
290fd32119bSDouglas Gilbert 	unsigned int channel;
291fd32119bSDouglas Gilbert 	unsigned int target;
292fd32119bSDouglas Gilbert 	u64 lun;
293bf476433SChristoph Hellwig 	uuid_t lu_name;
294fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
295fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
296fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
297fd32119bSDouglas Gilbert 	bool used;
298f0d1cf93SDouglas Gilbert 
299f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
30064e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
3014a5fc1c6SDamien Le Moal 	unsigned int zcap;
302f0d1cf93SDouglas Gilbert 	unsigned int zsize;
303f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
304f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
305aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
3064a5fc1c6SDamien Le Moal 	unsigned int nr_seq_zones;
307f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
308f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
309f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
310f0d1cf93SDouglas Gilbert 	unsigned int max_open;
311fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
312f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
313fd32119bSDouglas Gilbert };
314fd32119bSDouglas Gilbert 
315fd32119bSDouglas Gilbert struct sdebug_host_info {
316fd32119bSDouglas Gilbert 	struct list_head host_list;
31787c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
318fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
319fd32119bSDouglas Gilbert 	struct device dev;
320fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
321fd32119bSDouglas Gilbert };
322fd32119bSDouglas Gilbert 
32387c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
32487c715dcSDouglas Gilbert struct sdeb_store_info {
32587c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
32687c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
32787c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
32887c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32987c715dcSDouglas Gilbert };
33087c715dcSDouglas Gilbert 
331785d6b7cSJohn Garry #define dev_to_sdebug_host(d)	\
332fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
333fd32119bSDouglas Gilbert 
334785d6b7cSJohn Garry #define shost_to_sdebug_host(shost)	\
335785d6b7cSJohn Garry 	dev_to_sdebug_host(shost->dma_dev)
336785d6b7cSJohn Garry 
33710bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3384a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
33910bde980SDouglas Gilbert 
340fd32119bSDouglas Gilbert struct sdebug_defer {
341fd32119bSDouglas Gilbert 	struct hrtimer hrt;
342fd32119bSDouglas Gilbert 	struct execute_work ew;
3434a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
344c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
345c10fa55fSJohn Garry 	int hc_idx;	/* hostwide tag index */
346c4837394SDouglas Gilbert 	int issuing_cpu;
3477382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34810bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
349fd32119bSDouglas Gilbert };
350fd32119bSDouglas Gilbert 
351fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
352c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
353c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
354c4837394SDouglas Gilbert 	 */
3551107c7b2SJohn Garry 	struct sdebug_defer sd_dp;
3561107c7b2SJohn Garry 	struct scsi_cmnd *scmd;
3571107c7b2SJohn Garry };
3581107c7b2SJohn Garry 
3591107c7b2SJohn Garry struct sdebug_scsi_cmd {
3601107c7b2SJohn Garry 	spinlock_t   lock;
361fd32119bSDouglas Gilbert };
362fd32119bSDouglas Gilbert 
363c4837394SDouglas Gilbert struct sdebug_queue {
3641107c7b2SJohn Garry 	struct sdebug_queued_cmd *qc_arr[SDEBUG_CANQUEUE];
365c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
366c4837394SDouglas Gilbert 	spinlock_t qc_lock;
367fd32119bSDouglas Gilbert };
368fd32119bSDouglas Gilbert 
369c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
370c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
371c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
372c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3733a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3744a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
375c4837394SDouglas Gilbert 
376fd32119bSDouglas Gilbert struct opcode_info_t {
377b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
378b01f6f83SDouglas Gilbert 				/* for terminating element */
379fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
380fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
381fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
382fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
383fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3849a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3859a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
386fd32119bSDouglas Gilbert };
387fd32119bSDouglas Gilbert 
388fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
389c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
390c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
391c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
392c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
393c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
394c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
395c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
396c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
397c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
398c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
399c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
400c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
401c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
40246f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
40346f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
404c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
405c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
406c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
407481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
408c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
409c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
410c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
411c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
412c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
413c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
414c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
415c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
416c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
417c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
418c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
419ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
420f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
421f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
422f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
423c2248fc9SDouglas Gilbert };
424c2248fc9SDouglas Gilbert 
425c4837394SDouglas Gilbert 
426c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
427c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
428c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
429c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
430c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
431c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
432c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
433c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
434c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
435c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
436c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
437c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
438ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
439c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
440c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
441c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
442c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
443c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
444c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
445c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
446fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
447c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
448c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
449c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
450c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
451c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
452c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
453c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
454f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
455f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
45646f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
457c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
458c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
459c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
46046f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
46146f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
462c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
463c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
464c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
465c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
466c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
467c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
468c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
469c2248fc9SDouglas Gilbert };
470c2248fc9SDouglas Gilbert 
47180c49563SDouglas Gilbert /*
47280c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
47380c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
47480c49563SDouglas Gilbert  * command completion, they can mask their return value with
47580c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
47680c49563SDouglas Gilbert  */
47780c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
47880c49563SDouglas Gilbert 
479c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
480c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
488481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
489c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
490c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
491c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
492c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
493c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
49438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
49538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
496c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
497c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
498c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
49938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
500acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
50180c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
502ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
503f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
504f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
505f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
506f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
507f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
508c2248fc9SDouglas Gilbert 
50987c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
51087c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
51187c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
51287c715dcSDouglas Gilbert static int sdebug_add_store(void);
51387c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
51487c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
51587c715dcSDouglas Gilbert 
5161107c7b2SJohn Garry static void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp);
5171107c7b2SJohn Garry 
51846f64e70SDouglas Gilbert /*
51946f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
52046f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
52146f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
52246f64e70SDouglas Gilbert  */
52346f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
524c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
525c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
526c2248fc9SDouglas Gilbert };
527c2248fc9SDouglas Gilbert 
52846f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
529c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
530c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
531c2248fc9SDouglas Gilbert };
532c2248fc9SDouglas Gilbert 
53346f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
53446f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
535b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
536c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
53746f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
538c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53946f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
540b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
541c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
542c2248fc9SDouglas Gilbert };
543c2248fc9SDouglas Gilbert 
54446f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
54546f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
54646f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
54746f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
54846f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
54946f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
55046f64e70SDouglas Gilbert 		   0, 0, 0} },
55146f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
55246f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55346f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
554c2248fc9SDouglas Gilbert };
555c2248fc9SDouglas Gilbert 
556c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
557c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
558c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
559c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
560c3e2fe92SDouglas Gilbert };
561c3e2fe92SDouglas Gilbert 
56246f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
563c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
564c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56546f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
566c2248fc9SDouglas Gilbert };
567c2248fc9SDouglas Gilbert 
56846f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
56946f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
570b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
571c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
572481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
573481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
574481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
575c2248fc9SDouglas Gilbert };
576c2248fc9SDouglas Gilbert 
57746f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
57838d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
579c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
58046f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
58138d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
582c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
58346f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
584c2248fc9SDouglas Gilbert };
585c2248fc9SDouglas Gilbert 
58646f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
58746f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
588c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58946f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
590c2248fc9SDouglas Gilbert };
591c2248fc9SDouglas Gilbert 
59246f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
593c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
594c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
595c2248fc9SDouglas Gilbert };
596c2248fc9SDouglas Gilbert 
59746f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
598c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
599c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
600c2248fc9SDouglas Gilbert };
601c2248fc9SDouglas Gilbert 
60280c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
6034f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
60480c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60580c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
60680c49563SDouglas Gilbert };
60780c49563SDouglas Gilbert 
608ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
609b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
610ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
611ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
612ed9f3e25SDouglas Gilbert };
613ed9f3e25SDouglas Gilbert 
614f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
615b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
616f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
617f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
618b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
619f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
620f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
621b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
622f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
623f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
624f0d1cf93SDouglas Gilbert };
625f0d1cf93SDouglas Gilbert 
626f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
627b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
628f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
629f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
630f0d1cf93SDouglas Gilbert };
631f0d1cf93SDouglas Gilbert 
632c2248fc9SDouglas Gilbert 
633c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
634c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
635c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
636ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
637c2248fc9SDouglas Gilbert /* 0 */
63846f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
639c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64046f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
641c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
642c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
643c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
64446f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
645c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
646c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
647c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
648c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64946f64e70SDouglas Gilbert /* 5 */
65046f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
65146f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
65246f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65346f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
65446f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
65546f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65646f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
657c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
658c2248fc9SDouglas Gilbert 	     0, 0, 0} },
65946f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
660c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
661c2248fc9SDouglas Gilbert 	     0, 0} },
66246f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
66346f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
66446f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
665c2248fc9SDouglas Gilbert /* 10 */
66646f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
66746f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
66846f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66980c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6704f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
671c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
67246f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
67346f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
67446f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67546f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
676481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
677481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
678481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
67946f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
68046f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
68146f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
68246f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
68346f64e70SDouglas Gilbert /* 15 */
684c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
685c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
686c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
687c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
688c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
689c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
69046f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
69146f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
69246f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
69346f64e70SDouglas Gilbert 	     0xff, 0xff} },
69446f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
69546f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
696c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
697c2248fc9SDouglas Gilbert 	     0} },
69846f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
69946f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
700c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
701c2248fc9SDouglas Gilbert 	     0} },
702c2248fc9SDouglas Gilbert /* 20 */
703f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
704f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
705c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
706c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
707c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
708c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
709c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
710c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
71146f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
712b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
71346f64e70SDouglas Gilbert /* 25 */
714acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
715acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
716acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
71746f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
71846f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
71946f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
72046f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7214f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
72280c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
723b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
72480c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
72546f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
726c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
727b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
728b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
729ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
730ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
731ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
732c2248fc9SDouglas Gilbert 
733ed9f3e25SDouglas Gilbert /* 30 */
734b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
735f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
736f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
737f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
738b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
739f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
740f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
741f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
742f0d1cf93SDouglas Gilbert /* sentinel */
743c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
744c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
745c2248fc9SDouglas Gilbert };
746c2248fc9SDouglas Gilbert 
747f19fe8f3SBart Van Assche static int sdebug_num_hosts;
74887c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
749773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7509b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
751c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7529267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
753773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
754773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
755773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
756773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
757773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
758773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
759c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
760773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
761773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
762c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
763d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
764d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
765cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
766c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
767773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
768773642d9SDouglas Gilbert static int sdebug_no_uld;
769773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
770773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
771773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
772773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
773773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
77486e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
775b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
776773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
777773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
778fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
779773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
780773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
781773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
782773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
783773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
784773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
785773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
786773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
787773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
788773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
789773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
79009ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7910c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
79287c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
793773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
794773642d9SDouglas Gilbert static bool sdebug_clustering;
795773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
796773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
797817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
7987109f370SDouglas Gilbert static bool sdebug_no_rwlock;
799773642d9SDouglas Gilbert static bool sdebug_verbose;
800f46eb0e9SDouglas Gilbert static bool have_dif_prot;
8014f2c8bf6SDouglas Gilbert static bool write_since_sync;
802c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
8039447b6ceSMartin K. Petersen static bool sdebug_wp;
8049267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
8059267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
8069267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
8071da177e4SLinus Torvalds 
808ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
809ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
810ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
811ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
812ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
813ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
814ad0c7775SDouglas Gilbert 
815c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8161da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8191da177e4SLinus Torvalds    may still need them */
8201da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8211da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8221da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8250aaa3fadSJohn Garry static DEFINE_MUTEX(sdebug_host_list_mutex);
8261da177e4SLinus Torvalds 
82787c715dcSDouglas Gilbert static struct xarray per_store_arr;
82887c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
82987c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
83087c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
83187c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8321da177e4SLinus Torvalds 
83344d92694SMartin K. Petersen static unsigned long map_size;
834cbf67842SDouglas Gilbert static int num_aborts;
835cbf67842SDouglas Gilbert static int num_dev_resets;
836cbf67842SDouglas Gilbert static int num_target_resets;
837cbf67842SDouglas Gilbert static int num_bus_resets;
838cbf67842SDouglas Gilbert static int num_host_resets;
839c6a44287SMartin K. Petersen static int dix_writes;
840c6a44287SMartin K. Petersen static int dix_reads;
841c6a44287SMartin K. Petersen static int dif_errors;
8421da177e4SLinus Torvalds 
843f0d1cf93SDouglas Gilbert /* ZBC global data */
84464e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
8454a5fc1c6SDamien Le Moal static int sdeb_zbc_zone_cap_mb;
84698e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
847380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
848aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
849f0d1cf93SDouglas Gilbert 
850c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
851c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
852c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
853fd32119bSDouglas Gilbert 
8541da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
85587c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
85687c715dcSDouglas Gilbert 
85787c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8581da177e4SLinus Torvalds 
859cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
860cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8651da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8661da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8671da177e4SLinus Torvalds };
8681da177e4SLinus Torvalds 
8691da177e4SLinus Torvalds static const int check_condition_result =
870464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8711da177e4SLinus Torvalds 
872c6a44287SMartin K. Petersen static const int illegal_condition_result =
873464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
874c6a44287SMartin K. Petersen 
875cbf67842SDouglas Gilbert static const int device_qfull_result =
8767d5a129bSDouglas Gilbert 	(DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
877cbf67842SDouglas Gilbert 
878ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
879ed9f3e25SDouglas Gilbert 
880fd32119bSDouglas Gilbert 
881760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
882760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
883760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
884760f3b03SDouglas Gilbert  */
885760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
886fd32119bSDouglas Gilbert {
887fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
888fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
889fd32119bSDouglas Gilbert }
890c65b1445SDouglas Gilbert 
89187c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
89287c715dcSDouglas Gilbert 			    unsigned long long lba)
89314faa944SAkinobu Mita {
89487c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
89514faa944SAkinobu Mita 
89687c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
89787c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
89887c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
89987c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
90087c715dcSDouglas Gilbert 	}
90187c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
90214faa944SAkinobu Mita }
90314faa944SAkinobu Mita 
90487c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
90587c715dcSDouglas Gilbert 				      sector_t sector)
90614faa944SAkinobu Mita {
90749413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
90814faa944SAkinobu Mita 
90987c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
91014faa944SAkinobu Mita }
91114faa944SAkinobu Mita 
9128dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9138dea0d02SFUJITA Tomonori {
9148dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9158dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9168dea0d02SFUJITA Tomonori 
9170aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
9188dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9198dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9208dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
921773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
922773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9238dea0d02SFUJITA Tomonori 		else
924773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
925773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
926f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9278dea0d02SFUJITA Tomonori 	}
9280aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
9298dea0d02SFUJITA Tomonori }
9308dea0d02SFUJITA Tomonori 
93122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
93222017ed2SDouglas Gilbert 
93322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
934fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
935fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
93622017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
93722017ed2SDouglas Gilbert {
93822017ed2SDouglas Gilbert 	unsigned char *sbuff;
93922017ed2SDouglas Gilbert 	u8 sks[4];
94022017ed2SDouglas Gilbert 	int sl, asc;
94122017ed2SDouglas Gilbert 
94222017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
94322017ed2SDouglas Gilbert 	if (!sbuff) {
94422017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
94522017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
94622017ed2SDouglas Gilbert 		return;
94722017ed2SDouglas Gilbert 	}
94822017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
94922017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
950f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
95122017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
95222017ed2SDouglas Gilbert 	sks[0] = 0x80;
95322017ed2SDouglas Gilbert 	if (c_d)
95422017ed2SDouglas Gilbert 		sks[0] |= 0x40;
95522017ed2SDouglas Gilbert 	if (in_bit >= 0) {
95622017ed2SDouglas Gilbert 		sks[0] |= 0x8;
95722017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
95822017ed2SDouglas Gilbert 	}
95922017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
960773642d9SDouglas Gilbert 	if (sdebug_dsense) {
96122017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
96222017ed2SDouglas Gilbert 		sbuff[7] = sl;
96322017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
96422017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
96522017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
96622017ed2SDouglas Gilbert 	} else
96722017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
968773642d9SDouglas Gilbert 	if (sdebug_verbose)
96922017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
97022017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
97122017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
97222017ed2SDouglas Gilbert }
97322017ed2SDouglas Gilbert 
974cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9758dea0d02SFUJITA Tomonori {
976f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
977cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
978cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
979cbf67842SDouglas Gilbert 		return;
980cbf67842SDouglas Gilbert 	}
981f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9828dea0d02SFUJITA Tomonori 
983f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9848dea0d02SFUJITA Tomonori 
985773642d9SDouglas Gilbert 	if (sdebug_verbose)
986cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
987cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
988cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9898dea0d02SFUJITA Tomonori }
9901da177e4SLinus Torvalds 
991fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
99222017ed2SDouglas Gilbert {
99322017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
99422017ed2SDouglas Gilbert }
99522017ed2SDouglas Gilbert 
9966f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9976f4e626fSNathan Chancellor 			    void __user *arg)
9981da177e4SLinus Torvalds {
999773642d9SDouglas Gilbert 	if (sdebug_verbose) {
1000cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
1001cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
1002cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
1003cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
1004cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
1005cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
1006cbf67842SDouglas Gilbert 				    __func__);
1007cbf67842SDouglas Gilbert 		else
1008cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
1009cbf67842SDouglas Gilbert 				    __func__, cmd);
10101da177e4SLinus Torvalds 	}
10111da177e4SLinus Torvalds 	return -EINVAL;
10121da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds 
10159b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10169b760fd8SDouglas Gilbert {
10179b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10189b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10199b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10209b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10229b760fd8SDouglas Gilbert 		break;
10239b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10249b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10259b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10279b760fd8SDouglas Gilbert 		break;
10289b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10299b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10309b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10329b760fd8SDouglas Gilbert 		break;
10339b760fd8SDouglas Gilbert 	case 16:
10349b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10359b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10369b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10379b760fd8SDouglas Gilbert 		break;
10389b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10399b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10409b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10419b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10429b760fd8SDouglas Gilbert 		break;
10439b760fd8SDouglas Gilbert 	default:
10449b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10459b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10469b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10479b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10489b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10499b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10509b760fd8SDouglas Gilbert 		break;
10519b760fd8SDouglas Gilbert 	}
10529b760fd8SDouglas Gilbert }
10539b760fd8SDouglas Gilbert 
10549b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10559b760fd8SDouglas Gilbert {
10569b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10579b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10589b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10599b760fd8SDouglas Gilbert 
10600aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
10619b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10629b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10639b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10649b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10659b760fd8SDouglas Gilbert 		}
10669b760fd8SDouglas Gilbert 	}
10670aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
10689b760fd8SDouglas Gilbert }
10699b760fd8SDouglas Gilbert 
107019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
107119c8ead7SEwan D. Milne {
107200f9d622SJohn Garry 	struct sdebug_host_info *sdhp = devip->sdbg_host;
107319c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
107419c8ead7SEwan D. Milne 
107519c8ead7SEwan D. Milne 	list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
107619c8ead7SEwan D. Milne 		if ((devip->sdbg_host == dp->sdbg_host) &&
107700f9d622SJohn Garry 		    (devip->target == dp->target)) {
107819c8ead7SEwan D. Milne 			clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
107919c8ead7SEwan D. Milne 		}
108019c8ead7SEwan D. Milne 	}
108119c8ead7SEwan D. Milne }
108219c8ead7SEwan D. Milne 
1083f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10841da177e4SLinus Torvalds {
1085cbf67842SDouglas Gilbert 	int k;
1086cbf67842SDouglas Gilbert 
1087cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1088cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1089cbf67842SDouglas Gilbert 		const char *cp = NULL;
1090cbf67842SDouglas Gilbert 
1091cbf67842SDouglas Gilbert 		switch (k) {
1092cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1093f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1094f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1095773642d9SDouglas Gilbert 			if (sdebug_verbose)
1096cbf67842SDouglas Gilbert 				cp = "power on reset";
1097cbf67842SDouglas Gilbert 			break;
1098500d0d24SDouglas Gilbert 		case SDEBUG_UA_POOCCUR:
1099500d0d24SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1100500d0d24SDouglas Gilbert 					POWER_ON_OCCURRED_ASCQ);
1101500d0d24SDouglas Gilbert 			if (sdebug_verbose)
1102500d0d24SDouglas Gilbert 				cp = "power on occurred";
1103500d0d24SDouglas Gilbert 			break;
1104cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1105f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1106f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1107773642d9SDouglas Gilbert 			if (sdebug_verbose)
1108cbf67842SDouglas Gilbert 				cp = "bus reset";
1109cbf67842SDouglas Gilbert 			break;
1110cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1111f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1112f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1113773642d9SDouglas Gilbert 			if (sdebug_verbose)
1114cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1115cbf67842SDouglas Gilbert 			break;
11160d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1117f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1118f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1119773642d9SDouglas Gilbert 			if (sdebug_verbose)
11200d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1121f49accf1SEwan D. Milne 			break;
1122acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1123f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1124b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1125b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1126773642d9SDouglas Gilbert 			if (sdebug_verbose)
1127acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1128acafd0b9SEwan D. Milne 			break;
1129acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1130f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1131acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1132acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1133773642d9SDouglas Gilbert 			if (sdebug_verbose)
1134acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1135acafd0b9SEwan D. Milne 			break;
113619c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
113719c8ead7SEwan D. Milne 			/*
113819c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
113919c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
114019c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
114119c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1142773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
114319c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
114419c8ead7SEwan D. Milne 			 */
1145773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
114619c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1147f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
114819c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
114919c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1150773642d9SDouglas Gilbert 			if (sdebug_verbose)
115119c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
115219c8ead7SEwan D. Milne 			break;
1153cbf67842SDouglas Gilbert 		default:
1154773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1155773642d9SDouglas Gilbert 			if (sdebug_verbose)
1156cbf67842SDouglas Gilbert 				cp = "unknown";
1157cbf67842SDouglas Gilbert 			break;
1158cbf67842SDouglas Gilbert 		}
1159cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1160773642d9SDouglas Gilbert 		if (sdebug_verbose)
1161f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1162cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1163cbf67842SDouglas Gilbert 				   my_name, cp);
11641da177e4SLinus Torvalds 		return check_condition_result;
11651da177e4SLinus Torvalds 	}
11661da177e4SLinus Torvalds 	return 0;
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds 
1169fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11701da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11711da177e4SLinus Torvalds 				int arr_len)
11721da177e4SLinus Torvalds {
117321a61829SFUJITA Tomonori 	int act_len;
1174ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11751da177e4SLinus Torvalds 
1176072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11771da177e4SLinus Torvalds 		return 0;
1178ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1179773642d9SDouglas Gilbert 		return DID_ERROR << 16;
118021a61829SFUJITA Tomonori 
118121a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
118221a61829SFUJITA Tomonori 				      arr, arr_len);
118342d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
118421a61829SFUJITA Tomonori 
11851da177e4SLinus Torvalds 	return 0;
11861da177e4SLinus Torvalds }
11871da177e4SLinus Torvalds 
1188fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1189fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1190fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1191fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1192fb0cc8d1SDouglas Gilbert  */
1193fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1194fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1195fb0cc8d1SDouglas Gilbert {
11969237f04eSDamien Le Moal 	unsigned int act_len, n;
1197ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1198fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1199fb0cc8d1SDouglas Gilbert 
1200fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1201fb0cc8d1SDouglas Gilbert 		return 0;
1202ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1203fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1204fb0cc8d1SDouglas Gilbert 
1205fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1206fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1207fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
120842d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
120942d387beSBart Van Assche 		 scsi_get_resid(scp));
12109237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
121136e07d7eSGeorge Kennedy 	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
1212fb0cc8d1SDouglas Gilbert 	return 0;
1213fb0cc8d1SDouglas Gilbert }
1214fb0cc8d1SDouglas Gilbert 
1215fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1216fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1217fb0cc8d1SDouglas Gilbert  */
12181da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
121921a61829SFUJITA Tomonori 			       int arr_len)
12201da177e4SLinus Torvalds {
122121a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12221da177e4SLinus Torvalds 		return 0;
1223ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12241da177e4SLinus Torvalds 		return -1;
122521a61829SFUJITA Tomonori 
122621a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 
1230e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1231e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12329b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12331b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12341b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12351b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12361b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12371da177e4SLinus Torvalds 
1238cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1239760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12405a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
124109ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1242bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12431da177e4SLinus Torvalds {
1244c65b1445SDouglas Gilbert 	int num, port_a;
1245c65b1445SDouglas Gilbert 	char b[32];
12461da177e4SLinus Torvalds 
1247c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12481da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12491da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12501da177e4SLinus Torvalds 	arr[1] = 0x1;
12511da177e4SLinus Torvalds 	arr[2] = 0x0;
1252e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1253e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12541da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12551da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12561da177e4SLinus Torvalds 	arr[3] = num;
12571da177e4SLinus Torvalds 	num += 4;
1258c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
125909ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
126009ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
126109ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
126209ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
126309ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
126409ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
126509ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
126609ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
126709ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
126809ba24c1SDouglas Gilbert 			num += 16;
126909ba24c1SDouglas Gilbert 		} else {
12701b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1271c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1272c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1273c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1274c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12751b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1276773642d9SDouglas Gilbert 			num += 8;
127709ba24c1SDouglas Gilbert 		}
1278c65b1445SDouglas Gilbert 		/* Target relative port number */
1279c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1280c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1281c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1282c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1283c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1284c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1285c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1286c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1287c65b1445SDouglas Gilbert 	}
12881b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1289c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1290c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1291c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1292c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12931b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1294773642d9SDouglas Gilbert 	num += 8;
12951b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12965a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12975a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12985a09e398SHannes Reinecke 	arr[num++] = 0x0;
12995a09e398SHannes Reinecke 	arr[num++] = 0x4;
13005a09e398SHannes Reinecke 	arr[num++] = 0;
13015a09e398SHannes Reinecke 	arr[num++] = 0;
1302773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1303773642d9SDouglas Gilbert 	num += 2;
13041b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1305c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1306c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1307c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1308c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
13091b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1310773642d9SDouglas Gilbert 	num += 8;
1311c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1312c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1313c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1314c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1315c65b1445SDouglas Gilbert 	arr[num++] = 24;
13161b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1317c65b1445SDouglas Gilbert 	num += 12;
1318c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1319c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1320c65b1445SDouglas Gilbert 	num += 8;
1321c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1322c65b1445SDouglas Gilbert 	num += 4;
1323c65b1445SDouglas Gilbert 	return num;
1324c65b1445SDouglas Gilbert }
1325c65b1445SDouglas Gilbert 
1326c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1327c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1328c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1329c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1330c65b1445SDouglas Gilbert };
1331c65b1445SDouglas Gilbert 
1332cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1333760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1334c65b1445SDouglas Gilbert {
1335c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1336c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1337c65b1445SDouglas Gilbert }
1338c65b1445SDouglas Gilbert 
1339cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1340760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1341c65b1445SDouglas Gilbert {
1342c65b1445SDouglas Gilbert 	int num = 0;
1343c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1344c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1345c65b1445SDouglas Gilbert 	int plen, olen;
1346c65b1445SDouglas Gilbert 
1347c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1348c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1349c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1350c65b1445SDouglas Gilbert 	olen = strlen(na1);
1351c65b1445SDouglas Gilbert 	plen = olen + 1;
1352c65b1445SDouglas Gilbert 	if (plen % 4)
1353c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1354c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1355c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1356c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1357c65b1445SDouglas Gilbert 	num += plen;
1358c65b1445SDouglas Gilbert 
1359c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1360c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1361c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1362c65b1445SDouglas Gilbert 	olen = strlen(na2);
1363c65b1445SDouglas Gilbert 	plen = olen + 1;
1364c65b1445SDouglas Gilbert 	if (plen % 4)
1365c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1366c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1367c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1368c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1369c65b1445SDouglas Gilbert 	num += plen;
1370c65b1445SDouglas Gilbert 
1371c65b1445SDouglas Gilbert 	return num;
1372c65b1445SDouglas Gilbert }
1373c65b1445SDouglas Gilbert 
1374c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1375760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1376c65b1445SDouglas Gilbert {
1377c65b1445SDouglas Gilbert 	int num = 0;
1378c65b1445SDouglas Gilbert 	int port_a, port_b;
1379c65b1445SDouglas Gilbert 
1380c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1381c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1385c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1386c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1387c65b1445SDouglas Gilbert 	num += 6;
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1389c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1390c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1393c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1394c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13951b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1396773642d9SDouglas Gilbert 	num += 8;
1397c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1398c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1399c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1400c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1401c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1402c65b1445SDouglas Gilbert 	num += 6;
1403c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1404c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1405c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1406c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1407c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1408c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1409c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
14101b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1411773642d9SDouglas Gilbert 	num += 8;
1412c65b1445SDouglas Gilbert 
1413c65b1445SDouglas Gilbert 	return num;
1414c65b1445SDouglas Gilbert }
1415c65b1445SDouglas Gilbert 
1416c65b1445SDouglas Gilbert 
1417c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1418c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1419c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1420c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1421c65b1445SDouglas Gilbert '1','2','3','4',
1422c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1423c65b1445SDouglas Gilbert 0xec,0,0,0,
1424c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1425c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1426c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1427c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1428c65b1445SDouglas Gilbert 0x53,0x41,
1429c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1430c65b1445SDouglas Gilbert 0x20,0x20,
1431c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1432c65b1445SDouglas Gilbert 0x10,0x80,
1433c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1434c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1435c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1437c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1438c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1441c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1442c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1443c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1444c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1445c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1446c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1448c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1449c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1450c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1451c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1452c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1453c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1454c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1455c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1456c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1457c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1458c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1459c65b1445SDouglas Gilbert };
1460c65b1445SDouglas Gilbert 
1461cbf67842SDouglas Gilbert /* ATA Information VPD page */
1462760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1463c65b1445SDouglas Gilbert {
1464c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1465c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1466c65b1445SDouglas Gilbert }
1467c65b1445SDouglas Gilbert 
1468c65b1445SDouglas Gilbert 
1469c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14701e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14711e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14721e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14731e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1474c65b1445SDouglas Gilbert };
1475c65b1445SDouglas Gilbert 
1476cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1477760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1478c65b1445SDouglas Gilbert {
1479ea61fca5SMartin K. Petersen 	unsigned int gran;
1480ea61fca5SMartin K. Petersen 
1481c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1482e308b3d1SMartin K. Petersen 
1483e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
148486e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
148586e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
148686e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
148786e6828aSLukas Herbolt 	else
1488773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1489773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1490e308b3d1SMartin K. Petersen 
1491e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1492773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1493773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
149444d92694SMartin K. Petersen 
1495e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1496773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1497e308b3d1SMartin K. Petersen 
1498773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1499e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1500773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1501e308b3d1SMartin K. Petersen 
1502e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1503773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
150444d92694SMartin K. Petersen 	}
150544d92694SMartin K. Petersen 
1506e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1507773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1508773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
150944d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
151044d92694SMartin K. Petersen 	}
151144d92694SMartin K. Petersen 
1512e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1513773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
15146014759cSMartin K. Petersen 
15155b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1516773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15175b94e232SMartin K. Petersen 
15185b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
15191da177e4SLinus Torvalds }
15201da177e4SLinus Torvalds 
15211e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
152264e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1523eac6e8e4SMatthew Wilcox {
1524eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1525eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15261e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15271e49f785SDouglas Gilbert 	arr[2] = 0;
15281e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
152964e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
153064e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1531eac6e8e4SMatthew Wilcox 
1532eac6e8e4SMatthew Wilcox 	return 0x3c;
1533eac6e8e4SMatthew Wilcox }
15341da177e4SLinus Torvalds 
1535760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1536760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15376014759cSMartin K. Petersen {
15383f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15396014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1540773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15416014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1542773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15436014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1544773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15455b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1546760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1547760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1548760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1549760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1550760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15513f0bc3b3SMartin K. Petersen 	return 0x4;
15526014759cSMartin K. Petersen }
15536014759cSMartin K. Petersen 
1554d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1555f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1556d36da305SDouglas Gilbert {
1557d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1558d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1559d36da305SDouglas Gilbert 	/*
1560d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1561d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1562f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1563f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1564d36da305SDouglas Gilbert 	 */
1565d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1566d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
156764e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1568f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1569f0d1cf93SDouglas Gilbert 	else
1570d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
15714a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize) {
15724a5fc1c6SDamien Le Moal 		arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET;
15734a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, &arr[20]);
15744a5fc1c6SDamien Le Moal 	} else {
15754a5fc1c6SDamien Le Moal 		arr[19] = 0;
15764a5fc1c6SDamien Le Moal 	}
1577d36da305SDouglas Gilbert 	return 0x3c;
1578d36da305SDouglas Gilbert }
1579d36da305SDouglas Gilbert 
15801da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1581c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15821da177e4SLinus Torvalds 
1583c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15841da177e4SLinus Torvalds {
15851da177e4SLinus Torvalds 	unsigned char pq_pdt;
15865a09e398SHannes Reinecke 	unsigned char *arr;
158701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
158836e07d7eSGeorge Kennedy 	u32 alloc_len, n;
158936e07d7eSGeorge Kennedy 	int ret;
1590d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15911da177e4SLinus Torvalds 
1592773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15936f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15946f3cbf55SDouglas Gilbert 	if (! arr)
15956f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1596760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
159764e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1598d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1599b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1600c2248fc9SDouglas Gilbert 	if (have_wlun)
1601b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1602b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1603b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1604c65b1445SDouglas Gilbert 	else
1605773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
16061da177e4SLinus Torvalds 	arr[0] = pq_pdt;
16071da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
160822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
16095a09e398SHannes Reinecke 		kfree(arr);
16101da177e4SLinus Torvalds 		return check_condition_result;
16111da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
161236e07d7eSGeorge Kennedy 		int lu_id_num, port_group_id, target_dev_id;
161336e07d7eSGeorge Kennedy 		u32 len;
1614c65b1445SDouglas Gilbert 		char lu_id_str[6];
1615c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
16161da177e4SLinus Torvalds 
16175a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16185a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1619b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
162023183910SDouglas Gilbert 			host_no = 0;
1621c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1622c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1623c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1624c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1625c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16261da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1627c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1628c65b1445SDouglas Gilbert 			n = 4;
1629c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1630c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1631c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1632c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1633c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1634c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1635c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1636c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1637d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1638c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1639760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1640760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1641d36da305SDouglas Gilbert 				if (is_disk)
1642d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
164364e14eceSDamien Le Moal 				if (is_zbc)
1644d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1645760f3b03SDouglas Gilbert 			}
1646c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16471da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1648c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16491da177e4SLinus Torvalds 			arr[3] = len;
1650c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16511da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1652c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1653760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16545a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
165509ba24c1SDouglas Gilbert 						lu_id_str, len,
165609ba24c1SDouglas Gilbert 						&devip->lu_name);
1657c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1658c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1659760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1660c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1661c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1662760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1663c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1664c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1665c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16668475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1667c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1668760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1669c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1670c6a44287SMartin K. Petersen 			else
1671c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1672c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1673c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1674c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1675c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1676c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1677c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1678c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1679c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1680c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1681c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1682760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1683d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1684c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1685760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1686773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1687d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1688c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1689760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1690d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1691eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
169264e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1693760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16946014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1695760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1696d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1697d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1698f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16991da177e4SLinus Torvalds 		} else {
170022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
17015a09e398SHannes Reinecke 			kfree(arr);
17021da177e4SLinus Torvalds 			return check_condition_result;
17031da177e4SLinus Torvalds 		}
170436e07d7eSGeorge Kennedy 		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
17055a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
170636e07d7eSGeorge Kennedy 			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
17075a09e398SHannes Reinecke 		kfree(arr);
17085a09e398SHannes Reinecke 		return ret;
17091da177e4SLinus Torvalds 	}
17101da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1711773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1712773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
17131da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
17141da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1715f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1716b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
171770bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1718c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17191da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1720c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1721e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1722e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1723e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17249b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17259b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17261da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1727760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1728760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1729c65b1445SDouglas Gilbert 	n = 62;
1730760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1731760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1732760f3b03SDouglas Gilbert 		n += 2;
1733760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1734760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1735760f3b03SDouglas Gilbert 		n += 2;
1736d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1737d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1738d36da305SDouglas Gilbert 		n += 2;
17391da177e4SLinus Torvalds 	}
1740760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17415a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
174236e07d7eSGeorge Kennedy 			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17435a09e398SHannes Reinecke 	kfree(arr);
17445a09e398SHannes Reinecke 	return ret;
17451da177e4SLinus Torvalds }
17461da177e4SLinus Torvalds 
174784905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1748fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1749fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1750fd32119bSDouglas Gilbert 
17511da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17521da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17531da177e4SLinus Torvalds {
175401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
175584905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
175684905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
175736e07d7eSGeorge Kennedy 	u32 alloc_len = cmd[4];
175836e07d7eSGeorge Kennedy 	u32 len = 18;
175984905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17601da177e4SLinus Torvalds 
1761c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
176284905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
176384905d34SDouglas Gilbert 		if (dsense) {
176484905d34SDouglas Gilbert 			arr[0] = 0x72;
176584905d34SDouglas Gilbert 			arr[1] = NOT_READY;
176684905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
176784905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
176884905d34SDouglas Gilbert 			len = 8;
176984905d34SDouglas Gilbert 		} else {
177084905d34SDouglas Gilbert 			arr[0] = 0x70;
177184905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
177284905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
177384905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
177484905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
177584905d34SDouglas Gilbert 		}
177684905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
177784905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1778c2248fc9SDouglas Gilbert 		if (dsense) {
1779c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1780c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1781c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
178284905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1783c2248fc9SDouglas Gilbert 			len = 8;
1784c65b1445SDouglas Gilbert 		} else {
1785c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1786c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1787c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1788c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
178984905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1790c65b1445SDouglas Gilbert 		}
179184905d34SDouglas Gilbert 	} else {	/* nothing to report */
1792c2248fc9SDouglas Gilbert 		if (dsense) {
1793c2248fc9SDouglas Gilbert 			len = 8;
179484905d34SDouglas Gilbert 			memset(arr, 0, len);
179584905d34SDouglas Gilbert 			arr[0] = 0x72;
1796c2248fc9SDouglas Gilbert 		} else {
179784905d34SDouglas Gilbert 			memset(arr, 0, len);
1798c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1799c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1800c2248fc9SDouglas Gilbert 		}
1801c65b1445SDouglas Gilbert 	}
180236e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
18031da177e4SLinus Torvalds }
18041da177e4SLinus Torvalds 
1805fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1806c65b1445SDouglas Gilbert {
180701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1808fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
18094f2c8bf6SDouglas Gilbert 	bool changing;
1810c65b1445SDouglas Gilbert 
1811c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1812c65b1445SDouglas Gilbert 	if (power_cond) {
181322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1814c65b1445SDouglas Gilbert 		return check_condition_result;
1815c65b1445SDouglas Gilbert 	}
1816fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1817fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1818fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1819fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1820fc13638aSDouglas Gilbert 
1821fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1822fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1823fc13638aSDouglas Gilbert 
1824fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1825fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1826fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1827fc13638aSDouglas Gilbert 				stopped_state = 0;
1828fc13638aSDouglas Gilbert 			}
1829fc13638aSDouglas Gilbert 		}
1830fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1831fc13638aSDouglas Gilbert 			if (want_stop) {
1832fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1833fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1834fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1835fc13638aSDouglas Gilbert 				return check_condition_result;
1836fc13638aSDouglas Gilbert 			}
1837fc13638aSDouglas Gilbert 		}
1838fc13638aSDouglas Gilbert 	}
1839fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1840fc13638aSDouglas Gilbert 	if (changing)
1841fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1842fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18434f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18444f2c8bf6SDouglas Gilbert 	else
18454f2c8bf6SDouglas Gilbert 		return 0;
1846c65b1445SDouglas Gilbert }
1847c65b1445SDouglas Gilbert 
184828898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
184928898873SFUJITA Tomonori {
1850773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1851773642d9SDouglas Gilbert 
1852773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1853773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1854773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
185528898873SFUJITA Tomonori 	else
185628898873SFUJITA Tomonori 		return sdebug_store_sectors;
185728898873SFUJITA Tomonori }
185828898873SFUJITA Tomonori 
18591da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18601da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18611da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18621da177e4SLinus Torvalds {
18631da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1864c65b1445SDouglas Gilbert 	unsigned int capac;
18651da177e4SLinus Torvalds 
1866c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
186728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18681da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1869c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1870c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1871773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1872773642d9SDouglas Gilbert 	} else
1873773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1874773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18751da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18761da177e4SLinus Torvalds }
18771da177e4SLinus Torvalds 
1878c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1879c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1880c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1881c65b1445SDouglas Gilbert {
188201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1883c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18844e3ace00SYe Bin 	u32 alloc_len;
1885c65b1445SDouglas Gilbert 
1886773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1887c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
188828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1889c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1890773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1891773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1892773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1893773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
189444d92694SMartin K. Petersen 
1895be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18965b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1897760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1898760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1899760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1900760f3b03SDouglas Gilbert 		 */
1901760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1902760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1903be1dd78dSEric Sandeen 	}
190444d92694SMartin K. Petersen 
1905ecb8c258SBart Van Assche 	/*
1906ecb8c258SBart Van Assche 	 * Since the scsi_debug READ CAPACITY implementation always reports the
1907ecb8c258SBart Van Assche 	 * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices.
1908ecb8c258SBart Van Assche 	 */
1909ecb8c258SBart Van Assche 	if (devip->zmodel == BLK_ZONED_HM)
1910ecb8c258SBart Van Assche 		arr[12] |= 1 << 4;
1911ecb8c258SBart Van Assche 
1912773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1913c6a44287SMartin K. Petersen 
1914760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1915773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1916c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1917c6a44287SMartin K. Petersen 	}
1918c6a44287SMartin K. Petersen 
1919c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
19204e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1921c65b1445SDouglas Gilbert }
1922c65b1445SDouglas Gilbert 
19235a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19245a09e398SHannes Reinecke 
19255a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19265a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19275a09e398SHannes Reinecke {
192801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19295a09e398SHannes Reinecke 	unsigned char *arr;
19305a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19315a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1932f347c268SYe Bin 	u32 alen, n, rlen;
1933f347c268SYe Bin 	int ret;
19345a09e398SHannes Reinecke 
1935773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19366f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19376f3cbf55SDouglas Gilbert 	if (! arr)
19386f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19395a09e398SHannes Reinecke 	/*
19405a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19415a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19425a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19435a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19445a09e398SHannes Reinecke 	 */
19455a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19465a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19475a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19485a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19495a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19505a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19515a09e398SHannes Reinecke 
19525a09e398SHannes Reinecke 	/*
19535a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19545a09e398SHannes Reinecke 	 */
19555a09e398SHannes Reinecke 	n = 4;
1956b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19575a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19585a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19595a09e398SHannes Reinecke 	} else {
19605a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1961773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19625a09e398SHannes Reinecke 	}
1963773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1964773642d9SDouglas Gilbert 	n += 2;
19655a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19665a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19685a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19695a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19705a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1971773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1972773642d9SDouglas Gilbert 	n += 2;
19735a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19745a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1975773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1976773642d9SDouglas Gilbert 	n += 2;
19775a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19785a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19795a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19805a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19815a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19825a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1983773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1984773642d9SDouglas Gilbert 	n += 2;
19855a09e398SHannes Reinecke 
19865a09e398SHannes Reinecke 	rlen = n - 4;
1987773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19885a09e398SHannes Reinecke 
19895a09e398SHannes Reinecke 	/*
19905a09e398SHannes Reinecke 	 * Return the smallest value of either
19915a09e398SHannes Reinecke 	 * - The allocated length
19925a09e398SHannes Reinecke 	 * - The constructed command length
19935a09e398SHannes Reinecke 	 * - The maximum array size
19945a09e398SHannes Reinecke 	 */
1995f347c268SYe Bin 	rlen = min(alen, n);
19965a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1997f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19985a09e398SHannes Reinecke 	kfree(arr);
19995a09e398SHannes Reinecke 	return ret;
20005a09e398SHannes Reinecke }
20015a09e398SHannes Reinecke 
2002fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
2003fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
200438d5c833SDouglas Gilbert {
200538d5c833SDouglas Gilbert 	bool rctd;
200638d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
200738d5c833SDouglas Gilbert 	u16 req_sa, u;
200838d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
200938d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
201038d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
201138d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
201238d5c833SDouglas Gilbert 	u8 *arr;
201338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
201438d5c833SDouglas Gilbert 
201538d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
201638d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
201738d5c833SDouglas Gilbert 	req_opcode = cmd[3];
201838d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
201938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
20206d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
202138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
202238d5c833SDouglas Gilbert 		return check_condition_result;
202338d5c833SDouglas Gilbert 	}
202438d5c833SDouglas Gilbert 	if (alloc_len > 8192)
202538d5c833SDouglas Gilbert 		a_len = 8192;
202638d5c833SDouglas Gilbert 	else
202738d5c833SDouglas Gilbert 		a_len = alloc_len;
202899531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
202938d5c833SDouglas Gilbert 	if (NULL == arr) {
203038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
203138d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
203238d5c833SDouglas Gilbert 		return check_condition_result;
203338d5c833SDouglas Gilbert 	}
203438d5c833SDouglas Gilbert 	switch (reporting_opts) {
203538d5c833SDouglas Gilbert 	case 0:	/* all commands */
203638d5c833SDouglas Gilbert 		/* count number of commands */
203738d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
203838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
203938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
204038d5c833SDouglas Gilbert 				continue;
204138d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
204238d5c833SDouglas Gilbert 		}
204338d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
204438d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
204538d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
204638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
204738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
204838d5c833SDouglas Gilbert 				continue;
204938d5c833SDouglas Gilbert 			na = oip->num_attached;
205038d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
205138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
205238d5c833SDouglas Gilbert 			if (rctd)
205338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
205438d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
205538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
205638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
205738d5c833SDouglas Gilbert 			if (rctd)
205838d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
205938d5c833SDouglas Gilbert 			r_oip = oip;
206038d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
206138d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
206238d5c833SDouglas Gilbert 					continue;
206338d5c833SDouglas Gilbert 				offset += bump;
206438d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
206538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
206638d5c833SDouglas Gilbert 				if (rctd)
206738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
206838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
206938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
207038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
207138d5c833SDouglas Gilbert 						   arr + offset + 6);
207238d5c833SDouglas Gilbert 				if (rctd)
207338d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
207438d5c833SDouglas Gilbert 							   arr + offset + 8);
207538d5c833SDouglas Gilbert 			}
207638d5c833SDouglas Gilbert 			oip = r_oip;
207738d5c833SDouglas Gilbert 			offset += bump;
207838d5c833SDouglas Gilbert 		}
207938d5c833SDouglas Gilbert 		break;
208038d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
208138d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
208238d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
208338d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
208438d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
208538d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
208638d5c833SDouglas Gilbert 			supp = 1;
208738d5c833SDouglas Gilbert 			offset = 4;
208838d5c833SDouglas Gilbert 		} else {
208938d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
209038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
209138d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
209238d5c833SDouglas Gilbert 							     2, 2);
209338d5c833SDouglas Gilbert 					kfree(arr);
209438d5c833SDouglas Gilbert 					return check_condition_result;
209538d5c833SDouglas Gilbert 				}
209638d5c833SDouglas Gilbert 				req_sa = 0;
209738d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
209838d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
209938d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
210038d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
210138d5c833SDouglas Gilbert 				return check_condition_result;
210238d5c833SDouglas Gilbert 			}
210338d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
210438d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
210538d5c833SDouglas Gilbert 				supp = 3;
210638d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
210738d5c833SDouglas Gilbert 				na = oip->num_attached;
210838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
210938d5c833SDouglas Gilbert 				     ++k, ++oip) {
211038d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
211138d5c833SDouglas Gilbert 						break;
211238d5c833SDouglas Gilbert 				}
211338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
211438d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
211538d5c833SDouglas Gilbert 				na = oip->num_attached;
211638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
211738d5c833SDouglas Gilbert 				     ++k, ++oip) {
211838d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
211938d5c833SDouglas Gilbert 						break;
212038d5c833SDouglas Gilbert 				}
212138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
212238d5c833SDouglas Gilbert 			} else
212338d5c833SDouglas Gilbert 				supp = 3;
212438d5c833SDouglas Gilbert 			if (3 == supp) {
212538d5c833SDouglas Gilbert 				u = oip->len_mask[0];
212638d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
212738d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
212838d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
212938d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
213038d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
213138d5c833SDouglas Gilbert 				offset = 4 + u;
213238d5c833SDouglas Gilbert 			} else
213338d5c833SDouglas Gilbert 				offset = 4;
213438d5c833SDouglas Gilbert 		}
213538d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
213638d5c833SDouglas Gilbert 		if (rctd) {
213738d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
213838d5c833SDouglas Gilbert 			offset += 12;
213938d5c833SDouglas Gilbert 		}
214038d5c833SDouglas Gilbert 		break;
214138d5c833SDouglas Gilbert 	default:
214238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
214338d5c833SDouglas Gilbert 		kfree(arr);
214438d5c833SDouglas Gilbert 		return check_condition_result;
214538d5c833SDouglas Gilbert 	}
214638d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
214738d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
214838d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
214938d5c833SDouglas Gilbert 	kfree(arr);
215038d5c833SDouglas Gilbert 	return errsts;
215138d5c833SDouglas Gilbert }
215238d5c833SDouglas Gilbert 
2153fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2154fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
215538d5c833SDouglas Gilbert {
215638d5c833SDouglas Gilbert 	bool repd;
215738d5c833SDouglas Gilbert 	u32 alloc_len, len;
215838d5c833SDouglas Gilbert 	u8 arr[16];
215938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
216038d5c833SDouglas Gilbert 
216138d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
216238d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
216338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
216438d5c833SDouglas Gilbert 	if (alloc_len < 4) {
216538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
216638d5c833SDouglas Gilbert 		return check_condition_result;
216738d5c833SDouglas Gilbert 	}
216838d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
216938d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
217038d5c833SDouglas Gilbert 	if (repd) {
217138d5c833SDouglas Gilbert 		arr[3] = 0xc;
217238d5c833SDouglas Gilbert 		len = 16;
217338d5c833SDouglas Gilbert 	} else
217438d5c833SDouglas Gilbert 		len = 4;
217538d5c833SDouglas Gilbert 
217638d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
217738d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
217838d5c833SDouglas Gilbert }
217938d5c833SDouglas Gilbert 
21801da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21811da177e4SLinus Torvalds 
21821da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21831da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21841da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21851da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21861da177e4SLinus Torvalds 
21871da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21881da177e4SLinus Torvalds 	if (1 == pcontrol)
21891da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21901da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21911da177e4SLinus Torvalds }
21921da177e4SLinus Torvalds 
21931da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21941da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21951da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21961da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21971da177e4SLinus Torvalds 
21981da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21991da177e4SLinus Torvalds 	if (1 == pcontrol)
22001da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
22011da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
22021da177e4SLinus Torvalds }
22031da177e4SLinus Torvalds 
22041da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
22051da177e4SLinus Torvalds {       /* Format device page for mode_sense */
22061da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
22071da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
22081da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2211773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2212773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2213773642d9SDouglas Gilbert 	if (sdebug_removable)
22141da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
22151da177e4SLinus Torvalds 	if (1 == pcontrol)
22161da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
22171da177e4SLinus Torvalds 	return sizeof(format_pg);
22181da177e4SLinus Torvalds }
22191da177e4SLinus Torvalds 
2220fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2221fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2222fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2223fd32119bSDouglas Gilbert 
22241da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22251da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2226cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2227cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2228cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22291da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22301da177e4SLinus Torvalds 
2231773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2232cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22331da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22341da177e4SLinus Torvalds 	if (1 == pcontrol)
2235cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2236cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2237cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22381da177e4SLinus Torvalds 	return sizeof(caching_pg);
22391da177e4SLinus Torvalds }
22401da177e4SLinus Torvalds 
2241fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2242fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2243fd32119bSDouglas Gilbert 
22441da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22451da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2246c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2247c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2248c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22491da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22501da177e4SLinus Torvalds 
2251773642d9SDouglas Gilbert 	if (sdebug_dsense)
22521da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2253c65b1445SDouglas Gilbert 	else
2254c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2255c6a44287SMartin K. Petersen 
2256773642d9SDouglas Gilbert 	if (sdebug_ato)
2257c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2258c6a44287SMartin K. Petersen 
22591da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22601da177e4SLinus Torvalds 	if (1 == pcontrol)
2261c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2262c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2263c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22641da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22651da177e4SLinus Torvalds }
22661da177e4SLinus Torvalds 
2267c65b1445SDouglas Gilbert 
22681da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22691da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2270c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22711da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2272c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2273c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2274c65b1445SDouglas Gilbert 
22751da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22761da177e4SLinus Torvalds 	if (1 == pcontrol)
2277c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2278c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2279c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22801da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22811da177e4SLinus Torvalds }
22821da177e4SLinus Torvalds 
2283c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2284c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2285c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2286c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2287c65b1445SDouglas Gilbert 
2288c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2289c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2290c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2291c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2292c65b1445SDouglas Gilbert }
2293c65b1445SDouglas Gilbert 
2294c65b1445SDouglas Gilbert 
2295c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2296c65b1445SDouglas Gilbert 			      int target_dev_id)
2297c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2298c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2299c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2300773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2301773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2302c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2303c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2304c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2305c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2306773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2307773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2308c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2309c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2310c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2311c65b1445SDouglas Gilbert 		};
2312c65b1445SDouglas Gilbert 	int port_a, port_b;
2313c65b1445SDouglas Gilbert 
23141b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
23151b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
23161b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
23171b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2318c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2319c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2320c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2321773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2322773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2323c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2324c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2325c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2326c65b1445SDouglas Gilbert }
2327c65b1445SDouglas Gilbert 
2328c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2329c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2330c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2331c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2332c65b1445SDouglas Gilbert 		};
2333c65b1445SDouglas Gilbert 
2334c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2335c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2336c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2337c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2338c65b1445SDouglas Gilbert }
2339c65b1445SDouglas Gilbert 
23401da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23411da177e4SLinus Torvalds 
2342fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2343fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23441da177e4SLinus Torvalds {
234523183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23461da177e4SLinus Torvalds 	unsigned char dev_spec;
234736e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
234836e07d7eSGeorge Kennedy 	int target_dev_id;
2349c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23501da177e4SLinus Torvalds 	unsigned char *ap;
23511da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
235201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2353d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23541da177e4SLinus Torvalds 
2355760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23561da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23571da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23581da177e4SLinus Torvalds 	subpcode = cmd[3];
23591da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2360760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2361760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
236264e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2363d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
236423183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
236523183910SDouglas Gilbert 	else
236623183910SDouglas Gilbert 		bd_len = 0;
2367773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23681da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23691da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2370cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23711da177e4SLinus Torvalds 		return check_condition_result;
23721da177e4SLinus Torvalds 	}
2373c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2374c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2375d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2376d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2377b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23789447b6ceSMartin K. Petersen 		if (sdebug_wp)
23799447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23809447b6ceSMartin K. Petersen 	} else
238123183910SDouglas Gilbert 		dev_spec = 0x0;
23821da177e4SLinus Torvalds 	if (msense_6) {
23831da177e4SLinus Torvalds 		arr[2] = dev_spec;
238423183910SDouglas Gilbert 		arr[3] = bd_len;
23851da177e4SLinus Torvalds 		offset = 4;
23861da177e4SLinus Torvalds 	} else {
23871da177e4SLinus Torvalds 		arr[3] = dev_spec;
238823183910SDouglas Gilbert 		if (16 == bd_len)
238923183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
239023183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23911da177e4SLinus Torvalds 		offset = 8;
23921da177e4SLinus Torvalds 	}
23931da177e4SLinus Torvalds 	ap = arr + offset;
239428898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
239528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
239628898873SFUJITA Tomonori 
239723183910SDouglas Gilbert 	if (8 == bd_len) {
2398773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2399773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2400773642d9SDouglas Gilbert 		else
2401773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2402773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
240323183910SDouglas Gilbert 		offset += bd_len;
240423183910SDouglas Gilbert 		ap = arr + offset;
240523183910SDouglas Gilbert 	} else if (16 == bd_len) {
2406773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2407773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
240823183910SDouglas Gilbert 		offset += bd_len;
240923183910SDouglas Gilbert 		ap = arr + offset;
241023183910SDouglas Gilbert 	}
24111da177e4SLinus Torvalds 
2412c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2413c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
241422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24151da177e4SLinus Torvalds 		return check_condition_result;
24161da177e4SLinus Torvalds 	}
2417760f3b03SDouglas Gilbert 	bad_pcode = false;
2418760f3b03SDouglas Gilbert 
24191da177e4SLinus Torvalds 	switch (pcode) {
24201da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
24211da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
24221da177e4SLinus Torvalds 		offset += len;
24231da177e4SLinus Torvalds 		break;
24241da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
24251da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24261da177e4SLinus Torvalds 		offset += len;
24271da177e4SLinus Torvalds 		break;
24281da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2429760f3b03SDouglas Gilbert 		if (is_disk) {
24301da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24311da177e4SLinus Torvalds 			offset += len;
2432760f3b03SDouglas Gilbert 		} else
2433760f3b03SDouglas Gilbert 			bad_pcode = true;
24341da177e4SLinus Torvalds 		break;
24351da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2436d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24371da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24381da177e4SLinus Torvalds 			offset += len;
2439760f3b03SDouglas Gilbert 		} else
2440760f3b03SDouglas Gilbert 			bad_pcode = true;
24411da177e4SLinus Torvalds 		break;
24421da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24431da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24441da177e4SLinus Torvalds 		offset += len;
24451da177e4SLinus Torvalds 		break;
2446c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2447c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
244822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2449c65b1445SDouglas Gilbert 			return check_condition_result;
2450c65b1445SDouglas Gilbert 		}
2451c65b1445SDouglas Gilbert 		len = 0;
2452c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2453c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2454c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2455c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2456c65b1445SDouglas Gilbert 						  target_dev_id);
2457c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2458c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2459c65b1445SDouglas Gilbert 		offset += len;
2460c65b1445SDouglas Gilbert 		break;
24611da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24621da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24631da177e4SLinus Torvalds 		offset += len;
24641da177e4SLinus Torvalds 		break;
24651da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2466c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24671da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24681da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2469760f3b03SDouglas Gilbert 			if (is_disk) {
2470760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2471760f3b03SDouglas Gilbert 						      target);
2472760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2473760f3b03SDouglas Gilbert 						       target);
2474d36da305SDouglas Gilbert 			} else if (is_zbc) {
2475d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2476d36da305SDouglas Gilbert 						       target);
2477760f3b03SDouglas Gilbert 			}
24781da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2479c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2480c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2481c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2482c65b1445SDouglas Gilbert 						  target, target_dev_id);
2483c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2484c65b1445SDouglas Gilbert 			}
24851da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2486760f3b03SDouglas Gilbert 			offset += len;
2487c65b1445SDouglas Gilbert 		} else {
248822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2489c65b1445SDouglas Gilbert 			return check_condition_result;
2490c65b1445SDouglas Gilbert 		}
24911da177e4SLinus Torvalds 		break;
24921da177e4SLinus Torvalds 	default:
2493760f3b03SDouglas Gilbert 		bad_pcode = true;
2494760f3b03SDouglas Gilbert 		break;
2495760f3b03SDouglas Gilbert 	}
2496760f3b03SDouglas Gilbert 	if (bad_pcode) {
249722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24981da177e4SLinus Torvalds 		return check_condition_result;
24991da177e4SLinus Torvalds 	}
25001da177e4SLinus Torvalds 	if (msense_6)
25011da177e4SLinus Torvalds 		arr[0] = offset - 1;
2502773642d9SDouglas Gilbert 	else
2503773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
250436e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
25051da177e4SLinus Torvalds }
25061da177e4SLinus Torvalds 
2507c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2508c65b1445SDouglas Gilbert 
2509fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2510fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2511c65b1445SDouglas Gilbert {
2512c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2513c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2514c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
251501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2516c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2517c65b1445SDouglas Gilbert 
2518c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2519c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2520c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2521773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2522c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
252322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2524c65b1445SDouglas Gilbert 		return check_condition_result;
2525c65b1445SDouglas Gilbert 	}
2526c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2527c65b1445SDouglas Gilbert 	if (-1 == res)
2528773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2529773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2530cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2531cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2532cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2533773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2534773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2535e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2536e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
253722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2538c65b1445SDouglas Gilbert 		return check_condition_result;
2539c65b1445SDouglas Gilbert 	}
2540c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2541c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2542c65b1445SDouglas Gilbert 	if (ps) {
254322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2544c65b1445SDouglas Gilbert 		return check_condition_result;
2545c65b1445SDouglas Gilbert 	}
2546c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2547773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2548c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2549c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2550cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2551c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2552c65b1445SDouglas Gilbert 		return check_condition_result;
2553c65b1445SDouglas Gilbert 	}
2554c65b1445SDouglas Gilbert 	switch (mpage) {
2555cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2556cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2557cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2558cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2559cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2560cbf67842SDouglas Gilbert 		}
2561cbf67842SDouglas Gilbert 		break;
2562c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2563c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2564c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2565c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25669447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25679447b6ceSMartin K. Petersen 				sdebug_wp = true;
25689447b6ceSMartin K. Petersen 			else
25699447b6ceSMartin K. Petersen 				sdebug_wp = false;
2570773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2571cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2572c65b1445SDouglas Gilbert 		}
2573c65b1445SDouglas Gilbert 		break;
2574c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2575c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2576c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2577c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2578cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2579c65b1445SDouglas Gilbert 		}
2580c65b1445SDouglas Gilbert 		break;
2581c65b1445SDouglas Gilbert 	default:
2582c65b1445SDouglas Gilbert 		break;
2583c65b1445SDouglas Gilbert 	}
258422017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2585c65b1445SDouglas Gilbert 	return check_condition_result;
2586cbf67842SDouglas Gilbert set_mode_changed_ua:
2587cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2588cbf67842SDouglas Gilbert 	return 0;
2589c65b1445SDouglas Gilbert }
2590c65b1445SDouglas Gilbert 
2591c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2592c65b1445SDouglas Gilbert {
2593c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2594c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2595c65b1445SDouglas Gilbert 		};
2596c65b1445SDouglas Gilbert 
2597c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2598c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2599c65b1445SDouglas Gilbert }
2600c65b1445SDouglas Gilbert 
2601c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2602c65b1445SDouglas Gilbert {
2603c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2604c65b1445SDouglas Gilbert 		};
2605c65b1445SDouglas Gilbert 
2606c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2607c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2608c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2609c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2610c65b1445SDouglas Gilbert 	}
2611c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2612c65b1445SDouglas Gilbert }
2613c65b1445SDouglas Gilbert 
26140790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr)
26150790797aSDouglas Gilbert {
26160790797aSDouglas Gilbert 	unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
26170790797aSDouglas Gilbert 					 0x0, 40, 72, 0xff, 45, 18, 0, 0,
26180790797aSDouglas Gilbert 					 0x1, 0x0, 0x23, 0x8,
26190790797aSDouglas Gilbert 					 0x0, 55, 72, 35, 55, 45, 0, 0,
26200790797aSDouglas Gilbert 		};
26210790797aSDouglas Gilbert 
26220790797aSDouglas Gilbert 	memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
26230790797aSDouglas Gilbert 	return sizeof(env_rep_l_spg);
26240790797aSDouglas Gilbert }
26250790797aSDouglas Gilbert 
2626c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2627c65b1445SDouglas Gilbert 
2628c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2629c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2630c65b1445SDouglas Gilbert {
263136e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
263236e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2633c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
263401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2635c65b1445SDouglas Gilbert 
2636c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2637c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2638c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2639c65b1445SDouglas Gilbert 	if (ppc || sp) {
264022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2641c65b1445SDouglas Gilbert 		return check_condition_result;
2642c65b1445SDouglas Gilbert 	}
2643c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
264423183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2645773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2646c65b1445SDouglas Gilbert 	arr[0] = pcode;
264723183910SDouglas Gilbert 	if (0 == subpcode) {
2648c65b1445SDouglas Gilbert 		switch (pcode) {
2649c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2650c65b1445SDouglas Gilbert 			n = 4;
2651c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2652c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2653c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2654c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2655c65b1445SDouglas Gilbert 			break;
2656c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2657c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2658c65b1445SDouglas Gilbert 			break;
2659c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2660c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2661c65b1445SDouglas Gilbert 			break;
2662c65b1445SDouglas Gilbert 		default:
266322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2664c65b1445SDouglas Gilbert 			return check_condition_result;
2665c65b1445SDouglas Gilbert 		}
266623183910SDouglas Gilbert 	} else if (0xff == subpcode) {
266723183910SDouglas Gilbert 		arr[0] |= 0x40;
266823183910SDouglas Gilbert 		arr[1] = subpcode;
266923183910SDouglas Gilbert 		switch (pcode) {
267023183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
267123183910SDouglas Gilbert 			n = 4;
267223183910SDouglas Gilbert 			arr[n++] = 0x0;
267323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
267423183910SDouglas Gilbert 			arr[n++] = 0x0;
267523183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
267623183910SDouglas Gilbert 			arr[n++] = 0xd;
267723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26780790797aSDouglas Gilbert 			arr[n++] = 0xd;
26790790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26800790797aSDouglas Gilbert 			arr[n++] = 0xd;
26810790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0xd subpages */
268223183910SDouglas Gilbert 			arr[n++] = 0x2f;
268323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
26840790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26850790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0x2f subpages */
268623183910SDouglas Gilbert 			arr[3] = n - 4;
268723183910SDouglas Gilbert 			break;
268823183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
268923183910SDouglas Gilbert 			n = 4;
269023183910SDouglas Gilbert 			arr[n++] = 0xd;
269123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26920790797aSDouglas Gilbert 			arr[n++] = 0xd;
26930790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26940790797aSDouglas Gilbert 			arr[n++] = 0xd;
26950790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
269623183910SDouglas Gilbert 			arr[3] = n - 4;
269723183910SDouglas Gilbert 			break;
269823183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
269923183910SDouglas Gilbert 			n = 4;
270023183910SDouglas Gilbert 			arr[n++] = 0x2f;
270123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
27020790797aSDouglas Gilbert 			arr[n++] = 0x2f;
27030790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
270423183910SDouglas Gilbert 			arr[3] = n - 4;
270523183910SDouglas Gilbert 			break;
270623183910SDouglas Gilbert 		default:
270722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
270823183910SDouglas Gilbert 			return check_condition_result;
270923183910SDouglas Gilbert 		}
27100790797aSDouglas Gilbert 	} else if (subpcode > 0) {
27110790797aSDouglas Gilbert 		arr[0] |= 0x40;
27120790797aSDouglas Gilbert 		arr[1] = subpcode;
27130790797aSDouglas Gilbert 		if (pcode == 0xd && subpcode == 1)
27140790797aSDouglas Gilbert 			arr[3] = resp_env_rep_l_spg(arr + 4);
27150790797aSDouglas Gilbert 		else {
27160790797aSDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
27170790797aSDouglas Gilbert 			return check_condition_result;
27180790797aSDouglas Gilbert 		}
271923183910SDouglas Gilbert 	} else {
272022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
272123183910SDouglas Gilbert 		return check_condition_result;
272223183910SDouglas Gilbert 	}
272336e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2724c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
272536e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2726c65b1445SDouglas Gilbert }
2727c65b1445SDouglas Gilbert 
2728f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2729f0d1cf93SDouglas Gilbert {
2730f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2731f0d1cf93SDouglas Gilbert }
2732f0d1cf93SDouglas Gilbert 
2733f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2734f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2735f0d1cf93SDouglas Gilbert {
27364a5fc1c6SDamien Le Moal 	u32 zno = lba >> devip->zsize_shift;
27374a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp;
27384a5fc1c6SDamien Le Moal 
27394a5fc1c6SDamien Le Moal 	if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones)
27404a5fc1c6SDamien Le Moal 		return &devip->zstate[zno];
27414a5fc1c6SDamien Le Moal 
27424a5fc1c6SDamien Le Moal 	/*
27434a5fc1c6SDamien Le Moal 	 * If the zone capacity is less than the zone size, adjust for gap
27444a5fc1c6SDamien Le Moal 	 * zones.
27454a5fc1c6SDamien Le Moal 	 */
27464a5fc1c6SDamien Le Moal 	zno = 2 * zno - devip->nr_conv_zones;
27474a5fc1c6SDamien Le Moal 	WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones);
27484a5fc1c6SDamien Le Moal 	zsp = &devip->zstate[zno];
27494a5fc1c6SDamien Le Moal 	if (lba >= zsp->z_start + zsp->z_size)
27504a5fc1c6SDamien Le Moal 		zsp++;
27514a5fc1c6SDamien Le Moal 	WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size);
27524a5fc1c6SDamien Le Moal 	return zsp;
2753f0d1cf93SDouglas Gilbert }
2754f0d1cf93SDouglas Gilbert 
2755f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2756f0d1cf93SDouglas Gilbert {
275735dbe2b9SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_CNV;
2758f0d1cf93SDouglas Gilbert }
2759f0d1cf93SDouglas Gilbert 
27604a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp)
27614a5fc1c6SDamien Le Moal {
27624a5fc1c6SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_GAP;
27634a5fc1c6SDamien Le Moal }
27644a5fc1c6SDamien Le Moal 
27654a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp)
27664a5fc1c6SDamien Le Moal {
27674a5fc1c6SDamien Le Moal 	return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp);
27684a5fc1c6SDamien Le Moal }
27694a5fc1c6SDamien Le Moal 
2770f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2771f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2772f0d1cf93SDouglas Gilbert {
2773f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2774f0d1cf93SDouglas Gilbert 
27754a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2776f0d1cf93SDouglas Gilbert 		return;
2777f0d1cf93SDouglas Gilbert 
2778f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2779f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2780f0d1cf93SDouglas Gilbert 		return;
2781f0d1cf93SDouglas Gilbert 
2782f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2783f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2784f0d1cf93SDouglas Gilbert 	else
2785f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2786f0d1cf93SDouglas Gilbert 
2787f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2788f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2789f0d1cf93SDouglas Gilbert 	} else {
2790f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2791f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2792f0d1cf93SDouglas Gilbert 	}
2793f0d1cf93SDouglas Gilbert }
2794f0d1cf93SDouglas Gilbert 
2795f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2796f0d1cf93SDouglas Gilbert {
2797f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2798f0d1cf93SDouglas Gilbert 	unsigned int i;
2799f0d1cf93SDouglas Gilbert 
2800f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2801f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2802f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2803f0d1cf93SDouglas Gilbert 			return;
2804f0d1cf93SDouglas Gilbert 		}
2805f0d1cf93SDouglas Gilbert 	}
2806f0d1cf93SDouglas Gilbert }
2807f0d1cf93SDouglas Gilbert 
2808f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2809f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2810f0d1cf93SDouglas Gilbert {
2811f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2812f0d1cf93SDouglas Gilbert 
28134a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2814f0d1cf93SDouglas Gilbert 		return;
2815f0d1cf93SDouglas Gilbert 
2816f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2817f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2818f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2819f0d1cf93SDouglas Gilbert 		return;
2820f0d1cf93SDouglas Gilbert 
2821f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2822f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2823f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2824f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2825f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2826f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2827f0d1cf93SDouglas Gilbert 
2828f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2829f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2830f0d1cf93SDouglas Gilbert 	if (explicit) {
2831f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2832f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2833f0d1cf93SDouglas Gilbert 	} else {
2834f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2835f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2836f0d1cf93SDouglas Gilbert 	}
2837f0d1cf93SDouglas Gilbert }
2838f0d1cf93SDouglas Gilbert 
2839566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip,
2840566d3c57SDamien Le Moal 				     struct sdeb_zone_state *zsp)
2841566d3c57SDamien Le Moal {
2842566d3c57SDamien Le Moal 	switch (zsp->z_cond) {
2843566d3c57SDamien Le Moal 	case ZC2_IMPLICIT_OPEN:
2844566d3c57SDamien Le Moal 		devip->nr_imp_open--;
2845566d3c57SDamien Le Moal 		break;
2846566d3c57SDamien Le Moal 	case ZC3_EXPLICIT_OPEN:
2847566d3c57SDamien Le Moal 		devip->nr_exp_open--;
2848566d3c57SDamien Le Moal 		break;
2849566d3c57SDamien Le Moal 	default:
2850566d3c57SDamien Le Moal 		WARN_ONCE(true, "Invalid zone %llu condition %x\n",
2851566d3c57SDamien Le Moal 			  zsp->z_start, zsp->z_cond);
2852566d3c57SDamien Le Moal 		break;
2853566d3c57SDamien Le Moal 	}
2854566d3c57SDamien Le Moal 	zsp->z_cond = ZC5_FULL;
2855566d3c57SDamien Le Moal }
2856566d3c57SDamien Le Moal 
2857f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2858f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2859f0d1cf93SDouglas Gilbert {
2860f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
286164e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2862f0d1cf93SDouglas Gilbert 
28634a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2864f0d1cf93SDouglas Gilbert 		return;
2865f0d1cf93SDouglas Gilbert 
286635dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2867f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
286864e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2869566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
287064e14eceSDamien Le Moal 		return;
287164e14eceSDamien Le Moal 	}
287264e14eceSDamien Le Moal 
287364e14eceSDamien Le Moal 	while (num) {
287464e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
287564e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
287664e14eceSDamien Le Moal 
287764e14eceSDamien Le Moal 		end = lba + num;
287864e14eceSDamien Le Moal 		if (end >= zend) {
287964e14eceSDamien Le Moal 			n = zend - lba;
288064e14eceSDamien Le Moal 			zsp->z_wp = zend;
288164e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
288264e14eceSDamien Le Moal 			n = num;
288364e14eceSDamien Le Moal 			zsp->z_wp = end;
288464e14eceSDamien Le Moal 		} else {
288564e14eceSDamien Le Moal 			n = num;
288664e14eceSDamien Le Moal 		}
288764e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2888566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
288964e14eceSDamien Le Moal 
289064e14eceSDamien Le Moal 		num -= n;
289164e14eceSDamien Le Moal 		lba += n;
289264e14eceSDamien Le Moal 		if (num) {
289364e14eceSDamien Le Moal 			zsp++;
289464e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
289564e14eceSDamien Le Moal 		}
289664e14eceSDamien Le Moal 	}
2897f0d1cf93SDouglas Gilbert }
2898f0d1cf93SDouglas Gilbert 
2899f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
29009447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
29011da177e4SLinus Torvalds {
2902f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2903f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2904f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2905f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2906f0d1cf93SDouglas Gilbert 
2907f0d1cf93SDouglas Gilbert 	if (!write) {
290864e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
290964e14eceSDamien Le Moal 			return 0;
291064e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
29114a5fc1c6SDamien Le Moal 		if (zsp->z_type != zsp_end->z_type) {
2912f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2913f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2914f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2915f0d1cf93SDouglas Gilbert 			return check_condition_result;
2916f0d1cf93SDouglas Gilbert 		}
2917f0d1cf93SDouglas Gilbert 		return 0;
2918f0d1cf93SDouglas Gilbert 	}
2919f0d1cf93SDouglas Gilbert 
29204a5fc1c6SDamien Le Moal 	/* Writing into a gap zone is not allowed */
29214a5fc1c6SDamien Le Moal 	if (zbc_zone_is_gap(zsp)) {
29224a5fc1c6SDamien Le Moal 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE,
29234a5fc1c6SDamien Le Moal 				ATTEMPT_ACCESS_GAP);
29244a5fc1c6SDamien Le Moal 		return check_condition_result;
29254a5fc1c6SDamien Le Moal 	}
29264a5fc1c6SDamien Le Moal 
2927f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2928f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2929f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2930f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2931f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2932f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2933f0d1cf93SDouglas Gilbert 			return check_condition_result;
2934f0d1cf93SDouglas Gilbert 		}
2935f0d1cf93SDouglas Gilbert 		return 0;
2936f0d1cf93SDouglas Gilbert 	}
2937f0d1cf93SDouglas Gilbert 
293835dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2939f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2940f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2941f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2942f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2943f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2944f0d1cf93SDouglas Gilbert 			return check_condition_result;
2945f0d1cf93SDouglas Gilbert 		}
2946f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2947f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2948f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2949f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2950f0d1cf93SDouglas Gilbert 			return check_condition_result;
2951f0d1cf93SDouglas Gilbert 		}
2952f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2953f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2954f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2955f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2956f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2957f0d1cf93SDouglas Gilbert 			return check_condition_result;
2958f0d1cf93SDouglas Gilbert 		}
295964e14eceSDamien Le Moal 	}
2960f0d1cf93SDouglas Gilbert 
2961f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2962f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2963f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2964f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2965f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2966f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2967f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2968f0d1cf93SDouglas Gilbert 			return check_condition_result;
2969f0d1cf93SDouglas Gilbert 		}
2970f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2971f0d1cf93SDouglas Gilbert 	}
2972f0d1cf93SDouglas Gilbert 
2973f0d1cf93SDouglas Gilbert 	return 0;
2974f0d1cf93SDouglas Gilbert }
2975f0d1cf93SDouglas Gilbert 
2976f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2977f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2978f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2979f0d1cf93SDouglas Gilbert {
2980f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2981f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2982f0d1cf93SDouglas Gilbert 
2983c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
298422017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
29851da177e4SLinus Torvalds 		return check_condition_result;
29861da177e4SLinus Torvalds 	}
2987c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2988c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
298922017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2990cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2991c65b1445SDouglas Gilbert 		return check_condition_result;
2992c65b1445SDouglas Gilbert 	}
29939447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
29949447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29959447b6ceSMartin K. Petersen 		return check_condition_result;
29969447b6ceSMartin K. Petersen 	}
2997f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2998f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2999f0d1cf93SDouglas Gilbert 
300019789100SFUJITA Tomonori 	return 0;
300119789100SFUJITA Tomonori }
300219789100SFUJITA Tomonori 
3003b6ff8ca7SDouglas Gilbert /*
3004b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
3005b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
3006b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
3007b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
3008b6ff8ca7SDouglas Gilbert  */
3009b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
3010b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
301187c715dcSDouglas Gilbert {
3012b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
3013b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
3014b6ff8ca7SDouglas Gilbert 		return NULL;
3015b6ff8ca7SDouglas Gilbert 	}
3016b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
301787c715dcSDouglas Gilbert }
301887c715dcSDouglas Gilbert 
3019a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
302087c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
302187c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
302219789100SFUJITA Tomonori {
302319789100SFUJITA Tomonori 	int ret;
3024c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
3025a4517511SAkinobu Mita 	enum dma_data_direction dir;
302687c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
302787c715dcSDouglas Gilbert 	u8 *fsp;
302819789100SFUJITA Tomonori 
3029c2248fc9SDouglas Gilbert 	if (do_write) {
3030a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
30314f2c8bf6SDouglas Gilbert 		write_since_sync = true;
3032a4517511SAkinobu Mita 	} else {
3033a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
3034a4517511SAkinobu Mita 	}
3035a4517511SAkinobu Mita 
303687c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
3037a4517511SAkinobu Mita 		return 0;
303887c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
3039a4517511SAkinobu Mita 		return -1;
304087c715dcSDouglas Gilbert 	fsp = sip->storep;
304119789100SFUJITA Tomonori 
304219789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
304319789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
304419789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
304519789100SFUJITA Tomonori 
3046386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
304787c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
30480a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
3049773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
3050a4517511SAkinobu Mita 		return ret;
3051a4517511SAkinobu Mita 
3052a4517511SAkinobu Mita 	if (rest) {
3053386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
305487c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
30550a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
30560a7e69c7SDouglas Gilbert 			    do_write);
3057a4517511SAkinobu Mita 	}
305819789100SFUJITA Tomonori 
305919789100SFUJITA Tomonori 	return ret;
306019789100SFUJITA Tomonori }
306119789100SFUJITA Tomonori 
306287c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
306387c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
306487c715dcSDouglas Gilbert {
306587c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
306687c715dcSDouglas Gilbert 
306787c715dcSDouglas Gilbert 	if (!sdb->length)
306887c715dcSDouglas Gilbert 		return 0;
306987c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
307087c715dcSDouglas Gilbert 		return -1;
307187c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
307287c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
307387c715dcSDouglas Gilbert }
307487c715dcSDouglas Gilbert 
307587c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
307687c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
307738d5c833SDouglas Gilbert  * return false. */
307887c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
3079c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
308038d5c833SDouglas Gilbert {
308138d5c833SDouglas Gilbert 	bool res;
308238d5c833SDouglas Gilbert 	u64 block, rest = 0;
308338d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
3084773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
308587c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
308638d5c833SDouglas Gilbert 
308738d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
308838d5c833SDouglas Gilbert 	if (block + num > store_blks)
308938d5c833SDouglas Gilbert 		rest = block + num - store_blks;
309038d5c833SDouglas Gilbert 
309187c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
309238d5c833SDouglas Gilbert 	if (!res)
309338d5c833SDouglas Gilbert 		return res;
309438d5c833SDouglas Gilbert 	if (rest)
309587c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
309638d5c833SDouglas Gilbert 			     rest * lb_size);
309738d5c833SDouglas Gilbert 	if (!res)
309838d5c833SDouglas Gilbert 		return res;
3099c3e2fe92SDouglas Gilbert 	if (compare_only)
3100c3e2fe92SDouglas Gilbert 		return true;
310138d5c833SDouglas Gilbert 	arr += num * lb_size;
310287c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
310338d5c833SDouglas Gilbert 	if (rest)
310487c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
310538d5c833SDouglas Gilbert 	return res;
310638d5c833SDouglas Gilbert }
310738d5c833SDouglas Gilbert 
310851d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3109beb40ea4SAkinobu Mita {
311051d648afSAkinobu Mita 	__be16 csum;
3111beb40ea4SAkinobu Mita 
3112773642d9SDouglas Gilbert 	if (sdebug_guard)
311351d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
311451d648afSAkinobu Mita 	else
3115beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
311651d648afSAkinobu Mita 
3117beb40ea4SAkinobu Mita 	return csum;
3118beb40ea4SAkinobu Mita }
3119beb40ea4SAkinobu Mita 
31206ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3121beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3122beb40ea4SAkinobu Mita {
3123773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3124beb40ea4SAkinobu Mita 
3125beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3126c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3127beb40ea4SAkinobu Mita 			(unsigned long)sector,
3128beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3129beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3130beb40ea4SAkinobu Mita 		return 0x01;
3131beb40ea4SAkinobu Mita 	}
31328475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3133beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3134c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3135c1287970STomas Winkler 			(unsigned long)sector);
3136beb40ea4SAkinobu Mita 		return 0x03;
3137beb40ea4SAkinobu Mita 	}
31388475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3139beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3140c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3141c1287970STomas Winkler 			(unsigned long)sector);
3142beb40ea4SAkinobu Mita 		return 0x03;
3143beb40ea4SAkinobu Mita 	}
3144beb40ea4SAkinobu Mita 	return 0;
3145beb40ea4SAkinobu Mita }
3146beb40ea4SAkinobu Mita 
314787c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
314865f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3149c6a44287SMartin K. Petersen {
3150be4e11beSAkinobu Mita 	size_t resid;
3151c6a44287SMartin K. Petersen 	void *paddr;
315287c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3153b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
315487c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
315514faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3156be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3157c6a44287SMartin K. Petersen 
3158e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3159e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3160c6a44287SMartin K. Petersen 
316187c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
316287c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3163be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3164be4e11beSAkinobu Mita 
3165be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
316687c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
316787c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3168be4e11beSAkinobu Mita 		size_t rest = 0;
316914faa944SAkinobu Mita 
317014faa944SAkinobu Mita 		if (dif_store_end < start + len)
317114faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3172c6a44287SMartin K. Petersen 
3173be4e11beSAkinobu Mita 		paddr = miter.addr;
317414faa944SAkinobu Mita 
317565f72f2aSAkinobu Mita 		if (read)
317665f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
317765f72f2aSAkinobu Mita 		else
317865f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
317965f72f2aSAkinobu Mita 
318065f72f2aSAkinobu Mita 		if (rest) {
318165f72f2aSAkinobu Mita 			if (read)
318214faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
318365f72f2aSAkinobu Mita 			else
318465f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
318565f72f2aSAkinobu Mita 		}
3186c6a44287SMartin K. Petersen 
3187e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3188c6a44287SMartin K. Petersen 		resid -= len;
3189c6a44287SMartin K. Petersen 	}
3190be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3191bb8c063cSAkinobu Mita }
3192c6a44287SMartin K. Petersen 
319387c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3194bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3195bb8c063cSAkinobu Mita {
3196f7be6772SMartin K. Petersen 	int ret = 0;
3197bb8c063cSAkinobu Mita 	unsigned int i;
3198bb8c063cSAkinobu Mita 	sector_t sector;
319987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3200b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
320187c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3202bb8c063cSAkinobu Mita 
3203c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3204bb8c063cSAkinobu Mita 		sector = start_sec + i;
320587c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3206bb8c063cSAkinobu Mita 
320751d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3208bb8c063cSAkinobu Mita 			continue;
3209bb8c063cSAkinobu Mita 
3210f7be6772SMartin K. Petersen 		/*
3211f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3212f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3213f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3214f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3215f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3216f7be6772SMartin K. Petersen 		 */
3217f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3218f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3219f7be6772SMartin K. Petersen 					 sector, ei_lba);
3220bb8c063cSAkinobu Mita 			if (ret) {
3221bb8c063cSAkinobu Mita 				dif_errors++;
3222f7be6772SMartin K. Petersen 				break;
3223f7be6772SMartin K. Petersen 			}
3224bb8c063cSAkinobu Mita 		}
3225bb8c063cSAkinobu Mita 	}
3226bb8c063cSAkinobu Mita 
322787c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3228c6a44287SMartin K. Petersen 	dix_reads++;
3229c6a44287SMartin K. Petersen 
3230f7be6772SMartin K. Petersen 	return ret;
3231c6a44287SMartin K. Petersen }
3232c6a44287SMartin K. Petersen 
32337109f370SDouglas Gilbert static inline void
32347109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip)
32357109f370SDouglas Gilbert {
3236e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3237e9c47801SDamien Le Moal 		if (sip)
3238e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3239e9c47801SDamien Le Moal 		else
3240e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3241e9c47801SDamien Le Moal 	} else {
32427109f370SDouglas Gilbert 		if (sip)
32437109f370SDouglas Gilbert 			read_lock(&sip->macc_lck);
32447109f370SDouglas Gilbert 		else
32457109f370SDouglas Gilbert 			read_lock(&sdeb_fake_rw_lck);
32467109f370SDouglas Gilbert 	}
3247e9c47801SDamien Le Moal }
32487109f370SDouglas Gilbert 
32497109f370SDouglas Gilbert static inline void
32507109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip)
32517109f370SDouglas Gilbert {
3252e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3253e9c47801SDamien Le Moal 		if (sip)
3254e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3255e9c47801SDamien Le Moal 		else
3256e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3257e9c47801SDamien Le Moal 	} else {
32587109f370SDouglas Gilbert 		if (sip)
32597109f370SDouglas Gilbert 			read_unlock(&sip->macc_lck);
32607109f370SDouglas Gilbert 		else
32617109f370SDouglas Gilbert 			read_unlock(&sdeb_fake_rw_lck);
32627109f370SDouglas Gilbert 	}
3263e9c47801SDamien Le Moal }
32647109f370SDouglas Gilbert 
32657109f370SDouglas Gilbert static inline void
32667109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip)
32677109f370SDouglas Gilbert {
3268e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3269e9c47801SDamien Le Moal 		if (sip)
3270e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3271e9c47801SDamien Le Moal 		else
3272e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3273e9c47801SDamien Le Moal 	} else {
32747109f370SDouglas Gilbert 		if (sip)
32757109f370SDouglas Gilbert 			write_lock(&sip->macc_lck);
32767109f370SDouglas Gilbert 		else
32777109f370SDouglas Gilbert 			write_lock(&sdeb_fake_rw_lck);
32787109f370SDouglas Gilbert 	}
3279e9c47801SDamien Le Moal }
32807109f370SDouglas Gilbert 
32817109f370SDouglas Gilbert static inline void
32827109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip)
32837109f370SDouglas Gilbert {
3284e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3285e9c47801SDamien Le Moal 		if (sip)
3286e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3287e9c47801SDamien Le Moal 		else
3288e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3289e9c47801SDamien Le Moal 	} else {
32907109f370SDouglas Gilbert 		if (sip)
32917109f370SDouglas Gilbert 			write_unlock(&sip->macc_lck);
32927109f370SDouglas Gilbert 		else
32937109f370SDouglas Gilbert 			write_unlock(&sdeb_fake_rw_lck);
32947109f370SDouglas Gilbert 	}
3295e9c47801SDamien Le Moal }
32967109f370SDouglas Gilbert 
3297fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
329819789100SFUJITA Tomonori {
329987c715dcSDouglas Gilbert 	bool check_prot;
3300c2248fc9SDouglas Gilbert 	u32 num;
3301c2248fc9SDouglas Gilbert 	u32 ei_lba;
330219789100SFUJITA Tomonori 	int ret;
330387c715dcSDouglas Gilbert 	u64 lba;
3304b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
330587c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
330619789100SFUJITA Tomonori 
3307c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3308c2248fc9SDouglas Gilbert 	case READ_16:
3309c2248fc9SDouglas Gilbert 		ei_lba = 0;
3310c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3311c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3312c2248fc9SDouglas Gilbert 		check_prot = true;
3313c2248fc9SDouglas Gilbert 		break;
3314c2248fc9SDouglas Gilbert 	case READ_10:
3315c2248fc9SDouglas Gilbert 		ei_lba = 0;
3316c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3317c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3318c2248fc9SDouglas Gilbert 		check_prot = true;
3319c2248fc9SDouglas Gilbert 		break;
3320c2248fc9SDouglas Gilbert 	case READ_6:
3321c2248fc9SDouglas Gilbert 		ei_lba = 0;
3322c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3323c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3324c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3325c2248fc9SDouglas Gilbert 		check_prot = true;
3326c2248fc9SDouglas Gilbert 		break;
3327c2248fc9SDouglas Gilbert 	case READ_12:
3328c2248fc9SDouglas Gilbert 		ei_lba = 0;
3329c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3330c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3331c2248fc9SDouglas Gilbert 		check_prot = true;
3332c2248fc9SDouglas Gilbert 		break;
3333c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3334c2248fc9SDouglas Gilbert 		ei_lba = 0;
3335c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3336c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3337c2248fc9SDouglas Gilbert 		check_prot = false;
3338c2248fc9SDouglas Gilbert 		break;
3339c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3340c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3341c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3342c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3343c2248fc9SDouglas Gilbert 		check_prot = false;
3344c2248fc9SDouglas Gilbert 		break;
3345c2248fc9SDouglas Gilbert 	}
3346f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
33478475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3348c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3349c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3350c2248fc9SDouglas Gilbert 			return check_condition_result;
3351c2248fc9SDouglas Gilbert 		}
33528475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
33538475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3354c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3355c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3356c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3357c2248fc9SDouglas Gilbert 	}
33583a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
33593a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3360c2248fc9SDouglas Gilbert 		num /= 2;
33613a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3362c2248fc9SDouglas Gilbert 	}
3363c2248fc9SDouglas Gilbert 
33649447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
33659447b6ceSMartin K. Petersen 	if (ret)
33669447b6ceSMartin K. Petersen 		return ret;
3367f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3368d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3369d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3370c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3371c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3372c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3373c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3374c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
337532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
337632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3377c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3378c65b1445SDouglas Gilbert 		}
3379c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
33801da177e4SLinus Torvalds 		return check_condition_result;
33811da177e4SLinus Torvalds 	}
3382c6a44287SMartin K. Petersen 
33837109f370SDouglas Gilbert 	sdeb_read_lock(sip);
33846c78cc06SAkinobu Mita 
3385c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3386f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3387f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3388f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3389f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33907109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3391f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3392f7be6772SMartin K. Petersen 				return check_condition_result;
3393f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
33947109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3395f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3396c6a44287SMartin K. Petersen 				return illegal_condition_result;
3397c6a44287SMartin K. Petersen 			}
3398f7be6772SMartin K. Petersen 			break;
3399f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3400f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
34017109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3402f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3403f7be6772SMartin K. Petersen 				return check_condition_result;
3404f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
34057109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3406f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3407f7be6772SMartin K. Petersen 				return illegal_condition_result;
3408f7be6772SMartin K. Petersen 			}
3409f7be6772SMartin K. Petersen 			break;
3410f7be6772SMartin K. Petersen 		}
3411c6a44287SMartin K. Petersen 	}
3412c6a44287SMartin K. Petersen 
341387c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
34147109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
3415f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3416a4517511SAkinobu Mita 		return DID_ERROR << 16;
3417a4517511SAkinobu Mita 
341842d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3419a4517511SAkinobu Mita 
34203a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
34213a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
34223a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
34233a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
34243a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3425c2248fc9SDouglas Gilbert 			return check_condition_result;
34263a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3427c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3428c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
34293a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3430c2248fc9SDouglas Gilbert 			return illegal_condition_result;
34313a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3432c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
34333a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3434c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3435c2248fc9SDouglas Gilbert 		}
3436c2248fc9SDouglas Gilbert 	}
3437a4517511SAkinobu Mita 	return 0;
34381da177e4SLinus Torvalds }
34391da177e4SLinus Torvalds 
3440c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3441395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3442c6a44287SMartin K. Petersen {
3443be4e11beSAkinobu Mita 	int ret;
34446ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3445be4e11beSAkinobu Mita 	void *daddr;
344665f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3447c6a44287SMartin K. Petersen 	int ppage_offset;
3448be4e11beSAkinobu Mita 	int dpage_offset;
3449be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3450be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3451c6a44287SMartin K. Petersen 
3452c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3453c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3454c6a44287SMartin K. Petersen 
3455be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3456be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3457be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3458be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3459be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3460c6a44287SMartin K. Petersen 
3461be4e11beSAkinobu Mita 	/* For each protection page */
3462be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3463be4e11beSAkinobu Mita 		dpage_offset = 0;
3464be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3465be4e11beSAkinobu Mita 			ret = 0x01;
3466be4e11beSAkinobu Mita 			goto out;
3467c6a44287SMartin K. Petersen 		}
3468c6a44287SMartin K. Petersen 
3469be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
34706ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3471be4e11beSAkinobu Mita 			/* If we're at the end of the current
3472be4e11beSAkinobu Mita 			 * data page advance to the next one
3473be4e11beSAkinobu Mita 			 */
3474be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3475be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3476be4e11beSAkinobu Mita 					ret = 0x01;
3477be4e11beSAkinobu Mita 					goto out;
3478be4e11beSAkinobu Mita 				}
3479be4e11beSAkinobu Mita 				dpage_offset = 0;
3480be4e11beSAkinobu Mita 			}
3481c6a44287SMartin K. Petersen 
3482be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3483be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3484be4e11beSAkinobu Mita 
3485f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3486be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3487c78be80dSMartin K. Petersen 				if (ret)
3488395cef03SMartin K. Petersen 					goto out;
3489395cef03SMartin K. Petersen 			}
3490395cef03SMartin K. Petersen 
3491c6a44287SMartin K. Petersen 			sector++;
3492395cef03SMartin K. Petersen 			ei_lba++;
3493773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3494c6a44287SMartin K. Petersen 		}
3495be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3496be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3497c6a44287SMartin K. Petersen 	}
3498be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3499c6a44287SMartin K. Petersen 
350065f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3501c6a44287SMartin K. Petersen 	dix_writes++;
3502c6a44287SMartin K. Petersen 
3503c6a44287SMartin K. Petersen 	return 0;
3504c6a44287SMartin K. Petersen 
3505c6a44287SMartin K. Petersen out:
3506c6a44287SMartin K. Petersen 	dif_errors++;
3507be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3508be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3509c6a44287SMartin K. Petersen 	return ret;
3510c6a44287SMartin K. Petersen }
3511c6a44287SMartin K. Petersen 
3512b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3513b90ebc3dSAkinobu Mita {
3514773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3515773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3516773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3517b90ebc3dSAkinobu Mita 	return lba;
3518b90ebc3dSAkinobu Mita }
3519b90ebc3dSAkinobu Mita 
3520b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3521b90ebc3dSAkinobu Mita {
3522773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3523a027b5b9SAkinobu Mita 
3524773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3525773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3526a027b5b9SAkinobu Mita 	return lba;
3527a027b5b9SAkinobu Mita }
3528a027b5b9SAkinobu Mita 
352987c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
353087c715dcSDouglas Gilbert 			      unsigned int *num)
353144d92694SMartin K. Petersen {
3532b90ebc3dSAkinobu Mita 	sector_t end;
3533b90ebc3dSAkinobu Mita 	unsigned int mapped;
3534b90ebc3dSAkinobu Mita 	unsigned long index;
3535b90ebc3dSAkinobu Mita 	unsigned long next;
353644d92694SMartin K. Petersen 
3537b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
353887c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
353944d92694SMartin K. Petersen 
354044d92694SMartin K. Petersen 	if (mapped)
354187c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
354244d92694SMartin K. Petersen 	else
354387c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
354444d92694SMartin K. Petersen 
3545b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
354644d92694SMartin K. Petersen 	*num = end - lba;
354744d92694SMartin K. Petersen 	return mapped;
354844d92694SMartin K. Petersen }
354944d92694SMartin K. Petersen 
355087c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
355187c715dcSDouglas Gilbert 		       unsigned int len)
355244d92694SMartin K. Petersen {
355344d92694SMartin K. Petersen 	sector_t end = lba + len;
355444d92694SMartin K. Petersen 
355544d92694SMartin K. Petersen 	while (lba < end) {
3556b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
355744d92694SMartin K. Petersen 
3558b90ebc3dSAkinobu Mita 		if (index < map_size)
355987c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
356044d92694SMartin K. Petersen 
3561b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
356244d92694SMartin K. Petersen 	}
356344d92694SMartin K. Petersen }
356444d92694SMartin K. Petersen 
356587c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
356687c715dcSDouglas Gilbert 			 unsigned int len)
356744d92694SMartin K. Petersen {
356844d92694SMartin K. Petersen 	sector_t end = lba + len;
356987c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
357044d92694SMartin K. Petersen 
357144d92694SMartin K. Petersen 	while (lba < end) {
3572b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
357344d92694SMartin K. Petersen 
3574b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3575773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3576b90ebc3dSAkinobu Mita 		    index < map_size) {
357787c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3578760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
357987c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3580760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3581773642d9SDouglas Gilbert 				       sdebug_sector_size *
3582773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3583be1dd78dSEric Sandeen 			}
358487c715dcSDouglas Gilbert 			if (sip->dif_storep) {
358587c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
358687c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3587773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3588e9926b43SAkinobu Mita 			}
3589b90ebc3dSAkinobu Mita 		}
3590b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
359144d92694SMartin K. Petersen 	}
359244d92694SMartin K. Petersen }
359344d92694SMartin K. Petersen 
3594fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
35951da177e4SLinus Torvalds {
359687c715dcSDouglas Gilbert 	bool check_prot;
3597c2248fc9SDouglas Gilbert 	u32 num;
3598c2248fc9SDouglas Gilbert 	u32 ei_lba;
359919789100SFUJITA Tomonori 	int ret;
360087c715dcSDouglas Gilbert 	u64 lba;
3601b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
360287c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
36031da177e4SLinus Torvalds 
3604c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3605c2248fc9SDouglas Gilbert 	case WRITE_16:
3606c2248fc9SDouglas Gilbert 		ei_lba = 0;
3607c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3608c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3609c2248fc9SDouglas Gilbert 		check_prot = true;
3610c2248fc9SDouglas Gilbert 		break;
3611c2248fc9SDouglas Gilbert 	case WRITE_10:
3612c2248fc9SDouglas Gilbert 		ei_lba = 0;
3613c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3614c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3615c2248fc9SDouglas Gilbert 		check_prot = true;
3616c2248fc9SDouglas Gilbert 		break;
3617c2248fc9SDouglas Gilbert 	case WRITE_6:
3618c2248fc9SDouglas Gilbert 		ei_lba = 0;
3619c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3620c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3621c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3622c2248fc9SDouglas Gilbert 		check_prot = true;
3623c2248fc9SDouglas Gilbert 		break;
3624c2248fc9SDouglas Gilbert 	case WRITE_12:
3625c2248fc9SDouglas Gilbert 		ei_lba = 0;
3626c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3627c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3628c2248fc9SDouglas Gilbert 		check_prot = true;
3629c2248fc9SDouglas Gilbert 		break;
3630c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3631c2248fc9SDouglas Gilbert 		ei_lba = 0;
3632c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3633c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3634c2248fc9SDouglas Gilbert 		check_prot = false;
3635c2248fc9SDouglas Gilbert 		break;
3636c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3637c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3638c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3639c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3640c2248fc9SDouglas Gilbert 		check_prot = false;
3641c2248fc9SDouglas Gilbert 		break;
3642c2248fc9SDouglas Gilbert 	}
3643f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
36448475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3645c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3646c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3647c2248fc9SDouglas Gilbert 			return check_condition_result;
3648c2248fc9SDouglas Gilbert 		}
36498475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
36508475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3651c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3652c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3653c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3654c2248fc9SDouglas Gilbert 	}
3655f0d1cf93SDouglas Gilbert 
36567109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3657f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3658f0d1cf93SDouglas Gilbert 	if (ret) {
36597109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3660f0d1cf93SDouglas Gilbert 		return ret;
3661f0d1cf93SDouglas Gilbert 	}
36626c78cc06SAkinobu Mita 
3663c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3664f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3665f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3666f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3667f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
36687109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3669f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3670c6a44287SMartin K. Petersen 				return illegal_condition_result;
3671f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36727109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3673f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3674f7be6772SMartin K. Petersen 				return check_condition_result;
3675f7be6772SMartin K. Petersen 			}
3676f7be6772SMartin K. Petersen 			break;
3677f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3678f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
36797109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3680f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3681f7be6772SMartin K. Petersen 				return illegal_condition_result;
3682f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36837109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3684f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3685f7be6772SMartin K. Petersen 				return check_condition_result;
3686f7be6772SMartin K. Petersen 			}
3687f7be6772SMartin K. Petersen 			break;
3688c6a44287SMartin K. Petersen 		}
3689c6a44287SMartin K. Petersen 	}
3690c6a44287SMartin K. Petersen 
369187c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3692f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
369387c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3694f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3695f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3696f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
36977109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3698f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3699773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3700c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3701c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3702c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3703cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3704773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
370544d92694SMartin K. Petersen 
37063a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
37073a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
37083a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
37093a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
37103a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3711c2248fc9SDouglas Gilbert 			return check_condition_result;
37123a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3713c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3714c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37153a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3716c2248fc9SDouglas Gilbert 			return illegal_condition_result;
37173a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3718c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37193a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3720c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3721c2248fc9SDouglas Gilbert 		}
3722c2248fc9SDouglas Gilbert 	}
37231da177e4SLinus Torvalds 	return 0;
37241da177e4SLinus Torvalds }
37251da177e4SLinus Torvalds 
3726481b5e5cSDouglas Gilbert /*
3727481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3728481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3729481b5e5cSDouglas Gilbert  */
3730481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3731481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3732481b5e5cSDouglas Gilbert {
3733481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3734481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3735481b5e5cSDouglas Gilbert 	u8 *up;
3736b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3737481b5e5cSDouglas Gilbert 	u8 wrprotect;
3738481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3739481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3740481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3741481b5e5cSDouglas Gilbert 	u32 ei_lba;
3742481b5e5cSDouglas Gilbert 	u64 lba;
3743481b5e5cSDouglas Gilbert 	int ret, res;
3744481b5e5cSDouglas Gilbert 	bool is_16;
3745481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3746481b5e5cSDouglas Gilbert 
3747481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3748481b5e5cSDouglas Gilbert 		is_16 = false;
3749481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3750481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3751481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3752481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3753481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3754481b5e5cSDouglas Gilbert 		is_16 = true;
3755481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3756481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3757481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3758481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3759481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3760481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3761481b5e5cSDouglas Gilbert 			    wrprotect) {
3762481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3763481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3764481b5e5cSDouglas Gilbert 			}
3765481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3766481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3767481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3768481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3769481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3770481b5e5cSDouglas Gilbert 		}
3771481b5e5cSDouglas Gilbert 	}
3772481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3773481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3774481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3775481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3776481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3777481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3778481b5e5cSDouglas Gilbert 				my_name, __func__);
3779481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3780481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3781481b5e5cSDouglas Gilbert 	}
3782481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3783481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3784481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3785481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3786481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3787481b5e5cSDouglas Gilbert 				my_name, __func__);
3788481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3789481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3790481b5e5cSDouglas Gilbert 	}
3791216e1797SHarshit Mogalapalli 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN);
3792481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3793481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3794481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3795481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3796481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3797481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3798481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3799481b5e5cSDouglas Gilbert 	if (res == -1) {
3800481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3801481b5e5cSDouglas Gilbert 		goto err_out;
3802481b5e5cSDouglas Gilbert 	}
3803481b5e5cSDouglas Gilbert 
38047109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3805481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3806481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3807481b5e5cSDouglas Gilbert 	cum_lb = 0;
3808481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3809481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3810481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3811481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3812481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3813481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3814481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3815481b5e5cSDouglas Gilbert 		if (num == 0)
3816481b5e5cSDouglas Gilbert 			continue;
38179447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3818481b5e5cSDouglas Gilbert 		if (ret)
3819481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3820481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3821481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3822481b5e5cSDouglas Gilbert 
3823481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3824481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3825481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3826481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3827481b5e5cSDouglas Gilbert 				    my_name, __func__);
3828481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3829481b5e5cSDouglas Gilbert 					0);
3830481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3831481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3832481b5e5cSDouglas Gilbert 		}
3833481b5e5cSDouglas Gilbert 
3834481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3835481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3836481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3837481b5e5cSDouglas Gilbert 							 ei_lba);
3838481b5e5cSDouglas Gilbert 
3839481b5e5cSDouglas Gilbert 			if (prot_ret) {
3840481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3841481b5e5cSDouglas Gilbert 						prot_ret);
3842481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3843481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3844481b5e5cSDouglas Gilbert 			}
3845481b5e5cSDouglas Gilbert 		}
3846481b5e5cSDouglas Gilbert 
384787c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3848f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3849f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3850f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3851481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
385287c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3853481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3854481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3855481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3856481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3857481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3858481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3859481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3860481b5e5cSDouglas Gilbert 
38613a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
38623a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
38633a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
38643a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
38653a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
38663a90a63dSDouglas Gilbert 				ret = check_condition_result;
3867481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38683a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3869481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
38703a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
38713a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3872481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3873481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38743a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
38753a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
38763a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3877481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3878481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3879481b5e5cSDouglas Gilbert 			}
3880481b5e5cSDouglas Gilbert 		}
3881481b5e5cSDouglas Gilbert 		sg_off += num_by;
3882481b5e5cSDouglas Gilbert 		cum_lb += num;
3883481b5e5cSDouglas Gilbert 	}
3884481b5e5cSDouglas Gilbert 	ret = 0;
3885481b5e5cSDouglas Gilbert err_out_unlock:
38867109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3887481b5e5cSDouglas Gilbert err_out:
3888481b5e5cSDouglas Gilbert 	kfree(lrdp);
3889481b5e5cSDouglas Gilbert 	return ret;
3890481b5e5cSDouglas Gilbert }
3891481b5e5cSDouglas Gilbert 
3892fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3893fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
389444d92694SMartin K. Petersen {
3895f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3896f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
389744d92694SMartin K. Petersen 	unsigned long long i;
389840d07b52SDouglas Gilbert 	u64 block, lbaa;
389987c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
390087c715dcSDouglas Gilbert 	int ret;
390187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3902b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
390340d07b52SDouglas Gilbert 	u8 *fs1p;
390487c715dcSDouglas Gilbert 	u8 *fsp;
390544d92694SMartin K. Petersen 
39067109f370SDouglas Gilbert 	sdeb_write_lock(sip);
390744d92694SMartin K. Petersen 
3908f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3909f0d1cf93SDouglas Gilbert 	if (ret) {
39107109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3911f0d1cf93SDouglas Gilbert 		return ret;
3912f0d1cf93SDouglas Gilbert 	}
3913f0d1cf93SDouglas Gilbert 
39149ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
391587c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
391644d92694SMartin K. Petersen 		goto out;
391744d92694SMartin K. Petersen 	}
391840d07b52SDouglas Gilbert 	lbaa = lba;
391940d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3920c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
392187c715dcSDouglas Gilbert 	fsp = sip->storep;
392287c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3923c2248fc9SDouglas Gilbert 	if (ndob) {
392440d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3925c2248fc9SDouglas Gilbert 		ret = 0;
3926c2248fc9SDouglas Gilbert 	} else
392740d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
392844d92694SMartin K. Petersen 
392944d92694SMartin K. Petersen 	if (-1 == ret) {
39307109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3931773642d9SDouglas Gilbert 		return DID_ERROR << 16;
393240d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3933c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3934e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
393540d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
393644d92694SMartin K. Petersen 
393744d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
393840d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
393940d07b52SDouglas Gilbert 		lbaa = lba + i;
394040d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
394187c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
394240d07b52SDouglas Gilbert 	}
39439ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
394487c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3945f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3946f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3947f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
394844d92694SMartin K. Petersen out:
39497109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
395044d92694SMartin K. Petersen 
395144d92694SMartin K. Petersen 	return 0;
395244d92694SMartin K. Petersen }
395344d92694SMartin K. Petersen 
3954fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3955fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3956c2248fc9SDouglas Gilbert {
3957c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3958c2248fc9SDouglas Gilbert 	u32 lba;
3959c2248fc9SDouglas Gilbert 	u16 num;
3960c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3961c2248fc9SDouglas Gilbert 	bool unmap = false;
3962c2248fc9SDouglas Gilbert 
3963c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3964773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3965c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3966c2248fc9SDouglas Gilbert 			return check_condition_result;
3967c2248fc9SDouglas Gilbert 		} else
3968c2248fc9SDouglas Gilbert 			unmap = true;
3969c2248fc9SDouglas Gilbert 	}
3970c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3971c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3972773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3973c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3974c2248fc9SDouglas Gilbert 		return check_condition_result;
3975c2248fc9SDouglas Gilbert 	}
3976c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3977c2248fc9SDouglas Gilbert }
3978c2248fc9SDouglas Gilbert 
3979fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3980fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3981c2248fc9SDouglas Gilbert {
3982c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3983c2248fc9SDouglas Gilbert 	u64 lba;
3984c2248fc9SDouglas Gilbert 	u32 num;
3985c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3986c2248fc9SDouglas Gilbert 	bool unmap = false;
3987c2248fc9SDouglas Gilbert 	bool ndob = false;
3988c2248fc9SDouglas Gilbert 
3989c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3990773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3991c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3992c2248fc9SDouglas Gilbert 			return check_condition_result;
3993c2248fc9SDouglas Gilbert 		} else
3994c2248fc9SDouglas Gilbert 			unmap = true;
3995c2248fc9SDouglas Gilbert 	}
3996c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3997c2248fc9SDouglas Gilbert 		ndob = true;
3998c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3999c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
4000773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
4001c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
4002c2248fc9SDouglas Gilbert 		return check_condition_result;
4003c2248fc9SDouglas Gilbert 	}
4004c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
4005c2248fc9SDouglas Gilbert }
4006c2248fc9SDouglas Gilbert 
4007acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
4008acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
4009acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
4010fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
4011fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
4012acafd0b9SEwan D. Milne {
4013acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
4014acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
4015acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
4016acafd0b9SEwan D. Milne 	u8 mode;
4017acafd0b9SEwan D. Milne 
4018acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
4019acafd0b9SEwan D. Milne 	switch (mode) {
4020acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
4021acafd0b9SEwan D. Milne 		/* set UAs on this device only */
4022acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4023acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
4024acafd0b9SEwan D. Milne 		break;
4025acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
4026acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
4027acafd0b9SEwan D. Milne 		break;
4028acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
4029acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
4030acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4031acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4032acafd0b9SEwan D. Milne 				    dev_list)
4033acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
4034acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
4035acafd0b9SEwan D. Milne 				if (devip != dp)
4036acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
4037acafd0b9SEwan D. Milne 						dp->uas_bm);
4038acafd0b9SEwan D. Milne 			}
4039acafd0b9SEwan D. Milne 		break;
4040acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
4041acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
4042acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4043acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4044acafd0b9SEwan D. Milne 				    dev_list)
4045acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
4046acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
4047acafd0b9SEwan D. Milne 					dp->uas_bm);
4048acafd0b9SEwan D. Milne 		break;
4049acafd0b9SEwan D. Milne 	default:
4050acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
4051acafd0b9SEwan D. Milne 		break;
4052acafd0b9SEwan D. Milne 	}
4053acafd0b9SEwan D. Milne 	return 0;
4054acafd0b9SEwan D. Milne }
4055acafd0b9SEwan D. Milne 
4056fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
4057fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
405838d5c833SDouglas Gilbert {
405938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
406038d5c833SDouglas Gilbert 	u8 *arr;
4061b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
406238d5c833SDouglas Gilbert 	u64 lba;
406338d5c833SDouglas Gilbert 	u32 dnum;
4064773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
406538d5c833SDouglas Gilbert 	u8 num;
406638d5c833SDouglas Gilbert 	int ret;
4067d467d31fSDouglas Gilbert 	int retval = 0;
406838d5c833SDouglas Gilbert 
4069d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
407038d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
407138d5c833SDouglas Gilbert 	if (0 == num)
407238d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
40738475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
407438d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
407538d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
407638d5c833SDouglas Gilbert 		return check_condition_result;
407738d5c833SDouglas Gilbert 	}
40788475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
40798475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
408038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
408138d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
408238d5c833SDouglas Gilbert 			    "to DIF device\n");
40839447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
40849447b6ceSMartin K. Petersen 	if (ret)
40859447b6ceSMartin K. Petersen 		return ret;
4086d467d31fSDouglas Gilbert 	dnum = 2 * num;
40876396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
4088d467d31fSDouglas Gilbert 	if (NULL == arr) {
4089d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4090d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
4091d467d31fSDouglas Gilbert 		return check_condition_result;
4092d467d31fSDouglas Gilbert 	}
409338d5c833SDouglas Gilbert 
40947109f370SDouglas Gilbert 	sdeb_write_lock(sip);
409538d5c833SDouglas Gilbert 
409687c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
409738d5c833SDouglas Gilbert 	if (ret == -1) {
4098d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
4099d467d31fSDouglas Gilbert 		goto cleanup;
4100773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
410138d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
410238d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
410338d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
4104c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
410538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4106d467d31fSDouglas Gilbert 		retval = check_condition_result;
4107d467d31fSDouglas Gilbert 		goto cleanup;
410838d5c833SDouglas Gilbert 	}
410938d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
411087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
4111d467d31fSDouglas Gilbert cleanup:
41127109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4113d467d31fSDouglas Gilbert 	kfree(arr);
4114d467d31fSDouglas Gilbert 	return retval;
411538d5c833SDouglas Gilbert }
411638d5c833SDouglas Gilbert 
411744d92694SMartin K. Petersen struct unmap_block_desc {
411844d92694SMartin K. Petersen 	__be64	lba;
411944d92694SMartin K. Petersen 	__be32	blocks;
412044d92694SMartin K. Petersen 	__be32	__reserved;
412144d92694SMartin K. Petersen };
412244d92694SMartin K. Petersen 
4123fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
412444d92694SMartin K. Petersen {
412544d92694SMartin K. Petersen 	unsigned char *buf;
412644d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
4127b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
412844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
412944d92694SMartin K. Petersen 	int ret;
413044d92694SMartin K. Petersen 
4131c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
4132c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
4133c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
4134c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
413544d92694SMartin K. Petersen 
413644d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
4137773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
4138c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
413944d92694SMartin K. Petersen 		return check_condition_result;
4140c2248fc9SDouglas Gilbert 	}
414144d92694SMartin K. Petersen 
4142b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
4143c2248fc9SDouglas Gilbert 	if (!buf) {
4144c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4145c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
4146c2248fc9SDouglas Gilbert 		return check_condition_result;
4147c2248fc9SDouglas Gilbert 	}
4148c2248fc9SDouglas Gilbert 
4149c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
415044d92694SMartin K. Petersen 
415144d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
415244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
415344d92694SMartin K. Petersen 
415444d92694SMartin K. Petersen 	desc = (void *)&buf[8];
415544d92694SMartin K. Petersen 
41567109f370SDouglas Gilbert 	sdeb_write_lock(sip);
41576c78cc06SAkinobu Mita 
415844d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
415944d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
416044d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
416144d92694SMartin K. Petersen 
41629447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
416344d92694SMartin K. Petersen 		if (ret)
416444d92694SMartin K. Petersen 			goto out;
416544d92694SMartin K. Petersen 
416687c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
416744d92694SMartin K. Petersen 	}
416844d92694SMartin K. Petersen 
416944d92694SMartin K. Petersen 	ret = 0;
417044d92694SMartin K. Petersen 
417144d92694SMartin K. Petersen out:
41727109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
417344d92694SMartin K. Petersen 	kfree(buf);
417444d92694SMartin K. Petersen 
417544d92694SMartin K. Petersen 	return ret;
417644d92694SMartin K. Petersen }
417744d92694SMartin K. Petersen 
417844d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
417944d92694SMartin K. Petersen 
4180fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4181fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
418244d92694SMartin K. Petersen {
4183c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4184c2248fc9SDouglas Gilbert 	u64 lba;
4185c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
418644d92694SMartin K. Petersen 	int ret;
418787c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
418844d92694SMartin K. Petersen 
4189c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4190c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
419144d92694SMartin K. Petersen 
419244d92694SMartin K. Petersen 	if (alloc_len < 24)
419344d92694SMartin K. Petersen 		return 0;
419444d92694SMartin K. Petersen 
41959447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
419644d92694SMartin K. Petersen 	if (ret)
419744d92694SMartin K. Petersen 		return ret;
419844d92694SMartin K. Petersen 
4199b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4200b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4201b6ff8ca7SDouglas Gilbert 
420287c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4203b6ff8ca7SDouglas Gilbert 	} else {
4204c2248fc9SDouglas Gilbert 		mapped = 1;
4205c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4206c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4207c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4208c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4209c2248fc9SDouglas Gilbert 		else
4210c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4211c2248fc9SDouglas Gilbert 	}
421244d92694SMartin K. Petersen 
421344d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4214c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4215c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4216c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4217c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
421844d92694SMartin K. Petersen 
4219c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
422044d92694SMartin K. Petersen }
422144d92694SMartin K. Petersen 
422280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
422380c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
422480c49563SDouglas Gilbert {
42254f2c8bf6SDouglas Gilbert 	int res = 0;
422680c49563SDouglas Gilbert 	u64 lba;
422780c49563SDouglas Gilbert 	u32 num_blocks;
422880c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
422980c49563SDouglas Gilbert 
423080c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
423180c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
423280c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
423380c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
423480c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
423580c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
423680c49563SDouglas Gilbert 	}
423780c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
423880c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
423980c49563SDouglas Gilbert 		return check_condition_result;
424080c49563SDouglas Gilbert 	}
4241fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
42424f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
42434f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
42444f2c8bf6SDouglas Gilbert 		write_since_sync = false;
42454f2c8bf6SDouglas Gilbert 	return res;
424680c49563SDouglas Gilbert }
424780c49563SDouglas Gilbert 
4248ed9f3e25SDouglas Gilbert /*
4249ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4250ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4251ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4252ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4253ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4254ed9f3e25SDouglas Gilbert  */
4255ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4256ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4257ed9f3e25SDouglas Gilbert {
4258ed9f3e25SDouglas Gilbert 	int res = 0;
4259ed9f3e25SDouglas Gilbert 	u64 lba;
4260ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4261ed9f3e25SDouglas Gilbert 	u32 nblks;
4262ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4263b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4264b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4265ed9f3e25SDouglas Gilbert 
4266ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4267ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4268ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4269ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4270ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4271ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4272ed9f3e25SDouglas Gilbert 	}
4273ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4274ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4275ed9f3e25SDouglas Gilbert 		return check_condition_result;
4276ed9f3e25SDouglas Gilbert 	}
4277ed9f3e25SDouglas Gilbert 	if (!fsp)
4278ed9f3e25SDouglas Gilbert 		goto fini;
4279ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4280ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4281ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4282ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4283ed9f3e25SDouglas Gilbert 
4284ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
42857109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4286ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4287ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4288ed9f3e25SDouglas Gilbert 	if (rest)
4289ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
42907109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4291ed9f3e25SDouglas Gilbert fini:
4292ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4293ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4294ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4295ed9f3e25SDouglas Gilbert }
4296ed9f3e25SDouglas Gilbert 
4297fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4298fb0cc8d1SDouglas Gilbert 
42998d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
43008d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
43018d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
43028d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
43038d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
43048d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
43058d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
43068d039e22SDouglas Gilbert  */
43071da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
43081da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
43091da177e4SLinus Torvalds {
431001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
43118d039e22SDouglas Gilbert 	unsigned int alloc_len;
43128d039e22SDouglas Gilbert 	unsigned char select_report;
43138d039e22SDouglas Gilbert 	u64 lun;
43148d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4315fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
43168d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
43178d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
43188d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
43198d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4320fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4321fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4322fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
43231da177e4SLinus Torvalds 
432419c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
43258d039e22SDouglas Gilbert 
43268d039e22SDouglas Gilbert 	select_report = cmd[2];
43278d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
43288d039e22SDouglas Gilbert 
43298d039e22SDouglas Gilbert 	if (alloc_len < 4) {
43308d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
43318d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
43321da177e4SLinus Torvalds 		return check_condition_result;
43331da177e4SLinus Torvalds 	}
43348d039e22SDouglas Gilbert 
43358d039e22SDouglas Gilbert 	switch (select_report) {
43368d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4337773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43388d039e22SDouglas Gilbert 		wlun_cnt = 0;
43398d039e22SDouglas Gilbert 		break;
43408d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4341c65b1445SDouglas Gilbert 		lun_cnt = 0;
43428d039e22SDouglas Gilbert 		wlun_cnt = 1;
43438d039e22SDouglas Gilbert 		break;
43448d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
43458d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43468d039e22SDouglas Gilbert 		wlun_cnt = 1;
43478d039e22SDouglas Gilbert 		break;
43488d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
43498d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
43508d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
43518d039e22SDouglas Gilbert 	default:
43528d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
43538d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
43548d039e22SDouglas Gilbert 		return check_condition_result;
43558d039e22SDouglas Gilbert 	}
43568d039e22SDouglas Gilbert 
43578d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4358c65b1445SDouglas Gilbert 		--lun_cnt;
43598d039e22SDouglas Gilbert 
43608d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4361fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4362fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
43638d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
43648d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
43658d039e22SDouglas Gilbert 
4366fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
43678d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4368fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4369fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4370fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4371fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4372fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4373fb0cc8d1SDouglas Gilbert 			++lun_p;
4374fb0cc8d1SDouglas Gilbert 			j = 1;
4375fb0cc8d1SDouglas Gilbert 		}
4376fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4377fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4378fb0cc8d1SDouglas Gilbert 				break;
4379fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4380ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4381ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4382fb0cc8d1SDouglas Gilbert 		}
4383fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4384fb0cc8d1SDouglas Gilbert 			break;
4385fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4386fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4387fb0cc8d1SDouglas Gilbert 		if (res)
4388fb0cc8d1SDouglas Gilbert 			return res;
4389fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4390fb0cc8d1SDouglas Gilbert 	}
4391fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4392fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4393fb0cc8d1SDouglas Gilbert 		++j;
4394fb0cc8d1SDouglas Gilbert 	}
4395fb0cc8d1SDouglas Gilbert 	if (j > 0)
4396fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
43978d039e22SDouglas Gilbert 	return res;
43981da177e4SLinus Torvalds }
43991da177e4SLinus Torvalds 
4400c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4401c3e2fe92SDouglas Gilbert {
4402c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4403c3e2fe92SDouglas Gilbert 	u8 bytchk;
4404c3e2fe92SDouglas Gilbert 	int ret, j;
4405c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4406c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4407c3e2fe92SDouglas Gilbert 	u64 lba;
4408c3e2fe92SDouglas Gilbert 	u8 *arr;
4409c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4410b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4411c3e2fe92SDouglas Gilbert 
4412c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4413c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4414c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4415c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4416c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4417c3e2fe92SDouglas Gilbert 		return check_condition_result;
4418c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4419c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4420c3e2fe92SDouglas Gilbert 	}
4421c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4422c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4423c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4424c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4425c3e2fe92SDouglas Gilbert 		break;
4426c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4427c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4428c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4429c3e2fe92SDouglas Gilbert 		break;
4430c3e2fe92SDouglas Gilbert 	default:
4431c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4432c3e2fe92SDouglas Gilbert 		return check_condition_result;
4433c3e2fe92SDouglas Gilbert 	}
44343344b58bSGeorge Kennedy 	if (vnum == 0)
44353344b58bSGeorge Kennedy 		return 0;	/* not an error */
4436c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4437c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4438c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4439c3e2fe92SDouglas Gilbert 	if (ret)
4440c3e2fe92SDouglas Gilbert 		return ret;
4441c3e2fe92SDouglas Gilbert 
4442ed0f17b7SHarshit Mogalapalli 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN);
4443c3e2fe92SDouglas Gilbert 	if (!arr) {
4444c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4445c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4446c3e2fe92SDouglas Gilbert 		return check_condition_result;
4447c3e2fe92SDouglas Gilbert 	}
4448c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
44497109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4450c3e2fe92SDouglas Gilbert 
4451c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4452c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4453c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4454c3e2fe92SDouglas Gilbert 		goto cleanup;
4455c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4456c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4457c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4458c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4459c3e2fe92SDouglas Gilbert 	}
4460c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4461c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4462c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4463c3e2fe92SDouglas Gilbert 	}
4464c3e2fe92SDouglas Gilbert 	ret = 0;
4465c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4466c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4467c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4468c3e2fe92SDouglas Gilbert 		goto cleanup;
4469c3e2fe92SDouglas Gilbert 	}
4470c3e2fe92SDouglas Gilbert cleanup:
44717109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4472c3e2fe92SDouglas Gilbert 	kfree(arr);
4473c3e2fe92SDouglas Gilbert 	return ret;
4474c3e2fe92SDouglas Gilbert }
4475c3e2fe92SDouglas Gilbert 
4476f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4477f0d1cf93SDouglas Gilbert 
4478897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */
4479f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4480f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4481f0d1cf93SDouglas Gilbert {
44824a5fc1c6SDamien Le Moal 	unsigned int rep_max_zones, nrz = 0;
4483f0d1cf93SDouglas Gilbert 	int ret = 0;
4484f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4485f0d1cf93SDouglas Gilbert 	bool partial;
4486f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4487f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4488f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
44894a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp = NULL;
4490b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4491f0d1cf93SDouglas Gilbert 
4492f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4493f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4494f0d1cf93SDouglas Gilbert 		return check_condition_result;
4495f0d1cf93SDouglas Gilbert 	}
4496f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4497f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
44983344b58bSGeorge Kennedy 	if (alloc_len == 0)
44993344b58bSGeorge Kennedy 		return 0;	/* not an error */
4500f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4501f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4502f0d1cf93SDouglas Gilbert 
4503f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4504f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4505f0d1cf93SDouglas Gilbert 		return check_condition_result;
4506f0d1cf93SDouglas Gilbert 	}
4507f0d1cf93SDouglas Gilbert 
45084a5fc1c6SDamien Le Moal 	rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
4509f0d1cf93SDouglas Gilbert 
451007f2ca13SHarshit Mogalapalli 	arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
4511f0d1cf93SDouglas Gilbert 	if (!arr) {
4512f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4513f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4514f0d1cf93SDouglas Gilbert 		return check_condition_result;
4515f0d1cf93SDouglas Gilbert 	}
4516f0d1cf93SDouglas Gilbert 
45177109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4518f0d1cf93SDouglas Gilbert 
4519f0d1cf93SDouglas Gilbert 	desc = arr + 64;
45204a5fc1c6SDamien Le Moal 	for (lba = zs_lba; lba < sdebug_capacity;
45214a5fc1c6SDamien Le Moal 	     lba = zsp->z_start + zsp->z_size) {
45224a5fc1c6SDamien Le Moal 		if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba))
4523f0d1cf93SDouglas Gilbert 			break;
4524f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4525f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4526f0d1cf93SDouglas Gilbert 		case 0x00:
4527f0d1cf93SDouglas Gilbert 			/* All zones */
4528f0d1cf93SDouglas Gilbert 			break;
4529f0d1cf93SDouglas Gilbert 		case 0x01:
4530f0d1cf93SDouglas Gilbert 			/* Empty zones */
4531f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4532f0d1cf93SDouglas Gilbert 				continue;
4533f0d1cf93SDouglas Gilbert 			break;
4534f0d1cf93SDouglas Gilbert 		case 0x02:
4535f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4536f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4537f0d1cf93SDouglas Gilbert 				continue;
4538f0d1cf93SDouglas Gilbert 			break;
4539f0d1cf93SDouglas Gilbert 		case 0x03:
4540f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4541f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4542f0d1cf93SDouglas Gilbert 				continue;
4543f0d1cf93SDouglas Gilbert 			break;
4544f0d1cf93SDouglas Gilbert 		case 0x04:
4545f0d1cf93SDouglas Gilbert 			/* Closed zones */
4546f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4547f0d1cf93SDouglas Gilbert 				continue;
4548f0d1cf93SDouglas Gilbert 			break;
4549f0d1cf93SDouglas Gilbert 		case 0x05:
4550f0d1cf93SDouglas Gilbert 			/* Full zones */
4551f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4552f0d1cf93SDouglas Gilbert 				continue;
4553f0d1cf93SDouglas Gilbert 			break;
4554f0d1cf93SDouglas Gilbert 		case 0x06:
4555f0d1cf93SDouglas Gilbert 		case 0x07:
4556f0d1cf93SDouglas Gilbert 		case 0x10:
4557f0d1cf93SDouglas Gilbert 			/*
455864e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
455964e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4560f0d1cf93SDouglas Gilbert 			 */
4561f0d1cf93SDouglas Gilbert 			continue;
456264e14eceSDamien Le Moal 		case 0x11:
456364e14eceSDamien Le Moal 			/* non-seq-resource set */
456464e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
456564e14eceSDamien Le Moal 				continue;
456664e14eceSDamien Le Moal 			break;
45674a5fc1c6SDamien Le Moal 		case 0x3e:
45684a5fc1c6SDamien Le Moal 			/* All zones except gap zones. */
45694a5fc1c6SDamien Le Moal 			if (zbc_zone_is_gap(zsp))
45704a5fc1c6SDamien Le Moal 				continue;
45714a5fc1c6SDamien Le Moal 			break;
4572f0d1cf93SDouglas Gilbert 		case 0x3f:
4573f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
45744a5fc1c6SDamien Le Moal 			if (zbc_zone_is_seq(zsp))
4575f0d1cf93SDouglas Gilbert 				continue;
4576f0d1cf93SDouglas Gilbert 			break;
4577f0d1cf93SDouglas Gilbert 		default:
4578f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4579f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4580f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4581f0d1cf93SDouglas Gilbert 			goto fini;
4582f0d1cf93SDouglas Gilbert 		}
4583f0d1cf93SDouglas Gilbert 
4584f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4585f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
458664e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4587f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
458864e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
458964e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4590f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4591f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4592f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4593f0d1cf93SDouglas Gilbert 			desc += 64;
4594f0d1cf93SDouglas Gilbert 		}
4595f0d1cf93SDouglas Gilbert 
4596f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4597f0d1cf93SDouglas Gilbert 			break;
4598f0d1cf93SDouglas Gilbert 
4599f0d1cf93SDouglas Gilbert 		nrz++;
4600f0d1cf93SDouglas Gilbert 	}
4601f0d1cf93SDouglas Gilbert 
4602f0d1cf93SDouglas Gilbert 	/* Report header */
46034a5fc1c6SDamien Le Moal 	/* Zone list length. */
4604f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
46054a5fc1c6SDamien Le Moal 	/* Maximum LBA */
4606f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
46074a5fc1c6SDamien Le Moal 	/* Zone starting LBA granularity. */
46084a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
46094a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, arr + 16);
4610f0d1cf93SDouglas Gilbert 
4611f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
461236e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4613f0d1cf93SDouglas Gilbert 
4614f0d1cf93SDouglas Gilbert fini:
46157109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4616f0d1cf93SDouglas Gilbert 	kfree(arr);
4617f0d1cf93SDouglas Gilbert 	return ret;
4618f0d1cf93SDouglas Gilbert }
4619f0d1cf93SDouglas Gilbert 
4620f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4621f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4622f0d1cf93SDouglas Gilbert {
4623f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4624f0d1cf93SDouglas Gilbert 	unsigned int i;
4625f0d1cf93SDouglas Gilbert 
4626f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4627f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4628f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4629f0d1cf93SDouglas Gilbert 	}
4630f0d1cf93SDouglas Gilbert }
4631f0d1cf93SDouglas Gilbert 
4632f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4633f0d1cf93SDouglas Gilbert {
4634f0d1cf93SDouglas Gilbert 	int res = 0;
4635f0d1cf93SDouglas Gilbert 	u64 z_id;
4636f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4637f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4638f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4639f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4640b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4641f0d1cf93SDouglas Gilbert 
4642f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4643f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4644f0d1cf93SDouglas Gilbert 		return check_condition_result;
4645f0d1cf93SDouglas Gilbert 	}
4646f0d1cf93SDouglas Gilbert 
46477109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4648f0d1cf93SDouglas Gilbert 
4649f0d1cf93SDouglas Gilbert 	if (all) {
4650f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4651f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4652f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4653f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4654f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4655f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4656f0d1cf93SDouglas Gilbert 			goto fini;
4657f0d1cf93SDouglas Gilbert 		}
4658f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4659f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4660f0d1cf93SDouglas Gilbert 		goto fini;
4661f0d1cf93SDouglas Gilbert 	}
4662f0d1cf93SDouglas Gilbert 
4663f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4664f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4665f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4666f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4667f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4668f0d1cf93SDouglas Gilbert 		goto fini;
4669f0d1cf93SDouglas Gilbert 	}
4670f0d1cf93SDouglas Gilbert 
4671f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4672f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4673f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4674f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4675f0d1cf93SDouglas Gilbert 		goto fini;
4676f0d1cf93SDouglas Gilbert 	}
4677f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4678f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4679f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4680f0d1cf93SDouglas Gilbert 		goto fini;
4681f0d1cf93SDouglas Gilbert 	}
4682f0d1cf93SDouglas Gilbert 
4683f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4684f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4685f0d1cf93SDouglas Gilbert 		goto fini;
4686f0d1cf93SDouglas Gilbert 
4687f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4688f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4689f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4690f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4691f0d1cf93SDouglas Gilbert 		goto fini;
4692f0d1cf93SDouglas Gilbert 	}
4693f0d1cf93SDouglas Gilbert 
4694f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4695f0d1cf93SDouglas Gilbert fini:
46967109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4697f0d1cf93SDouglas Gilbert 	return res;
4698f0d1cf93SDouglas Gilbert }
4699f0d1cf93SDouglas Gilbert 
4700f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4701f0d1cf93SDouglas Gilbert {
4702f0d1cf93SDouglas Gilbert 	unsigned int i;
4703f0d1cf93SDouglas Gilbert 
4704f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4705f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4706f0d1cf93SDouglas Gilbert }
4707f0d1cf93SDouglas Gilbert 
4708f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4709f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4710f0d1cf93SDouglas Gilbert {
4711f0d1cf93SDouglas Gilbert 	int res = 0;
4712f0d1cf93SDouglas Gilbert 	u64 z_id;
4713f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4714f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4715f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4716b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4717f0d1cf93SDouglas Gilbert 
4718f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4719f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4720f0d1cf93SDouglas Gilbert 		return check_condition_result;
4721f0d1cf93SDouglas Gilbert 	}
4722f0d1cf93SDouglas Gilbert 
47237109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4724f0d1cf93SDouglas Gilbert 
4725f0d1cf93SDouglas Gilbert 	if (all) {
4726f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4727f0d1cf93SDouglas Gilbert 		goto fini;
4728f0d1cf93SDouglas Gilbert 	}
4729f0d1cf93SDouglas Gilbert 
4730f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4731f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4732f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4733f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4734f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4735f0d1cf93SDouglas Gilbert 		goto fini;
4736f0d1cf93SDouglas Gilbert 	}
4737f0d1cf93SDouglas Gilbert 
4738f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4739f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4740f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4741f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4742f0d1cf93SDouglas Gilbert 		goto fini;
4743f0d1cf93SDouglas Gilbert 	}
4744f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4745f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4746f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4747f0d1cf93SDouglas Gilbert 		goto fini;
4748f0d1cf93SDouglas Gilbert 	}
4749f0d1cf93SDouglas Gilbert 
4750f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4751f0d1cf93SDouglas Gilbert fini:
47527109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4753f0d1cf93SDouglas Gilbert 	return res;
4754f0d1cf93SDouglas Gilbert }
4755f0d1cf93SDouglas Gilbert 
4756f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4757f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4758f0d1cf93SDouglas Gilbert {
4759f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4760f0d1cf93SDouglas Gilbert 
4761f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4762f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4763f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4764f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4765f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4766f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4767f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4768f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4769f0d1cf93SDouglas Gilbert 	}
4770f0d1cf93SDouglas Gilbert }
4771f0d1cf93SDouglas Gilbert 
4772f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4773f0d1cf93SDouglas Gilbert {
4774f0d1cf93SDouglas Gilbert 	unsigned int i;
4775f0d1cf93SDouglas Gilbert 
4776f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4777f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4778f0d1cf93SDouglas Gilbert }
4779f0d1cf93SDouglas Gilbert 
4780f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4781f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4782f0d1cf93SDouglas Gilbert {
4783f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4784f0d1cf93SDouglas Gilbert 	int res = 0;
4785f0d1cf93SDouglas Gilbert 	u64 z_id;
4786f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4787f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4788b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4789f0d1cf93SDouglas Gilbert 
4790f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4791f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4792f0d1cf93SDouglas Gilbert 		return check_condition_result;
4793f0d1cf93SDouglas Gilbert 	}
4794f0d1cf93SDouglas Gilbert 
47957109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4796f0d1cf93SDouglas Gilbert 
4797f0d1cf93SDouglas Gilbert 	if (all) {
4798f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4799f0d1cf93SDouglas Gilbert 		goto fini;
4800f0d1cf93SDouglas Gilbert 	}
4801f0d1cf93SDouglas Gilbert 
4802f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4803f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4804f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4805f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4806f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4807f0d1cf93SDouglas Gilbert 		goto fini;
4808f0d1cf93SDouglas Gilbert 	}
4809f0d1cf93SDouglas Gilbert 
4810f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4811f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4812f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4813f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4814f0d1cf93SDouglas Gilbert 		goto fini;
4815f0d1cf93SDouglas Gilbert 	}
4816f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4817f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4818f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4819f0d1cf93SDouglas Gilbert 		goto fini;
4820f0d1cf93SDouglas Gilbert 	}
4821f0d1cf93SDouglas Gilbert 
4822f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4823f0d1cf93SDouglas Gilbert fini:
48247109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4825f0d1cf93SDouglas Gilbert 	return res;
4826f0d1cf93SDouglas Gilbert }
4827f0d1cf93SDouglas Gilbert 
4828f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4829f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4830f0d1cf93SDouglas Gilbert {
4831f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
48322d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4833f0d1cf93SDouglas Gilbert 
48344a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
4835f0d1cf93SDouglas Gilbert 		return;
4836f0d1cf93SDouglas Gilbert 
4837f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4838f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4839f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4840f0d1cf93SDouglas Gilbert 
4841f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4842f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4843f0d1cf93SDouglas Gilbert 
48442d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
48452d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
48462d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
48472d62253eSShin'ichiro Kawasaki 
484864e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4849f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4850f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4851f0d1cf93SDouglas Gilbert }
4852f0d1cf93SDouglas Gilbert 
4853f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4854f0d1cf93SDouglas Gilbert {
4855f0d1cf93SDouglas Gilbert 	unsigned int i;
4856f0d1cf93SDouglas Gilbert 
4857f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4858f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4859f0d1cf93SDouglas Gilbert }
4860f0d1cf93SDouglas Gilbert 
4861f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4862f0d1cf93SDouglas Gilbert {
4863f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4864f0d1cf93SDouglas Gilbert 	int res = 0;
4865f0d1cf93SDouglas Gilbert 	u64 z_id;
4866f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4867f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4868b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4869f0d1cf93SDouglas Gilbert 
4870f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4871f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4872f0d1cf93SDouglas Gilbert 		return check_condition_result;
4873f0d1cf93SDouglas Gilbert 	}
4874f0d1cf93SDouglas Gilbert 
48757109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4876f0d1cf93SDouglas Gilbert 
4877f0d1cf93SDouglas Gilbert 	if (all) {
4878f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4879f0d1cf93SDouglas Gilbert 		goto fini;
4880f0d1cf93SDouglas Gilbert 	}
4881f0d1cf93SDouglas Gilbert 
4882f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4883f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4884f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4885f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4886f0d1cf93SDouglas Gilbert 		goto fini;
4887f0d1cf93SDouglas Gilbert 	}
4888f0d1cf93SDouglas Gilbert 
4889f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4890f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4891f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4892f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4893f0d1cf93SDouglas Gilbert 		goto fini;
4894f0d1cf93SDouglas Gilbert 	}
4895f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4896f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4897f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4898f0d1cf93SDouglas Gilbert 		goto fini;
4899f0d1cf93SDouglas Gilbert 	}
4900f0d1cf93SDouglas Gilbert 
4901f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4902f0d1cf93SDouglas Gilbert fini:
49037109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4904f0d1cf93SDouglas Gilbert 	return res;
4905f0d1cf93SDouglas Gilbert }
4906f0d1cf93SDouglas Gilbert 
4907c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4908c4837394SDouglas Gilbert {
4909c10fa55fSJohn Garry 	u16 hwq;
4910a6e76e6fSBart Van Assche 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4911c10fa55fSJohn Garry 
4912c10fa55fSJohn Garry 	hwq = blk_mq_unique_tag_to_hwq(tag);
4913c4837394SDouglas Gilbert 
4914458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4915458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4916458df78bSBart Van Assche 		hwq = 0;
4917f7c4cdc7SJohn Garry 
4918458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4919c4837394SDouglas Gilbert }
4920c4837394SDouglas Gilbert 
4921c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4922c10fa55fSJohn Garry {
4923a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4924c10fa55fSJohn Garry }
4925c10fa55fSJohn Garry 
4926c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4927fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
49281da177e4SLinus Torvalds {
49291107c7b2SJohn Garry 	struct sdebug_queued_cmd *sqcp = container_of(sd_dp, struct sdebug_queued_cmd, sd_dp);
4930c4837394SDouglas Gilbert 	int qc_idx;
4931cbf67842SDouglas Gilbert 	int retiring = 0;
49321107c7b2SJohn Garry 	unsigned long flags, iflags;
49331107c7b2SJohn Garry 	struct scsi_cmnd *scp = sqcp->scmd;
49341107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc;
49351107c7b2SJohn Garry 	bool aborted;
4936c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
49371da177e4SLinus Torvalds 
49381107c7b2SJohn Garry 	qc_idx = sd_dp->sqa_idx;
4939c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4940cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4941c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4942c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4943c4837394SDouglas Gilbert 	}
49441107c7b2SJohn Garry 	if (!scp) {
49451107c7b2SJohn Garry 		pr_err("scmd=NULL\n");
49461107c7b2SJohn Garry 		goto out;
49471107c7b2SJohn Garry 	}
4948c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4949c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
49501107c7b2SJohn Garry 		goto out;
49511da177e4SLinus Torvalds 	}
49521107c7b2SJohn Garry 
49531107c7b2SJohn Garry 	sdsc = scsi_cmd_priv(scp);
49541107c7b2SJohn Garry 	sqp = get_queue(scp);
4955c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
49561107c7b2SJohn Garry 	spin_lock_irqsave(&sdsc->lock, flags);
49571107c7b2SJohn Garry 	aborted = sd_dp->aborted;
49581107c7b2SJohn Garry 	if (unlikely(aborted))
49591107c7b2SJohn Garry 		sd_dp->aborted = false;
49601107c7b2SJohn Garry 	ASSIGN_QUEUED_CMD(scp, NULL);
4961151f0ec9SJohn Garry 
4962f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4963cbf67842SDouglas Gilbert 		retiring = 1;
4964cbf67842SDouglas Gilbert 
49651107c7b2SJohn Garry 	sqp->qc_arr[qc_idx] = NULL;
4966c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
49671107c7b2SJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
4968c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
49691107c7b2SJohn Garry 		pr_err("Unexpected completion qc_idx=%d\n", qc_idx);
49701107c7b2SJohn Garry 		goto out;
49711da177e4SLinus Torvalds 	}
49721da177e4SLinus Torvalds 
4973cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4974cbf67842SDouglas Gilbert 		int k, retval;
4975cbf67842SDouglas Gilbert 
4976cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4977c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
49781107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
4979c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4980c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
49811107c7b2SJohn Garry 			goto out;
4982cbf67842SDouglas Gilbert 		}
4983c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4984773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4985cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4986cbf67842SDouglas Gilbert 		else
4987cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4988cbf67842SDouglas Gilbert 	}
49891107c7b2SJohn Garry 
49901107c7b2SJohn Garry 	spin_unlock_irqrestore(&sdsc->lock, flags);
4991c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
49921107c7b2SJohn Garry 
49931107c7b2SJohn Garry 	if (aborted) {
4994f037b5cbSJohn Garry 		pr_info("bypassing scsi_done() due to aborted cmd, kicking-off EH\n");
4995f037b5cbSJohn Garry 		blk_abort_request(scsi_cmd_to_rq(scp));
49961107c7b2SJohn Garry 		goto out;
49977382f9d8SDouglas Gilbert 	}
49981107c7b2SJohn Garry 
49996c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
50001107c7b2SJohn Garry out:
50011107c7b2SJohn Garry 	sdebug_free_queued_cmd(sqcp);
5002cbf67842SDouglas Gilbert }
5003cbf67842SDouglas Gilbert 
5004cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
5005fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
5006cbf67842SDouglas Gilbert {
5007a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
5008a10bc12aSDouglas Gilbert 						  hrt);
5009a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5010cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
5011cbf67842SDouglas Gilbert }
50121da177e4SLinus Torvalds 
5013a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
5014fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
5015a10bc12aSDouglas Gilbert {
5016a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
5017a10bc12aSDouglas Gilbert 						  ew.work);
5018a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
5019a10bc12aSDouglas Gilbert }
5020a10bc12aSDouglas Gilbert 
502109ba24c1SDouglas Gilbert static bool got_shared_uuid;
5022bf476433SChristoph Hellwig static uuid_t shared_uuid;
502309ba24c1SDouglas Gilbert 
5024f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
5025f0d1cf93SDouglas Gilbert {
5026f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
5027f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
50284a5fc1c6SDamien Le Moal 	sector_t conv_capacity;
5029f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
5030f0d1cf93SDouglas Gilbert 	unsigned int i;
5031f0d1cf93SDouglas Gilbert 
5032f0d1cf93SDouglas Gilbert 	/*
503398e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
503498e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
5035f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
5036f0d1cf93SDouglas Gilbert 	 * created for the device.
5037f0d1cf93SDouglas Gilbert 	 */
503898e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
5039f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
5040f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5041f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
5042f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
5043f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
5044f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
5045f0d1cf93SDouglas Gilbert 			return -EINVAL;
5046f0d1cf93SDouglas Gilbert 		}
5047f0d1cf93SDouglas Gilbert 	} else {
5048108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
5049108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
5050108e36f0SDamien Le Moal 			return -EINVAL;
5051108e36f0SDamien Le Moal 		}
505298e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
5053f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
5054f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
5055f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
5056f0d1cf93SDouglas Gilbert 			return -EINVAL;
5057f0d1cf93SDouglas Gilbert 		}
5058f0d1cf93SDouglas Gilbert 	}
5059f0d1cf93SDouglas Gilbert 
5060f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
5061f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
5062f0d1cf93SDouglas Gilbert 
50634a5fc1c6SDamien Le Moal 	if (sdeb_zbc_zone_cap_mb == 0) {
50644a5fc1c6SDamien Le Moal 		devip->zcap = devip->zsize;
50654a5fc1c6SDamien Le Moal 	} else {
50664a5fc1c6SDamien Le Moal 		devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >>
50674a5fc1c6SDamien Le Moal 			      ilog2(sdebug_sector_size);
50684a5fc1c6SDamien Le Moal 		if (devip->zcap > devip->zsize) {
50694a5fc1c6SDamien Le Moal 			pr_err("Zone capacity too large\n");
50704a5fc1c6SDamien Le Moal 			return -EINVAL;
50714a5fc1c6SDamien Le Moal 		}
50724a5fc1c6SDamien Le Moal 	}
50734a5fc1c6SDamien Le Moal 
50744a5fc1c6SDamien Le Moal 	conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift;
50754a5fc1c6SDamien Le Moal 	if (conv_capacity >= capacity) {
5076aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
5077aa8fecf9SDamien Le Moal 		return -EINVAL;
5078aa8fecf9SDamien Le Moal 	}
5079aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
50804a5fc1c6SDamien Le Moal 	devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >>
50814a5fc1c6SDamien Le Moal 			      devip->zsize_shift;
50824a5fc1c6SDamien Le Moal 	devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones;
50834a5fc1c6SDamien Le Moal 
50844a5fc1c6SDamien Le Moal 	/* Add gap zones if zone capacity is smaller than the zone size */
50854a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
50864a5fc1c6SDamien Le Moal 		devip->nr_zones += devip->nr_seq_zones;
5087aa8fecf9SDamien Le Moal 
508864e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
508964e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
5090380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
5091f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
5092f0d1cf93SDouglas Gilbert 		else
5093380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
509464e14eceSDamien Le Moal 	}
5095f0d1cf93SDouglas Gilbert 
5096f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
5097f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
5098f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
5099f0d1cf93SDouglas Gilbert 		return -ENOMEM;
5100f0d1cf93SDouglas Gilbert 
5101f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
5102f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
5103f0d1cf93SDouglas Gilbert 
5104f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
5105f0d1cf93SDouglas Gilbert 
5106aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
510735dbe2b9SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_CNV;
5108f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
5109f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
51104a5fc1c6SDamien Le Moal 			zsp->z_size =
51114a5fc1c6SDamien Le Moal 				min_t(u64, devip->zsize, capacity - zstart);
51124a5fc1c6SDamien Le Moal 		} else if ((zstart & (devip->zsize - 1)) == 0) {
511364e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
511435dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWR;
511564e14eceSDamien Le Moal 			else
511635dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWP;
5117f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
5118f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
51194a5fc1c6SDamien Le Moal 			zsp->z_size =
51204a5fc1c6SDamien Le Moal 				min_t(u64, devip->zcap, capacity - zstart);
51214a5fc1c6SDamien Le Moal 		} else {
51224a5fc1c6SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_GAP;
51234a5fc1c6SDamien Le Moal 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
51244a5fc1c6SDamien Le Moal 			zsp->z_wp = (sector_t)-1;
51254a5fc1c6SDamien Le Moal 			zsp->z_size = min_t(u64, devip->zsize - devip->zcap,
51264a5fc1c6SDamien Le Moal 					    capacity - zstart);
5127f0d1cf93SDouglas Gilbert 		}
5128f0d1cf93SDouglas Gilbert 
51294a5fc1c6SDamien Le Moal 		WARN_ON_ONCE((int)zsp->z_size <= 0);
5130f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
5131f0d1cf93SDouglas Gilbert 	}
5132f0d1cf93SDouglas Gilbert 
5133f0d1cf93SDouglas Gilbert 	return 0;
5134f0d1cf93SDouglas Gilbert }
5135f0d1cf93SDouglas Gilbert 
5136fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
5137fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
51385cb2fc06SFUJITA Tomonori {
51395cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
51405cb2fc06SFUJITA Tomonori 
51415cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
51425cb2fc06SFUJITA Tomonori 	if (devip) {
514309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
5144bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
514509ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
514609ba24c1SDouglas Gilbert 			if (got_shared_uuid)
514709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
514809ba24c1SDouglas Gilbert 			else {
5149bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
515009ba24c1SDouglas Gilbert 				got_shared_uuid = true;
515109ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
515209ba24c1SDouglas Gilbert 			}
515309ba24c1SDouglas Gilbert 		}
51545cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
5155f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
515664e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
5157f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
5158f0d1cf93SDouglas Gilbert 				kfree(devip);
5159f0d1cf93SDouglas Gilbert 				return NULL;
5160f0d1cf93SDouglas Gilbert 			}
516164e14eceSDamien Le Moal 		} else {
516264e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
5163f0d1cf93SDouglas Gilbert 		}
5164fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
5165fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
51665cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
51675cb2fc06SFUJITA Tomonori 	}
51685cb2fc06SFUJITA Tomonori 	return devip;
51695cb2fc06SFUJITA Tomonori }
51705cb2fc06SFUJITA Tomonori 
5171f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
51721da177e4SLinus Torvalds {
51731da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51741da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
5175f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
51761da177e4SLinus Torvalds 
5177785d6b7cSJohn Garry 	sdbg_host = shost_to_sdebug_host(sdev->host);
5178ad0c7775SDouglas Gilbert 
51791da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
51801da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
51811da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
51821da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
51831da177e4SLinus Torvalds 			return devip;
51841da177e4SLinus Torvalds 		else {
51851da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
51861da177e4SLinus Torvalds 				open_devip = devip;
51871da177e4SLinus Torvalds 		}
51881da177e4SLinus Torvalds 	}
51895cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
51905cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
51915cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5192c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51931da177e4SLinus Torvalds 			return NULL;
51941da177e4SLinus Torvalds 		}
51951da177e4SLinus Torvalds 	}
5196a75869d1SFUJITA Tomonori 
51971da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
51981da177e4SLinus Torvalds 	open_devip->target = sdev->id;
51991da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
52001da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5201500d0d24SDouglas Gilbert 	set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
5202c2248fc9SDouglas Gilbert 	open_devip->used = true;
52031da177e4SLinus Torvalds 	return open_devip;
52041da177e4SLinus Torvalds }
52051da177e4SLinus Torvalds 
52068dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
52071da177e4SLinus Torvalds {
5208773642d9SDouglas Gilbert 	if (sdebug_verbose)
5209c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
52108dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52118dea0d02SFUJITA Tomonori 	return 0;
52128dea0d02SFUJITA Tomonori }
52131da177e4SLinus Torvalds 
52148dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
52158dea0d02SFUJITA Tomonori {
5216f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5217f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5218a34c4e98SFUJITA Tomonori 
5219773642d9SDouglas Gilbert 	if (sdebug_verbose)
5220c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
52218dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5222b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5223b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5224b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5225f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5226b01f6f83SDouglas Gilbert 		if (devip == NULL)
52278dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5228f46eb0e9SDouglas Gilbert 	}
5229c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5230773642d9SDouglas Gilbert 	if (sdebug_no_uld)
523178d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
52329b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
52338dea0d02SFUJITA Tomonori 	return 0;
52348dea0d02SFUJITA Tomonori }
52358dea0d02SFUJITA Tomonori 
52368dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
52378dea0d02SFUJITA Tomonori {
52388dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
52398dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
52408dea0d02SFUJITA Tomonori 
5241773642d9SDouglas Gilbert 	if (sdebug_verbose)
5242c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
52438dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
52448dea0d02SFUJITA Tomonori 	if (devip) {
524525985edcSLucas De Marchi 		/* make this slot available for re-use */
5246c2248fc9SDouglas Gilbert 		devip->used = false;
52478dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
52488dea0d02SFUJITA Tomonori 	}
52498dea0d02SFUJITA Tomonori }
52508dea0d02SFUJITA Tomonori 
52511107c7b2SJohn Garry /* Returns true if we require the queued memory to be freed by the caller. */
52521107c7b2SJohn Garry static bool stop_qc_helper(struct sdebug_defer *sd_dp,
525310bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5254c4837394SDouglas Gilbert {
52551107c7b2SJohn Garry 	if (defer_t == SDEB_DEFER_HRT) {
52561107c7b2SJohn Garry 		int res = hrtimer_try_to_cancel(&sd_dp->hrt);
5257c4837394SDouglas Gilbert 
52581107c7b2SJohn Garry 		switch (res) {
52591107c7b2SJohn Garry 		case 0: /* Not active, it must have already run */
52601107c7b2SJohn Garry 		case -1: /* -1 It's executing the CB */
52611107c7b2SJohn Garry 			return false;
52621107c7b2SJohn Garry 		case 1: /* Was active, we've now cancelled */
52631107c7b2SJohn Garry 		default:
5264a10bc12aSDouglas Gilbert 			return true;
52658dea0d02SFUJITA Tomonori 		}
52661107c7b2SJohn Garry 	} else if (defer_t == SDEB_DEFER_WQ) {
52671107c7b2SJohn Garry 		/* Cancel if pending */
52681107c7b2SJohn Garry 		if (cancel_work_sync(&sd_dp->ew.work))
52691107c7b2SJohn Garry 			return true;
52701107c7b2SJohn Garry 		/* Was not pending, so it must have run */
52711107c7b2SJohn Garry 		return false;
52721107c7b2SJohn Garry 	} else if (defer_t == SDEB_DEFER_POLL) {
52731107c7b2SJohn Garry 		return true;
5274cbf67842SDouglas Gilbert 	}
52751107c7b2SJohn Garry 
52761107c7b2SJohn Garry 	return false;
52771107c7b2SJohn Garry }
52781107c7b2SJohn Garry 
52791107c7b2SJohn Garry 
52801107c7b2SJohn Garry static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd, int *sqa_idx)
52811107c7b2SJohn Garry {
52821107c7b2SJohn Garry 	enum sdeb_defer_type l_defer_t;
52831107c7b2SJohn Garry 	struct sdebug_queued_cmd *sqcp;
52841107c7b2SJohn Garry 	struct sdebug_defer *sd_dp;
52851107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
52861107c7b2SJohn Garry 
52871107c7b2SJohn Garry 	lockdep_assert_held(&sdsc->lock);
52881107c7b2SJohn Garry 
52891107c7b2SJohn Garry 	sqcp = TO_QUEUED_CMD(cmnd);
52901107c7b2SJohn Garry 	if (!sqcp)
52911107c7b2SJohn Garry 		return false;
52921107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
52931107c7b2SJohn Garry 	if (sqa_idx)
52941107c7b2SJohn Garry 		*sqa_idx = sd_dp->sqa_idx;
52951107c7b2SJohn Garry 	l_defer_t = READ_ONCE(sd_dp->defer_t);
52961107c7b2SJohn Garry 	ASSIGN_QUEUED_CMD(cmnd, NULL);
52971107c7b2SJohn Garry 
52981107c7b2SJohn Garry 	if (stop_qc_helper(sd_dp, l_defer_t))
52991107c7b2SJohn Garry 		sdebug_free_queued_cmd(sqcp);
53001107c7b2SJohn Garry 
53011107c7b2SJohn Garry 	return true;
53021107c7b2SJohn Garry }
53031107c7b2SJohn Garry 
53041107c7b2SJohn Garry /*
53051107c7b2SJohn Garry  * Called from scsi_debug_abort() only, which is for timed-out cmd.
53061107c7b2SJohn Garry  */
53071107c7b2SJohn Garry static bool scsi_debug_abort_cmnd(struct scsi_cmnd *cmnd)
53081107c7b2SJohn Garry {
53091107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
53101107c7b2SJohn Garry 	struct sdebug_queue *sqp = get_queue(cmnd);
53111107c7b2SJohn Garry 	unsigned long flags, iflags;
53121107c7b2SJohn Garry 	int k = -1;
53131107c7b2SJohn Garry 	bool res;
53141107c7b2SJohn Garry 
53151107c7b2SJohn Garry 	spin_lock_irqsave(&sdsc->lock, flags);
53161107c7b2SJohn Garry 	res = scsi_debug_stop_cmnd(cmnd, &k);
53171107c7b2SJohn Garry 	spin_unlock_irqrestore(&sdsc->lock, flags);
53181107c7b2SJohn Garry 
53191107c7b2SJohn Garry 	if (k >= 0) {
53201107c7b2SJohn Garry 		spin_lock_irqsave(&sqp->qc_lock, iflags);
53211107c7b2SJohn Garry 		clear_bit(k, sqp->in_use_bm);
53221107c7b2SJohn Garry 		sqp->qc_arr[k] = NULL;
5323c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5324c4837394SDouglas Gilbert 	}
53251107c7b2SJohn Garry 
53261107c7b2SJohn Garry 	return res;
53278dea0d02SFUJITA Tomonori }
53288dea0d02SFUJITA Tomonori 
5329a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
5330f19fe8f3SBart Van Assche static void stop_all_queued(void)
53318dea0d02SFUJITA Tomonori {
53321107c7b2SJohn Garry 	unsigned long iflags, flags;
5333c4837394SDouglas Gilbert 	int j, k;
5334c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
53358dea0d02SFUJITA Tomonori 
5336c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5337c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5338c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5339c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
53401107c7b2SJohn Garry 				struct sdebug_queued_cmd *sqcp = sqp->qc_arr[k];
53411107c7b2SJohn Garry 				struct sdebug_scsi_cmd *sdsc;
53421107c7b2SJohn Garry 				struct scsi_cmnd *scmd;
53431107c7b2SJohn Garry 
53441107c7b2SJohn Garry 				if (!sqcp)
5345a10bc12aSDouglas Gilbert 					continue;
53461107c7b2SJohn Garry 				scmd = sqcp->scmd;
53471107c7b2SJohn Garry 				if (!scmd)
53481107c7b2SJohn Garry 					continue;
53491107c7b2SJohn Garry 				sdsc = scsi_cmd_priv(scmd);
53501107c7b2SJohn Garry 				spin_lock_irqsave(&sdsc->lock, flags);
53511107c7b2SJohn Garry 				if (TO_QUEUED_CMD(scmd) != sqcp) {
53521107c7b2SJohn Garry 					spin_unlock_irqrestore(&sdsc->lock, flags);
53531107c7b2SJohn Garry 					continue;
53541107c7b2SJohn Garry 				}
53551107c7b2SJohn Garry 				scsi_debug_stop_cmnd(scmd, NULL);
53561107c7b2SJohn Garry 				spin_unlock_irqrestore(&sdsc->lock, flags);
53571107c7b2SJohn Garry 				sqp->qc_arr[k] = NULL;
5358c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
53598dea0d02SFUJITA Tomonori 			}
53608dea0d02SFUJITA Tomonori 		}
5361c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5362c4837394SDouglas Gilbert 	}
5363cbf67842SDouglas Gilbert }
5364cbf67842SDouglas Gilbert 
53651da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
53661da177e4SLinus Torvalds {
53671107c7b2SJohn Garry 	bool ok = scsi_debug_abort_cmnd(SCpnt);
5368a10bc12aSDouglas Gilbert 
53691da177e4SLinus Torvalds 	++num_aborts;
537006be9fbeSJohn Garry 
537106be9fbeSJohn Garry 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5372a10bc12aSDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5373a10bc12aSDouglas Gilbert 			    "%s: command%s found\n", __func__,
5374a10bc12aSDouglas Gilbert 			    ok ? "" : " not");
537506be9fbeSJohn Garry 
53761da177e4SLinus Torvalds 	return SUCCESS;
53771da177e4SLinus Torvalds }
53781da177e4SLinus Torvalds 
53791da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
53801da177e4SLinus Torvalds {
5381cbf67842SDouglas Gilbert 	struct scsi_device *sdp = SCpnt->device;
5382a19226f8SJohn Garry 	struct sdebug_dev_info *devip = sdp->hostdata;
5383a19226f8SJohn Garry 
5384a19226f8SJohn Garry 	++num_dev_resets;
5385cbf67842SDouglas Gilbert 
5386773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5387cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
53881da177e4SLinus Torvalds 	if (devip)
5389cbf67842SDouglas Gilbert 		set_bit(SDEBUG_UA_POR, devip->uas_bm);
5390a19226f8SJohn Garry 
53911da177e4SLinus Torvalds 	return SUCCESS;
53921da177e4SLinus Torvalds }
53931da177e4SLinus Torvalds 
5394cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5395cbf67842SDouglas Gilbert {
5396a15df530SJohn Garry 	struct scsi_device *sdp = SCpnt->device;
5397a15df530SJohn Garry 	struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host);
5398cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5399cbf67842SDouglas Gilbert 	int k = 0;
5400cbf67842SDouglas Gilbert 
5401cbf67842SDouglas Gilbert 	++num_target_resets;
5402773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5403cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5404a15df530SJohn Garry 
5405a15df530SJohn Garry 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
5406cbf67842SDouglas Gilbert 		if (devip->target == sdp->id) {
5407cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5408cbf67842SDouglas Gilbert 			++k;
5409cbf67842SDouglas Gilbert 		}
5410cbf67842SDouglas Gilbert 	}
5411a15df530SJohn Garry 
5412773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5413cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5414cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5415a15df530SJohn Garry 
5416cbf67842SDouglas Gilbert 	return SUCCESS;
5417cbf67842SDouglas Gilbert }
5418cbf67842SDouglas Gilbert 
54191da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
54201da177e4SLinus Torvalds {
5421519bfc14SJohn Garry 	struct scsi_device *sdp = SCpnt->device;
5422519bfc14SJohn Garry 	struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host);
5423cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5424cbf67842SDouglas Gilbert 	int k = 0;
54251da177e4SLinus Torvalds 
54261da177e4SLinus Torvalds 	++num_bus_resets;
5427519bfc14SJohn Garry 
5428773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5429cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5430519bfc14SJohn Garry 
5431519bfc14SJohn Garry 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
5432cbf67842SDouglas Gilbert 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5433cbf67842SDouglas Gilbert 		++k;
54341da177e4SLinus Torvalds 	}
5435519bfc14SJohn Garry 
5436773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5437cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5438cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
54391da177e4SLinus Torvalds 	return SUCCESS;
54401da177e4SLinus Torvalds }
54411da177e4SLinus Torvalds 
54421da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
54431da177e4SLinus Torvalds {
54441da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5445cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5446cbf67842SDouglas Gilbert 	int k = 0;
54471da177e4SLinus Torvalds 
54481da177e4SLinus Torvalds 	++num_host_resets;
54499c230382SJohn Garry 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5450cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
54510aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
54521da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5453cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5454cbf67842SDouglas Gilbert 				    dev_list) {
5455cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5456cbf67842SDouglas Gilbert 			++k;
5457cbf67842SDouglas Gilbert 		}
54581da177e4SLinus Torvalds 	}
54590aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
5460f19fe8f3SBart Van Assche 	stop_all_queued();
5461773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5462cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5463cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
54641da177e4SLinus Torvalds 	return SUCCESS;
54651da177e4SLinus Torvalds }
54661da177e4SLinus Torvalds 
546787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
54681da177e4SLinus Torvalds {
54691442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5470979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
54711da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
54721da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
54731da177e4SLinus Torvalds 
54741da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5475773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
54761da177e4SLinus Torvalds 		return;
5477773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5478773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5479c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
54801da177e4SLinus Torvalds 	}
54818c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
54821da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5483773642d9SDouglas Gilbert 			   / sdebug_num_parts;
54841da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
54851da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5486979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5487979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
54881da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
54891da177e4SLinus Torvalds 			    * heads_by_sects;
5490979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5491979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5492979e0dc3SJohn Pittman 	}
5493773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5494773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
54951da177e4SLinus Torvalds 
54961da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
54971da177e4SLinus Torvalds 	ramp[511] = 0xAA;
54981442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
54991da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
55001da177e4SLinus Torvalds 		start_sec = starts[k];
5501979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
55021da177e4SLinus Torvalds 		pp->boot_ind = 0;
55031da177e4SLinus Torvalds 
55041da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
55051da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
55061da177e4SLinus Torvalds 			   / sdebug_sectors_per;
55071da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
55081da177e4SLinus Torvalds 
55091da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
55101da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
55111da177e4SLinus Torvalds 			       / sdebug_sectors_per;
55121da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
55131da177e4SLinus Torvalds 
5514150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5515150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
55161da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
55171da177e4SLinus Torvalds 	}
55181da177e4SLinus Torvalds }
55191da177e4SLinus Torvalds 
5520f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block)
5521c4837394SDouglas Gilbert {
5522a0473bf3SJohn Garry 	struct sdebug_host_info *sdhp;
5523c4837394SDouglas Gilbert 
552425b80b2cSJohn Garry 	lockdep_assert_held(&sdebug_host_list_mutex);
552525b80b2cSJohn Garry 
5526a0473bf3SJohn Garry 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
5527a0473bf3SJohn Garry 		struct Scsi_Host *shost = sdhp->shost;
5528a0473bf3SJohn Garry 
5529a0473bf3SJohn Garry 		if (block)
5530a0473bf3SJohn Garry 			scsi_block_requests(shost);
5531a0473bf3SJohn Garry 		else
5532a0473bf3SJohn Garry 			scsi_unblock_requests(shost);
5533a0473bf3SJohn Garry 	}
5534c4837394SDouglas Gilbert }
5535c4837394SDouglas Gilbert 
5536c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5537c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5538c4837394SDouglas Gilbert  */
5539c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5540c4837394SDouglas Gilbert {
5541c4837394SDouglas Gilbert 	int count, modulo;
5542c4837394SDouglas Gilbert 
5543c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5544c4837394SDouglas Gilbert 	if (modulo < 2)
5545c4837394SDouglas Gilbert 		return;
554625b80b2cSJohn Garry 
554725b80b2cSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
5548f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
5549c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5550c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5551f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
555225b80b2cSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
5553c4837394SDouglas Gilbert }
5554c4837394SDouglas Gilbert 
5555c4837394SDouglas Gilbert static void clear_queue_stats(void)
5556c4837394SDouglas Gilbert {
5557c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5558c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5559c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5560c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5561c4837394SDouglas Gilbert }
5562c4837394SDouglas Gilbert 
55633a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5564c4837394SDouglas Gilbert {
55653a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
55663a90a63dSDouglas Gilbert 		return false;
55673a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5568c4837394SDouglas Gilbert }
5569c4837394SDouglas Gilbert 
5570a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5571a2aede97SDouglas Gilbert 
55721107c7b2SJohn Garry 
55731107c7b2SJohn Garry void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp)
55741107c7b2SJohn Garry {
55751107c7b2SJohn Garry 	if (sqcp)
55761107c7b2SJohn Garry 		kmem_cache_free(queued_cmd_cache, sqcp);
55771107c7b2SJohn Garry }
55781107c7b2SJohn Garry 
55791107c7b2SJohn Garry static struct sdebug_queued_cmd *sdebug_alloc_queued_cmd(struct scsi_cmnd *scmd)
55801107c7b2SJohn Garry {
55811107c7b2SJohn Garry 	struct sdebug_queued_cmd *sqcp;
55821107c7b2SJohn Garry 	struct sdebug_defer *sd_dp;
55831107c7b2SJohn Garry 
55841107c7b2SJohn Garry 	sqcp = kmem_cache_zalloc(queued_cmd_cache, GFP_ATOMIC);
55851107c7b2SJohn Garry 	if (!sqcp)
55861107c7b2SJohn Garry 		return NULL;
55871107c7b2SJohn Garry 
55881107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
55891107c7b2SJohn Garry 
55901107c7b2SJohn Garry 	hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
55911107c7b2SJohn Garry 	sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
55921107c7b2SJohn Garry 	INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
55931107c7b2SJohn Garry 
55941107c7b2SJohn Garry 	sqcp->scmd = scmd;
55951107c7b2SJohn Garry 	sd_dp->sqa_idx = -1;
55961107c7b2SJohn Garry 
55971107c7b2SJohn Garry 	return sqcp;
55981107c7b2SJohn Garry }
55991107c7b2SJohn Garry 
5600c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5601c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5602c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5603c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5604c4837394SDouglas Gilbert  */
5605fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5606f66b8517SMartin Wilck 			 int scsi_result,
5607f19fe8f3SBart Van Assche 			 int (*pfp)(struct scsi_cmnd *,
5608f19fe8f3SBart Van Assche 				    struct sdebug_dev_info *),
5609f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
56101da177e4SLinus Torvalds {
56111107c7b2SJohn Garry 	struct request *rq = scsi_cmd_to_rq(cmnd);
56121107c7b2SJohn Garry 	bool polled = rq->cmd_flags & REQ_POLLED;
56131107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
56141107c7b2SJohn Garry 	unsigned long iflags, flags;
5615a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5616c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5617c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5618299b6c07STomas Winkler 	struct scsi_device *sdp;
5619a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
56201107c7b2SJohn Garry 	int k;
56211da177e4SLinus Torvalds 
5622b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5623b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5624f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5625f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
56261da177e4SLinus Torvalds 	}
5627299b6c07STomas Winkler 	sdp = cmnd->device;
5628299b6c07STomas Winkler 
5629f19fe8f3SBart Van Assche 	if (delta_jiff == 0)
5630cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56311da177e4SLinus Torvalds 
5632c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5633c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5634151f0ec9SJohn Garry 
56350befb879SJohn Garry 	if (unlikely(sdebug_every_nth && (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5636f46eb0e9SDouglas Gilbert 		     (scsi_result == 0))) {
5637151f0ec9SJohn Garry 		int num_in_q = scsi_device_busy(sdp);
5638151f0ec9SJohn Garry 		int qdepth = cmnd->device->queue_depth;
5639151f0ec9SJohn Garry 
56406500d204SJohn Garry 		if ((num_in_q == qdepth) &&
5641cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5642773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5643cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
5644cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5645151f0ec9SJohn Garry 
5646151f0ec9SJohn Garry 			if (unlikely(SDEBUG_OPT_Q_NOISE & sdebug_opts))
5647151f0ec9SJohn Garry 				sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, <inject> status: TASK SET FULL\n",
5648151f0ec9SJohn Garry 					    __func__, num_in_q);
56491da177e4SLinus Torvalds 		}
5650cbf67842SDouglas Gilbert 	}
5651cbf67842SDouglas Gilbert 
5652c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5653f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5654c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5655cd62b7daSDouglas Gilbert 		if (scsi_result)
5656cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5657cd62b7daSDouglas Gilbert 		scsi_result = device_qfull_result;
5658773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
56597d5a129bSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
56607d5a129bSDouglas Gilbert 				    __func__, sdebug_max_queue);
5661cd62b7daSDouglas Gilbert 		goto respond_in_thread;
56621da177e4SLinus Torvalds 	}
566374595c04SDouglas Gilbert 	set_bit(k, sqp->in_use_bm);
5664c4b57d89SKashyap Desai 
56651107c7b2SJohn Garry 	sqcp = sdebug_alloc_queued_cmd(cmnd);
56661107c7b2SJohn Garry 	if (!sqcp) {
566774595c04SDouglas Gilbert 		clear_bit(k, sqp->in_use_bm);
56681107c7b2SJohn Garry 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
566910bde980SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
567074595c04SDouglas Gilbert 	}
56711107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
56721107c7b2SJohn Garry 	sd_dp->sqa_idx = k;
56731107c7b2SJohn Garry 	sqp->qc_arr[k] = sqcp;
56741107c7b2SJohn Garry 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5675f66b8517SMartin Wilck 
5676c10fa55fSJohn Garry 	/* Set the hostwide tag */
5677c10fa55fSJohn Garry 	if (sdebug_host_max_queue)
5678c10fa55fSJohn Garry 		sd_dp->hc_idx = get_tag(cmnd);
5679c10fa55fSJohn Garry 
56806ce913feSChristoph Hellwig 	if (polled)
5681a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5682a2aede97SDouglas Gilbert 
5683a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
56843a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5685f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5686f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5687f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5688f66b8517SMartin Wilck 	}
5689f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5690f66b8517SMartin Wilck 		cmnd->result = scsi_result;
56913a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
56923a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
56933a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
56943a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56953a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
56963a90a63dSDouglas Gilbert 		}
56973a90a63dSDouglas Gilbert 	}
5698f66b8517SMartin Wilck 
5699f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5700f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5701f66b8517SMartin Wilck 			    __func__, cmnd->result);
5702f66b8517SMartin Wilck 
570310bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5704b333a819SDouglas Gilbert 		ktime_t kt;
5705cbf67842SDouglas Gilbert 
5706b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
57070c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
57080c4bc91dSDouglas Gilbert 
57090c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
57108032bf12SJason A. Donenfeld 				ns = get_random_u32_below((u32)ns);
57110c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
57120c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
57130c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
57148032bf12SJason A. Donenfeld 					ns = get_random_u32_below((u32)ns);
57150c4bc91dSDouglas Gilbert 				ns <<= 12;
57160c4bc91dSDouglas Gilbert 			}
57170c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
57180c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
57198032bf12SJason A. Donenfeld 			kt = sdebug_random ? get_random_u32_below((u32)ndelay) :
57200c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5721a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5722a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5723a2aede97SDouglas Gilbert 
5724a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5725223f91b4SDouglas Gilbert 					spin_lock_irqsave(&sqp->qc_lock, iflags);
57261107c7b2SJohn Garry 					sqp->qc_arr[k] = NULL;
5727a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5728223f91b4SDouglas Gilbert 					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5729a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
57301107c7b2SJohn Garry 					sdebug_free_queued_cmd(sqcp);
57316c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5732a2aede97SDouglas Gilbert 					return 0;
5733a2aede97SDouglas Gilbert 				}
5734a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5735a2aede97SDouglas Gilbert 				kt -= d;
5736a2aede97SDouglas Gilbert 			}
57370c4bc91dSDouglas Gilbert 		}
57384a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
57394a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
57401107c7b2SJohn Garry 		if (polled) {
57411107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
57421107c7b2SJohn Garry 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
57431107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
57441107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57451107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
57461107c7b2SJohn Garry 		} else {
57471107c7b2SJohn Garry 			/* schedule the invocation of scsi_done() for a later time */
57481107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
57491107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
57501107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
57511107c7b2SJohn Garry 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
57521107c7b2SJohn Garry 			/*
57531107c7b2SJohn Garry 			 * The completion handler will try to grab sqcp->lock,
57541107c7b2SJohn Garry 			 * so there is no chance that the completion handler
57551107c7b2SJohn Garry 			 * will call scsi_done() until we release the lock
57561107c7b2SJohn Garry 			 * here (so ok to keep referencing sdsc).
57571107c7b2SJohn Garry 			 */
57581107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
57591107c7b2SJohn Garry 		}
5760c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
57614a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5762f037b5cbSJohn Garry 			     atomic_read(&sdeb_inject_pending))) {
57634a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
5764f037b5cbSJohn Garry 			atomic_set(&sdeb_inject_pending, 0);
5765f037b5cbSJohn Garry 			sdev_printk(KERN_INFO, sdp, "abort request tag=%#x\n",
5766f037b5cbSJohn Garry 				    blk_mq_unique_tag_to_tag(get_tag(cmnd)));
5767f037b5cbSJohn Garry 		}
5768f037b5cbSJohn Garry 
5769c4837394SDouglas Gilbert 		if (sdebug_statistics)
5770c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
57711107c7b2SJohn Garry 		if (polled) {
57721107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
57731107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
57741107c7b2SJohn Garry 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
57751107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
57761107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
57771107c7b2SJohn Garry 		} else {
57781107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
57791107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
57801107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
57811107c7b2SJohn Garry 			schedule_work(&sd_dp->ew.work);
57821107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
57831107c7b2SJohn Garry 		}
5784cbf67842SDouglas Gilbert 	}
5785151f0ec9SJohn Garry 
57861da177e4SLinus Torvalds 	return 0;
5787cd62b7daSDouglas Gilbert 
5788cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5789f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5790f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5791f19fe8f3SBart Van Assche 	if (cmnd->result == 0 && scsi_result != 0)
5792cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
57936c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5794cd62b7daSDouglas Gilbert 	return 0;
57951da177e4SLinus Torvalds }
5796cbf67842SDouglas Gilbert 
579723183910SDouglas Gilbert /* Note: The following macros create attribute files in the
579823183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
579923183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
580023183910SDouglas Gilbert    as it can when the corresponding attribute in the
580123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
580223183910SDouglas Gilbert  */
5803773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5804773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
58059b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5806773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5807c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5808773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5809773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5810773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5811773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5812773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5813773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5814773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5815773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5816c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5817e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5818e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5819e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5820e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
58215d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
58225d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
58235d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5824773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5825773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5826773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5827773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5828ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5829773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5830773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
58315d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
58325d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58335d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
58345d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5835773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5836773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
58377109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
5838773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5839773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5840773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5841773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
58425d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5843773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
584487c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
584587c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5846773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5847773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
58480c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5849773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5850773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5851773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5852c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5853773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5854c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5855c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5856fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5857773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5858773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5859773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5860773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
586109ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
58625d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5863773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
586423183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
58659447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5866773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
58675b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
58689267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
58694a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO);
5870380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5871aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
587298e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
58731da177e4SLinus Torvalds 
58741da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
58751da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
58761da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5877b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
58781da177e4SLinus Torvalds 
58795d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
58805b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
58819b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
58820759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5883cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5884c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
58855b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
58865b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5887c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5888beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
588923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
58905b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5891185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5892c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5893c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5894e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
58959b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
58969b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
58975d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
58985d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
58995d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
59005b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
59015b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
59025b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
59035b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5904ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5905fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5906cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5907d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
59085d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5909cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5910c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
59117109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
591278d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
59131da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5914c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
591532c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
591686e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
59175d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
59185d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
59195d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5920fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
59211da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
59220c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5923d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5924760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5925ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5926c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5927c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5928c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5929fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
59305b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
59315b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
59326014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
59336014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
593409ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
593509ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5936c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
59375b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
59389447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
59395b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
59409267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
59414a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)");
5942380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5943aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
594498e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
59451da177e4SLinus Torvalds 
5946760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5947760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
59481da177e4SLinus Torvalds 
59491da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
59501da177e4SLinus Torvalds {
5951c4837394SDouglas Gilbert 	int k;
5952c4837394SDouglas Gilbert 
5953760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5954760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5955760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5956c4837394SDouglas Gilbert 		return sdebug_info;
5957760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5958760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5959760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5960760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
59611da177e4SLinus Torvalds 	return sdebug_info;
59621da177e4SLinus Torvalds }
59631da177e4SLinus Torvalds 
5964cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5965fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5966fd32119bSDouglas Gilbert 				 int length)
59671da177e4SLinus Torvalds {
59681da177e4SLinus Torvalds 	char arr[16];
5969c8ed555aSAl Viro 	int opts;
59701da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
59711da177e4SLinus Torvalds 
59721da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
59731da177e4SLinus Torvalds 		return -EACCES;
59741da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
59751da177e4SLinus Torvalds 	arr[minLen] = '\0';
5976c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
59771da177e4SLinus Torvalds 		return -EINVAL;
5978773642d9SDouglas Gilbert 	sdebug_opts = opts;
5979773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5980773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5981773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5982c4837394SDouglas Gilbert 		tweak_cmnd_count();
59831da177e4SLinus Torvalds 	return length;
59841da177e4SLinus Torvalds }
5985c8ed555aSAl Viro 
5986cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5987cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5988cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5989c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5990c8ed555aSAl Viro {
5991c4837394SDouglas Gilbert 	int f, j, l;
5992c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
599387c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5994cbf67842SDouglas Gilbert 
5995c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5996c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5997c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5998c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5999c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
6000c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
6001c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
6002c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
6003c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
6004c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
6005c4837394SDouglas Gilbert 		   num_aborts);
6006c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
6007c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
6008c4837394SDouglas Gilbert 		   num_host_resets);
6009c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
6010c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
6011458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
6012458df78bSBart Van Assche 		   sdebug_statistics);
60134a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
6014c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
6015c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
6016c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
60174a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
60184a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
6019cbf67842SDouglas Gilbert 
6020c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
6021c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
6022c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
6023c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
6024773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
6025c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
6026c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
6027c4837394SDouglas Gilbert 				   "first,last bits", f, l);
6028c4837394SDouglas Gilbert 		}
6029cbf67842SDouglas Gilbert 	}
603087c715dcSDouglas Gilbert 
603187c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
603287c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
603387c715dcSDouglas Gilbert 		bool niu;
603487c715dcSDouglas Gilbert 		int idx;
603587c715dcSDouglas Gilbert 		unsigned long l_idx;
603687c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
603787c715dcSDouglas Gilbert 
603887c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
603987c715dcSDouglas Gilbert 		j = 0;
604087c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
604187c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
604287c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
604387c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
604487c715dcSDouglas Gilbert 			++j;
604587c715dcSDouglas Gilbert 		}
604687c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
604787c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
604887c715dcSDouglas Gilbert 		j = 0;
604987c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
605087c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
605187c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
605287c715dcSDouglas Gilbert 			idx = (int)l_idx;
605387c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
605487c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
605587c715dcSDouglas Gilbert 			++j;
605687c715dcSDouglas Gilbert 		}
605787c715dcSDouglas Gilbert 	}
6058c8ed555aSAl Viro 	return 0;
60591da177e4SLinus Torvalds }
60601da177e4SLinus Torvalds 
606182069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
60621da177e4SLinus Torvalds {
6063c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
60641da177e4SLinus Torvalds }
6065c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
6066c4837394SDouglas Gilbert  * of delay is jiffies.
6067c4837394SDouglas Gilbert  */
606882069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
606982069379SAkinobu Mita 			   size_t count)
60701da177e4SLinus Torvalds {
6071c2206098SDouglas Gilbert 	int jdelay, res;
60721da177e4SLinus Torvalds 
6073b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
6074cbf67842SDouglas Gilbert 		res = count;
6075c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
6076c4837394SDouglas Gilbert 			int j, k;
6077c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6078cbf67842SDouglas Gilbert 
607925b80b2cSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
6080f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6081c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6082c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6083c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6084c4837394SDouglas Gilbert 						   sdebug_max_queue);
6085c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6086c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6087c4837394SDouglas Gilbert 					break;
6088c4837394SDouglas Gilbert 				}
6089c4837394SDouglas Gilbert 			}
6090c4837394SDouglas Gilbert 			if (res > 0) {
6091c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
6092773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
60931da177e4SLinus Torvalds 			}
6094f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
609525b80b2cSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
6096cbf67842SDouglas Gilbert 		}
6097cbf67842SDouglas Gilbert 		return res;
60981da177e4SLinus Torvalds 	}
60991da177e4SLinus Torvalds 	return -EINVAL;
61001da177e4SLinus Torvalds }
610182069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
61021da177e4SLinus Torvalds 
6103cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
6104cbf67842SDouglas Gilbert {
6105773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
6106cbf67842SDouglas Gilbert }
6107cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6108c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
6109cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6110cbf67842SDouglas Gilbert 			    size_t count)
6111cbf67842SDouglas Gilbert {
6112c4837394SDouglas Gilbert 	int ndelay, res;
6113cbf67842SDouglas Gilbert 
6114cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6115c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6116cbf67842SDouglas Gilbert 		res = count;
6117773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
6118c4837394SDouglas Gilbert 			int j, k;
6119c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
6120c4837394SDouglas Gilbert 
612125b80b2cSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
6122f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
6123c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6124c4837394SDouglas Gilbert 			     ++j, ++sqp) {
6125c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
6126c4837394SDouglas Gilbert 						   sdebug_max_queue);
6127c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
6128c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6129c4837394SDouglas Gilbert 					break;
6130c4837394SDouglas Gilbert 				}
6131c4837394SDouglas Gilbert 			}
6132c4837394SDouglas Gilbert 			if (res > 0) {
6133773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6134c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6135c2206098SDouglas Gilbert 							: DEF_JDELAY;
6136cbf67842SDouglas Gilbert 			}
6137f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
613825b80b2cSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
6139cbf67842SDouglas Gilbert 		}
6140cbf67842SDouglas Gilbert 		return res;
6141cbf67842SDouglas Gilbert 	}
6142cbf67842SDouglas Gilbert 	return -EINVAL;
6143cbf67842SDouglas Gilbert }
6144cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6145cbf67842SDouglas Gilbert 
614682069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
61471da177e4SLinus Torvalds {
6148773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
61491da177e4SLinus Torvalds }
61501da177e4SLinus Torvalds 
615182069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
615282069379SAkinobu Mita 			  size_t count)
61531da177e4SLinus Torvalds {
61541da177e4SLinus Torvalds 	int opts;
61551da177e4SLinus Torvalds 	char work[20];
61561da177e4SLinus Torvalds 
61579a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
61589a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
61599a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
61601da177e4SLinus Torvalds 				goto opts_done;
61611da177e4SLinus Torvalds 		} else {
61629a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
61631da177e4SLinus Torvalds 				goto opts_done;
61641da177e4SLinus Torvalds 		}
61651da177e4SLinus Torvalds 	}
61661da177e4SLinus Torvalds 	return -EINVAL;
61671da177e4SLinus Torvalds opts_done:
6168773642d9SDouglas Gilbert 	sdebug_opts = opts;
6169773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6170773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6171c4837394SDouglas Gilbert 	tweak_cmnd_count();
61721da177e4SLinus Torvalds 	return count;
61731da177e4SLinus Torvalds }
617482069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
61751da177e4SLinus Torvalds 
617682069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
61771da177e4SLinus Torvalds {
6178773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
61791da177e4SLinus Torvalds }
618082069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
618182069379SAkinobu Mita 			   size_t count)
61821da177e4SLinus Torvalds {
61831da177e4SLinus Torvalds 	int n;
61841da177e4SLinus Torvalds 
6185f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6186f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6187f0d1cf93SDouglas Gilbert 		return -EINVAL;
6188f0d1cf93SDouglas Gilbert 
61891da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6190f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6191f0d1cf93SDouglas Gilbert 			return -EINVAL;
6192773642d9SDouglas Gilbert 		sdebug_ptype = n;
61931da177e4SLinus Torvalds 		return count;
61941da177e4SLinus Torvalds 	}
61951da177e4SLinus Torvalds 	return -EINVAL;
61961da177e4SLinus Torvalds }
619782069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
61981da177e4SLinus Torvalds 
619982069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
62001da177e4SLinus Torvalds {
6201773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
62021da177e4SLinus Torvalds }
620382069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
620482069379SAkinobu Mita 			    size_t count)
62051da177e4SLinus Torvalds {
62061da177e4SLinus Torvalds 	int n;
62071da177e4SLinus Torvalds 
62081da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6209773642d9SDouglas Gilbert 		sdebug_dsense = n;
62101da177e4SLinus Torvalds 		return count;
62111da177e4SLinus Torvalds 	}
62121da177e4SLinus Torvalds 	return -EINVAL;
62131da177e4SLinus Torvalds }
621482069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
62151da177e4SLinus Torvalds 
621682069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
621723183910SDouglas Gilbert {
6218773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
621923183910SDouglas Gilbert }
622082069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
622182069379SAkinobu Mita 			     size_t count)
622223183910SDouglas Gilbert {
622387c715dcSDouglas Gilbert 	int n, idx;
622423183910SDouglas Gilbert 
622523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
622687c715dcSDouglas Gilbert 		bool want_store = (n == 0);
622787c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
622887c715dcSDouglas Gilbert 
6229cbf67842SDouglas Gilbert 		n = (n > 0);
6230773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
623187c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
623287c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6233cbf67842SDouglas Gilbert 
623487c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
623587c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
623687c715dcSDouglas Gilbert 				idx = sdebug_add_store();
623787c715dcSDouglas Gilbert 				if (idx < 0)
623887c715dcSDouglas Gilbert 					return idx;
623987c715dcSDouglas Gilbert 			} else {
624087c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
624187c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
624287c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6243cbf67842SDouglas Gilbert 			}
624487c715dcSDouglas Gilbert 			/* make all hosts use same store */
624587c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
624687c715dcSDouglas Gilbert 					    host_list) {
624787c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
624887c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
624987c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
625087c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
625187c715dcSDouglas Gilbert 				}
625287c715dcSDouglas Gilbert 			}
625387c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
625487c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
625587c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6256cbf67842SDouglas Gilbert 		}
6257773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
625823183910SDouglas Gilbert 		return count;
625923183910SDouglas Gilbert 	}
626023183910SDouglas Gilbert 	return -EINVAL;
626123183910SDouglas Gilbert }
626282069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
626323183910SDouglas Gilbert 
626482069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6265c65b1445SDouglas Gilbert {
6266773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6267c65b1445SDouglas Gilbert }
626882069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
626982069379SAkinobu Mita 			      size_t count)
6270c65b1445SDouglas Gilbert {
6271c65b1445SDouglas Gilbert 	int n;
6272c65b1445SDouglas Gilbert 
6273c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6274773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6275c65b1445SDouglas Gilbert 		return count;
6276c65b1445SDouglas Gilbert 	}
6277c65b1445SDouglas Gilbert 	return -EINVAL;
6278c65b1445SDouglas Gilbert }
627982069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6280c65b1445SDouglas Gilbert 
628182069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
62821da177e4SLinus Torvalds {
6283773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
62841da177e4SLinus Torvalds }
628582069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
628682069379SAkinobu Mita 			      size_t count)
62871da177e4SLinus Torvalds {
62881da177e4SLinus Torvalds 	int n;
62891da177e4SLinus Torvalds 
62901da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6291773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
62921da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
62931da177e4SLinus Torvalds 		return count;
62941da177e4SLinus Torvalds 	}
62951da177e4SLinus Torvalds 	return -EINVAL;
62961da177e4SLinus Torvalds }
629782069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
62981da177e4SLinus Torvalds 
629982069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
63001da177e4SLinus Torvalds {
6301773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
63021da177e4SLinus Torvalds }
630382069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
63041da177e4SLinus Torvalds 
630587c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
630687c715dcSDouglas Gilbert {
630787c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
630887c715dcSDouglas Gilbert }
630987c715dcSDouglas Gilbert 
631087c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
631187c715dcSDouglas Gilbert 				    size_t count)
631287c715dcSDouglas Gilbert {
631387c715dcSDouglas Gilbert 	bool v;
631487c715dcSDouglas Gilbert 
631587c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
631687c715dcSDouglas Gilbert 		return -EINVAL;
631787c715dcSDouglas Gilbert 
631887c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
631987c715dcSDouglas Gilbert 	return count;
632087c715dcSDouglas Gilbert }
632187c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
632287c715dcSDouglas Gilbert 
632382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
63241da177e4SLinus Torvalds {
6325773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
63261da177e4SLinus Torvalds }
632782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
63281da177e4SLinus Torvalds 
632982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
63301da177e4SLinus Torvalds {
6331773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
63321da177e4SLinus Torvalds }
633382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
633482069379SAkinobu Mita 			       size_t count)
63351da177e4SLinus Torvalds {
63361da177e4SLinus Torvalds 	int nth;
63373a90a63dSDouglas Gilbert 	char work[20];
63381da177e4SLinus Torvalds 
63393a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
63403a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
63413a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
63423a90a63dSDouglas Gilbert 				goto every_nth_done;
63433a90a63dSDouglas Gilbert 		} else {
63443a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
63453a90a63dSDouglas Gilbert 				goto every_nth_done;
63463a90a63dSDouglas Gilbert 		}
63473a90a63dSDouglas Gilbert 	}
63483a90a63dSDouglas Gilbert 	return -EINVAL;
63493a90a63dSDouglas Gilbert 
63503a90a63dSDouglas Gilbert every_nth_done:
6351773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6352c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6353c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6354c4837394SDouglas Gilbert 		sdebug_statistics = true;
6355c4837394SDouglas Gilbert 	}
6356c4837394SDouglas Gilbert 	tweak_cmnd_count();
63571da177e4SLinus Torvalds 	return count;
63581da177e4SLinus Torvalds }
635982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
63601da177e4SLinus Torvalds 
6361ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6362ad0c7775SDouglas Gilbert {
6363ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6364ad0c7775SDouglas Gilbert }
6365ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6366ad0c7775SDouglas Gilbert 				size_t count)
6367ad0c7775SDouglas Gilbert {
6368ad0c7775SDouglas Gilbert 	int n;
6369ad0c7775SDouglas Gilbert 	bool changed;
6370ad0c7775SDouglas Gilbert 
6371ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6372ad0c7775SDouglas Gilbert 		return -EINVAL;
6373ad0c7775SDouglas Gilbert 	if (n >= 0) {
6374ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6375ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6376ad0c7775SDouglas Gilbert 			return -EINVAL;
6377ad0c7775SDouglas Gilbert 		}
6378ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6379ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6380ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6381ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6382ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6383ad0c7775SDouglas Gilbert 
63840aaa3fadSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
6385ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6386ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6387ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6388ad0c7775SDouglas Gilbert 				}
6389ad0c7775SDouglas Gilbert 			}
63900aaa3fadSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
6391ad0c7775SDouglas Gilbert 		}
6392ad0c7775SDouglas Gilbert 		return count;
6393ad0c7775SDouglas Gilbert 	}
6394ad0c7775SDouglas Gilbert 	return -EINVAL;
6395ad0c7775SDouglas Gilbert }
6396ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6397ad0c7775SDouglas Gilbert 
639882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
63991da177e4SLinus Torvalds {
6400773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
64011da177e4SLinus Torvalds }
640282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
640382069379SAkinobu Mita 			      size_t count)
64041da177e4SLinus Torvalds {
64051da177e4SLinus Torvalds 	int n;
640619c8ead7SEwan D. Milne 	bool changed;
64071da177e4SLinus Torvalds 
64081da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
64098d039e22SDouglas Gilbert 		if (n > 256) {
64108d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
64118d039e22SDouglas Gilbert 			return -EINVAL;
64128d039e22SDouglas Gilbert 		}
6413773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6414773642d9SDouglas Gilbert 		sdebug_max_luns = n;
64151da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6416773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
641719c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
641819c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
641919c8ead7SEwan D. Milne 
64200aaa3fadSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
642119c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
642219c8ead7SEwan D. Milne 					    host_list) {
642319c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
642419c8ead7SEwan D. Milne 						    dev_list) {
642519c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
642619c8ead7SEwan D. Milne 						dp->uas_bm);
642719c8ead7SEwan D. Milne 				}
642819c8ead7SEwan D. Milne 			}
64290aaa3fadSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
643019c8ead7SEwan D. Milne 		}
64311da177e4SLinus Torvalds 		return count;
64321da177e4SLinus Torvalds 	}
64331da177e4SLinus Torvalds 	return -EINVAL;
64341da177e4SLinus Torvalds }
643582069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
64361da177e4SLinus Torvalds 
643782069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
643878d4e5a0SDouglas Gilbert {
6439773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
644078d4e5a0SDouglas Gilbert }
6441cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6442cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
644382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
644482069379SAkinobu Mita 			       size_t count)
644578d4e5a0SDouglas Gilbert {
6446c4837394SDouglas Gilbert 	int j, n, k, a;
6447c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
644878d4e5a0SDouglas Gilbert 
644978d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6450c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6451c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
645225b80b2cSJohn Garry 		mutex_lock(&sdebug_host_list_mutex);
6453f19fe8f3SBart Van Assche 		block_unblock_all_queues(true);
6454c4837394SDouglas Gilbert 		k = 0;
6455c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6456c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6457c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6458c4837394SDouglas Gilbert 			if (a > k)
6459c4837394SDouglas Gilbert 				k = a;
6460c4837394SDouglas Gilbert 		}
6461773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6462c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6463cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6464cbf67842SDouglas Gilbert 		else if (k >= n)
6465cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6466cbf67842SDouglas Gilbert 		else
6467cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6468f19fe8f3SBart Van Assche 		block_unblock_all_queues(false);
646925b80b2cSJohn Garry 		mutex_unlock(&sdebug_host_list_mutex);
647078d4e5a0SDouglas Gilbert 		return count;
647178d4e5a0SDouglas Gilbert 	}
647278d4e5a0SDouglas Gilbert 	return -EINVAL;
647378d4e5a0SDouglas Gilbert }
647482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
647578d4e5a0SDouglas Gilbert 
6476c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6477c10fa55fSJohn Garry {
6478c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6479c10fa55fSJohn Garry }
6480c10fa55fSJohn Garry 
64817109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
64827109f370SDouglas Gilbert {
64837109f370SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
64847109f370SDouglas Gilbert }
64857109f370SDouglas Gilbert 
64867109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
64877109f370SDouglas Gilbert {
64887109f370SDouglas Gilbert 	bool v;
64897109f370SDouglas Gilbert 
64907109f370SDouglas Gilbert 	if (kstrtobool(buf, &v))
64917109f370SDouglas Gilbert 		return -EINVAL;
64927109f370SDouglas Gilbert 
64937109f370SDouglas Gilbert 	sdebug_no_rwlock = v;
64947109f370SDouglas Gilbert 	return count;
64957109f370SDouglas Gilbert }
64967109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock);
64977109f370SDouglas Gilbert 
6498c10fa55fSJohn Garry /*
6499c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6500c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6501c10fa55fSJohn Garry  */
6502c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6503c10fa55fSJohn Garry 
650482069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
650578d4e5a0SDouglas Gilbert {
6506773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
650778d4e5a0SDouglas Gilbert }
650882069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
650978d4e5a0SDouglas Gilbert 
651082069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
65111da177e4SLinus Torvalds {
6512773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
65131da177e4SLinus Torvalds }
651482069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
65151da177e4SLinus Torvalds 
651682069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6517c65b1445SDouglas Gilbert {
6518773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6519c65b1445SDouglas Gilbert }
652082069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
652182069379SAkinobu Mita 				size_t count)
6522c65b1445SDouglas Gilbert {
6523c65b1445SDouglas Gilbert 	int n;
65240d01c5dfSDouglas Gilbert 	bool changed;
6525c65b1445SDouglas Gilbert 
6526f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6527f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6528f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6529f0d1cf93SDouglas Gilbert 
6530c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6531773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6532773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
653328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
65340d01c5dfSDouglas Gilbert 		if (changed) {
65350d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
65360d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
653728898873SFUJITA Tomonori 
65380aaa3fadSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
65390d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
65400d01c5dfSDouglas Gilbert 					    host_list) {
65410d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
65420d01c5dfSDouglas Gilbert 						    dev_list) {
65430d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
65440d01c5dfSDouglas Gilbert 						dp->uas_bm);
65450d01c5dfSDouglas Gilbert 				}
65460d01c5dfSDouglas Gilbert 			}
65470aaa3fadSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
65480d01c5dfSDouglas Gilbert 		}
6549c65b1445SDouglas Gilbert 		return count;
6550c65b1445SDouglas Gilbert 	}
6551c65b1445SDouglas Gilbert 	return -EINVAL;
6552c65b1445SDouglas Gilbert }
655382069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6554c65b1445SDouglas Gilbert 
655582069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
65561da177e4SLinus Torvalds {
655787c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
6558f19fe8f3SBart Van Assche 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
65591da177e4SLinus Torvalds }
65601da177e4SLinus Torvalds 
656182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
656282069379SAkinobu Mita 			      size_t count)
65631da177e4SLinus Torvalds {
6564f19fe8f3SBart Van Assche 	bool found;
6565f19fe8f3SBart Van Assche 	unsigned long idx;
6566f19fe8f3SBart Van Assche 	struct sdeb_store_info *sip;
6567f19fe8f3SBart Van Assche 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
65681da177e4SLinus Torvalds 	int delta_hosts;
65691da177e4SLinus Torvalds 
6570f19fe8f3SBart Van Assche 	if (sscanf(buf, "%d", &delta_hosts) != 1)
65711da177e4SLinus Torvalds 		return -EINVAL;
65721da177e4SLinus Torvalds 	if (delta_hosts > 0) {
65731da177e4SLinus Torvalds 		do {
6574f19fe8f3SBart Van Assche 			found = false;
6575f19fe8f3SBart Van Assche 			if (want_phs) {
6576f19fe8f3SBart Van Assche 				xa_for_each_marked(per_store_ap, idx, sip,
6577f19fe8f3SBart Van Assche 						   SDEB_XA_NOT_IN_USE) {
6578f19fe8f3SBart Van Assche 					sdeb_most_recent_idx = (int)idx;
6579f19fe8f3SBart Van Assche 					found = true;
658087c715dcSDouglas Gilbert 					break;
658187c715dcSDouglas Gilbert 				}
6582f19fe8f3SBart Van Assche 				if (found)	/* re-use case */
6583f19fe8f3SBart Van Assche 					sdebug_add_host_helper((int)idx);
6584f19fe8f3SBart Van Assche 				else
6585f19fe8f3SBart Van Assche 					sdebug_do_add_host(true);
6586f19fe8f3SBart Van Assche 			} else {
6587f19fe8f3SBart Van Assche 				sdebug_do_add_host(false);
6588f19fe8f3SBart Van Assche 			}
6589f19fe8f3SBart Van Assche 		} while (--delta_hosts);
6590f19fe8f3SBart Van Assche 	} else if (delta_hosts < 0) {
6591f19fe8f3SBart Van Assche 		do {
659287c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
65931da177e4SLinus Torvalds 		} while (++delta_hosts);
65941da177e4SLinus Torvalds 	}
65951da177e4SLinus Torvalds 	return count;
65961da177e4SLinus Torvalds }
659782069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
65981da177e4SLinus Torvalds 
659982069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
660023183910SDouglas Gilbert {
6601773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
660223183910SDouglas Gilbert }
660382069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
660482069379SAkinobu Mita 				    size_t count)
660523183910SDouglas Gilbert {
660623183910SDouglas Gilbert 	int n;
660723183910SDouglas Gilbert 
660823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6609773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
661023183910SDouglas Gilbert 		return count;
661123183910SDouglas Gilbert 	}
661223183910SDouglas Gilbert 	return -EINVAL;
661323183910SDouglas Gilbert }
661482069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
661523183910SDouglas Gilbert 
6616c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6617c4837394SDouglas Gilbert {
6618c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6619c4837394SDouglas Gilbert }
6620c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6621c4837394SDouglas Gilbert 				size_t count)
6622c4837394SDouglas Gilbert {
6623c4837394SDouglas Gilbert 	int n;
6624c4837394SDouglas Gilbert 
6625c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6626c4837394SDouglas Gilbert 		if (n > 0)
6627c4837394SDouglas Gilbert 			sdebug_statistics = true;
6628c4837394SDouglas Gilbert 		else {
6629c4837394SDouglas Gilbert 			clear_queue_stats();
6630c4837394SDouglas Gilbert 			sdebug_statistics = false;
6631c4837394SDouglas Gilbert 		}
6632c4837394SDouglas Gilbert 		return count;
6633c4837394SDouglas Gilbert 	}
6634c4837394SDouglas Gilbert 	return -EINVAL;
6635c4837394SDouglas Gilbert }
6636c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6637c4837394SDouglas Gilbert 
663882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6639597136abSMartin K. Petersen {
6640773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6641597136abSMartin K. Petersen }
664282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6643597136abSMartin K. Petersen 
6644c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6645c4837394SDouglas Gilbert {
6646c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6647c4837394SDouglas Gilbert }
6648c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6649c4837394SDouglas Gilbert 
665082069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6651c6a44287SMartin K. Petersen {
6652773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6653c6a44287SMartin K. Petersen }
665482069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6655c6a44287SMartin K. Petersen 
665682069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6657c6a44287SMartin K. Petersen {
6658773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6659c6a44287SMartin K. Petersen }
666082069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6661c6a44287SMartin K. Petersen 
666282069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6663c6a44287SMartin K. Petersen {
6664773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6665c6a44287SMartin K. Petersen }
666682069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6667c6a44287SMartin K. Petersen 
666882069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6669c6a44287SMartin K. Petersen {
6670773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6671c6a44287SMartin K. Petersen }
667282069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6673c6a44287SMartin K. Petersen 
667482069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
667544d92694SMartin K. Petersen {
667687c715dcSDouglas Gilbert 	ssize_t count = 0;
667744d92694SMartin K. Petersen 
66785b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
667944d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
668044d92694SMartin K. Petersen 				 sdebug_store_sectors);
668144d92694SMartin K. Petersen 
668287c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
668387c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
668487c715dcSDouglas Gilbert 
668587c715dcSDouglas Gilbert 		if (sip)
6686c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
668787c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
668887c715dcSDouglas Gilbert 	}
668944d92694SMartin K. Petersen 	buf[count++] = '\n';
6690c7badc90STejun Heo 	buf[count] = '\0';
669144d92694SMartin K. Petersen 
669244d92694SMartin K. Petersen 	return count;
669344d92694SMartin K. Petersen }
669482069379SAkinobu Mita static DRIVER_ATTR_RO(map);
669544d92694SMartin K. Petersen 
66960c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
66970c4bc91dSDouglas Gilbert {
66980c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
66990c4bc91dSDouglas Gilbert }
67000c4bc91dSDouglas Gilbert 
67010c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
67020c4bc91dSDouglas Gilbert 			    size_t count)
67030c4bc91dSDouglas Gilbert {
67040c4bc91dSDouglas Gilbert 	bool v;
67050c4bc91dSDouglas Gilbert 
67060c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
67070c4bc91dSDouglas Gilbert 		return -EINVAL;
67080c4bc91dSDouglas Gilbert 
67090c4bc91dSDouglas Gilbert 	sdebug_random = v;
67100c4bc91dSDouglas Gilbert 	return count;
67110c4bc91dSDouglas Gilbert }
67120c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
67130c4bc91dSDouglas Gilbert 
671482069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6715d986788bSMartin Pitt {
6716773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6717d986788bSMartin Pitt }
671882069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
671982069379SAkinobu Mita 			       size_t count)
6720d986788bSMartin Pitt {
6721d986788bSMartin Pitt 	int n;
6722d986788bSMartin Pitt 
6723d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6724773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6725d986788bSMartin Pitt 		return count;
6726d986788bSMartin Pitt 	}
6727d986788bSMartin Pitt 	return -EINVAL;
6728d986788bSMartin Pitt }
672982069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6730d986788bSMartin Pitt 
6731cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6732cbf67842SDouglas Gilbert {
6733773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6734cbf67842SDouglas Gilbert }
6735185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6736cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6737cbf67842SDouglas Gilbert 			       size_t count)
6738cbf67842SDouglas Gilbert {
6739185dd232SDouglas Gilbert 	int n;
6740cbf67842SDouglas Gilbert 
6741cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6742185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6743185dd232SDouglas Gilbert 		return count;
6744cbf67842SDouglas Gilbert 	}
6745cbf67842SDouglas Gilbert 	return -EINVAL;
6746cbf67842SDouglas Gilbert }
6747cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6748cbf67842SDouglas Gilbert 
6749c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6750c2248fc9SDouglas Gilbert {
6751773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6752c2248fc9SDouglas Gilbert }
6753c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6754c2248fc9SDouglas Gilbert 			    size_t count)
6755c2248fc9SDouglas Gilbert {
6756c2248fc9SDouglas Gilbert 	int n;
6757c2248fc9SDouglas Gilbert 
6758c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6759773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6760c2248fc9SDouglas Gilbert 		return count;
6761c2248fc9SDouglas Gilbert 	}
6762c2248fc9SDouglas Gilbert 	return -EINVAL;
6763c2248fc9SDouglas Gilbert }
6764c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6765c2248fc9SDouglas Gilbert 
676609ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
676709ba24c1SDouglas Gilbert {
676809ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
676909ba24c1SDouglas Gilbert }
677009ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
677109ba24c1SDouglas Gilbert 
67729b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
67739b760fd8SDouglas Gilbert {
67749b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
67759b760fd8SDouglas Gilbert }
67769b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
67779b760fd8SDouglas Gilbert 			     size_t count)
67789b760fd8SDouglas Gilbert {
67799b760fd8SDouglas Gilbert 	int ret, n;
67809b760fd8SDouglas Gilbert 
67819b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
67829b760fd8SDouglas Gilbert 	if (ret)
67839b760fd8SDouglas Gilbert 		return ret;
67849b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
67859b760fd8SDouglas Gilbert 	all_config_cdb_len();
67869b760fd8SDouglas Gilbert 	return count;
67879b760fd8SDouglas Gilbert }
67889b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
67899b760fd8SDouglas Gilbert 
67909267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
67919267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
67929267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
67939267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
67949267e0ebSDouglas Gilbert };
67959267e0ebSDouglas Gilbert 
67969267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
67979267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
67989267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
67999267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
68009267e0ebSDouglas Gilbert };
68019267e0ebSDouglas Gilbert 
68029267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
68039267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
68049267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
68059267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
68069267e0ebSDouglas Gilbert };
68079267e0ebSDouglas Gilbert 
68089267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
68099267e0ebSDouglas Gilbert {
68109267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
68119267e0ebSDouglas Gilbert 
68129267e0ebSDouglas Gilbert 	if (res < 0) {
68139267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
68149267e0ebSDouglas Gilbert 		if (res < 0) {
68159267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
681647742bdeSDan Carpenter 			if (res < 0)
68179267e0ebSDouglas Gilbert 				return -EINVAL;
68189267e0ebSDouglas Gilbert 		}
68199267e0ebSDouglas Gilbert 	}
68209267e0ebSDouglas Gilbert 	return res;
68219267e0ebSDouglas Gilbert }
68229267e0ebSDouglas Gilbert 
68239267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
68249267e0ebSDouglas Gilbert {
68259267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
68269267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
68279267e0ebSDouglas Gilbert }
68289267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6829cbf67842SDouglas Gilbert 
6830fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6831fc13638aSDouglas Gilbert {
6832fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6833fc13638aSDouglas Gilbert }
6834fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6835fc13638aSDouglas Gilbert 
683682069379SAkinobu Mita /* Note: The following array creates attribute files in the
683723183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
683823183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
683923183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
684087c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
684123183910SDouglas Gilbert  */
68426ecaff7fSRandy Dunlap 
684382069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
684482069379SAkinobu Mita 	&driver_attr_delay.attr,
684582069379SAkinobu Mita 	&driver_attr_opts.attr,
684682069379SAkinobu Mita 	&driver_attr_ptype.attr,
684782069379SAkinobu Mita 	&driver_attr_dsense.attr,
684882069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6849c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
685082069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
685182069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
685282069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
685382069379SAkinobu Mita 	&driver_attr_num_parts.attr,
685482069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6855ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
685682069379SAkinobu Mita 	&driver_attr_max_luns.attr,
685782069379SAkinobu Mita 	&driver_attr_max_queue.attr,
68587109f370SDouglas Gilbert 	&driver_attr_no_rwlock.attr,
685982069379SAkinobu Mita 	&driver_attr_no_uld.attr,
686082069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
686182069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
686282069379SAkinobu Mita 	&driver_attr_add_host.attr,
686387c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
686482069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
686582069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6866c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6867c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
686882069379SAkinobu Mita 	&driver_attr_dix.attr,
686982069379SAkinobu Mita 	&driver_attr_dif.attr,
687082069379SAkinobu Mita 	&driver_attr_guard.attr,
687182069379SAkinobu Mita 	&driver_attr_ato.attr,
687282069379SAkinobu Mita 	&driver_attr_map.attr,
68730c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
687482069379SAkinobu Mita 	&driver_attr_removable.attr,
6875cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6876cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6877c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
687809ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
68799b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6880fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
68819267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
688282069379SAkinobu Mita 	NULL,
688382069379SAkinobu Mita };
688482069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
68851da177e4SLinus Torvalds 
688611ddcecaSAkinobu Mita static struct device *pseudo_primary;
68878dea0d02SFUJITA Tomonori 
68881da177e4SLinus Torvalds static int __init scsi_debug_init(void)
68891da177e4SLinus Torvalds {
689087c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
68915f2578e5SFUJITA Tomonori 	unsigned long sz;
689287c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
689387c715dcSDouglas Gilbert 	int idx = -1;
68941da177e4SLinus Torvalds 
689587c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
689687c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6897cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6898cbf67842SDouglas Gilbert 
6899773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6900c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6901773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6902773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6903c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6904cbf67842SDouglas Gilbert 
6905773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6906597136abSMartin K. Petersen 	case  512:
6907597136abSMartin K. Petersen 	case 1024:
6908597136abSMartin K. Petersen 	case 2048:
6909597136abSMartin K. Petersen 	case 4096:
6910597136abSMartin K. Petersen 		break;
6911597136abSMartin K. Petersen 	default:
6912773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6913597136abSMartin K. Petersen 		return -EINVAL;
6914597136abSMartin K. Petersen 	}
6915597136abSMartin K. Petersen 
6916773642d9SDouglas Gilbert 	switch (sdebug_dif) {
69178475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6918f46eb0e9SDouglas Gilbert 		break;
69198475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
69208475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
69218475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6922f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6923c6a44287SMartin K. Petersen 		break;
6924c6a44287SMartin K. Petersen 
6925c6a44287SMartin K. Petersen 	default:
6926c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6927c6a44287SMartin K. Petersen 		return -EINVAL;
6928c6a44287SMartin K. Petersen 	}
6929c6a44287SMartin K. Petersen 
6930aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6931aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6932aa5334c4SMaurizio Lombardi 		return -EINVAL;
6933aa5334c4SMaurizio Lombardi 	}
6934aa5334c4SMaurizio Lombardi 
6935773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6936c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6937c6a44287SMartin K. Petersen 		return -EINVAL;
6938c6a44287SMartin K. Petersen 	}
6939c6a44287SMartin K. Petersen 
6940773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6941c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6942c6a44287SMartin K. Petersen 		return -EINVAL;
6943c6a44287SMartin K. Petersen 	}
6944c6a44287SMartin K. Petersen 
6945773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6946773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6947ea61fca5SMartin K. Petersen 		return -EINVAL;
6948ea61fca5SMartin K. Petersen 	}
6949ad0c7775SDouglas Gilbert 
6950ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6951ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6952ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6953ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6954ad0c7775SDouglas Gilbert 	}
6955ad0c7775SDouglas Gilbert 
69568d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6957ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6958ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
69598d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
69608d039e22SDouglas Gilbert 		}
6961ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6962ad0c7775SDouglas Gilbert 	}
6963ea61fca5SMartin K. Petersen 
6964773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6965773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6966ea61fca5SMartin K. Petersen 		return -EINVAL;
6967ea61fca5SMartin K. Petersen 	}
6968ea61fca5SMartin K. Petersen 
6969c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6970c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6971c4837394SDouglas Gilbert 		return -EINVAL;
6972c4837394SDouglas Gilbert 	}
6973c87bf24cSJohn Garry 
6974c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6975c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6976c87bf24cSJohn Garry 		return -EINVAL;
6977c87bf24cSJohn Garry 	}
6978c87bf24cSJohn Garry 
6979c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6980c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6981c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6982c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6983c10fa55fSJohn Garry 		return -EINVAL;
6984c10fa55fSJohn Garry 	}
6985c10fa55fSJohn Garry 
6986c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6987c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6988c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6989c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6990c10fa55fSJohn Garry 			sdebug_max_queue);
6991c10fa55fSJohn Garry 	}
6992c10fa55fSJohn Garry 
6993c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6994c4837394SDouglas Gilbert 			       GFP_KERNEL);
6995c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6996c4837394SDouglas Gilbert 		return -ENOMEM;
6997c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6998c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6999c4837394SDouglas Gilbert 
7000f0d1cf93SDouglas Gilbert 	/*
70019267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
70029267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
7003f0d1cf93SDouglas Gilbert 	 */
70049267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
70059267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
70069267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
70079267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
70089267e0ebSDouglas Gilbert 		if (k < 0) {
70099267e0ebSDouglas Gilbert 			ret = k;
70103b01d7eaSDinghao Liu 			goto free_q_arr;
70119267e0ebSDouglas Gilbert 		}
70129267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
70139267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
70149267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
701564e14eceSDamien Le Moal 		case BLK_ZONED_HA:
70169267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
70179267e0ebSDouglas Gilbert 			break;
70189267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
70199267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
70209267e0ebSDouglas Gilbert 			break;
70219267e0ebSDouglas Gilbert 		default:
70229267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
70233b01d7eaSDinghao Liu 			ret = -EINVAL;
70243b01d7eaSDinghao Liu 			goto free_q_arr;
70259267e0ebSDouglas Gilbert 		}
70269267e0ebSDouglas Gilbert 	}
70279267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
7028f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
70299267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70309267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
70319267e0ebSDouglas Gilbert 	}
7032f0d1cf93SDouglas Gilbert 
70339267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
70349267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
7035773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
7036773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
7037773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
7038773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
703928898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
70401da177e4SLinus Torvalds 
70411da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
70421da177e4SLinus Torvalds 	sdebug_heads = 8;
70431da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
7044773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
70451da177e4SLinus Torvalds 		sdebug_heads = 64;
7046773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
7047fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
70481da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70491da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70501da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
70511da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
70521da177e4SLinus Torvalds 		sdebug_heads = 255;
70531da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
70541da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
70551da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
70561da177e4SLinus Torvalds 	}
70575b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
7058773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
7059773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
70606014759cSMartin K. Petersen 
7061773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
7062773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
70636014759cSMartin K. Petersen 
7064773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
7065773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
70666014759cSMartin K. Petersen 
7067773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
7068773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
7069773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
7070c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
7071c4837394SDouglas Gilbert 			ret = -EINVAL;
707287c715dcSDouglas Gilbert 			goto free_q_arr;
707344d92694SMartin K. Petersen 		}
707444d92694SMartin K. Petersen 	}
707587c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
707687c715dcSDouglas Gilbert 	if (want_store) {
707787c715dcSDouglas Gilbert 		idx = sdebug_add_store();
707887c715dcSDouglas Gilbert 		if (idx < 0) {
707987c715dcSDouglas Gilbert 			ret = idx;
708087c715dcSDouglas Gilbert 			goto free_q_arr;
708187c715dcSDouglas Gilbert 		}
708244d92694SMartin K. Petersen 	}
708344d92694SMartin K. Petersen 
70849b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
70859b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
7086c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
70879b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
70886ecaff7fSRandy Dunlap 		goto free_vm;
70896ecaff7fSRandy Dunlap 	}
70906ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
70916ecaff7fSRandy Dunlap 	if (ret < 0) {
7092c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
70936ecaff7fSRandy Dunlap 		goto dev_unreg;
70946ecaff7fSRandy Dunlap 	}
70956ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
70966ecaff7fSRandy Dunlap 	if (ret < 0) {
7097c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
70986ecaff7fSRandy Dunlap 		goto bus_unreg;
70996ecaff7fSRandy Dunlap 	}
71001da177e4SLinus Torvalds 
710187c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
7102773642d9SDouglas Gilbert 	sdebug_add_host = 0;
71031da177e4SLinus Torvalds 
71041107c7b2SJohn Garry 	queued_cmd_cache = KMEM_CACHE(sdebug_queued_cmd, SLAB_HWCACHE_ALIGN);
71051107c7b2SJohn Garry 	if (!queued_cmd_cache)
71061107c7b2SJohn Garry 		goto driver_unreg;
71071107c7b2SJohn Garry 
710887c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
710987c715dcSDouglas Gilbert 		if (want_store && k == 0) {
711087c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
711187c715dcSDouglas Gilbert 			if (ret < 0) {
711287c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
711387c715dcSDouglas Gilbert 				       k, -ret);
711487c715dcSDouglas Gilbert 				break;
711587c715dcSDouglas Gilbert 			}
711687c715dcSDouglas Gilbert 		} else {
711787c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
711887c715dcSDouglas Gilbert 						 sdebug_per_host_store);
711987c715dcSDouglas Gilbert 			if (ret < 0) {
712087c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
71211da177e4SLinus Torvalds 				break;
71221da177e4SLinus Torvalds 			}
71231da177e4SLinus Torvalds 		}
712487c715dcSDouglas Gilbert 	}
7125773642d9SDouglas Gilbert 	if (sdebug_verbose)
7126f19fe8f3SBart Van Assche 		pr_info("built %d host(s)\n", sdebug_num_hosts);
7127c1287970STomas Winkler 
71281da177e4SLinus Torvalds 	return 0;
71296ecaff7fSRandy Dunlap 
71301107c7b2SJohn Garry driver_unreg:
71311107c7b2SJohn Garry 	driver_unregister(&sdebug_driverfs_driver);
71326ecaff7fSRandy Dunlap bus_unreg:
71336ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
71346ecaff7fSRandy Dunlap dev_unreg:
71359b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71366ecaff7fSRandy Dunlap free_vm:
713787c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
7138c4837394SDouglas Gilbert free_q_arr:
7139c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
71406ecaff7fSRandy Dunlap 	return ret;
71411da177e4SLinus Torvalds }
71421da177e4SLinus Torvalds 
71431da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
71441da177e4SLinus Torvalds {
7145f19fe8f3SBart Van Assche 	int k = sdebug_num_hosts;
71461da177e4SLinus Torvalds 
7147f19fe8f3SBart Van Assche 	for (; k; k--)
714887c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
71491107c7b2SJohn Garry 	kmem_cache_destroy(queued_cmd_cache);
71501da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
71511da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
71529b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
71531da177e4SLinus Torvalds 
715487c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
715587c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
7156f852c596SMaurizio Lombardi 	kfree(sdebug_q_arr);
71571da177e4SLinus Torvalds }
71581da177e4SLinus Torvalds 
71591da177e4SLinus Torvalds device_initcall(scsi_debug_init);
71601da177e4SLinus Torvalds module_exit(scsi_debug_exit);
71611da177e4SLinus Torvalds 
71621da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
71631da177e4SLinus Torvalds {
71641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71651da177e4SLinus Torvalds 
7166785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
71671da177e4SLinus Torvalds 	kfree(sdbg_host);
71681da177e4SLinus Torvalds }
71691da177e4SLinus Torvalds 
717087c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
717187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
71721da177e4SLinus Torvalds {
717387c715dcSDouglas Gilbert 	if (idx < 0)
717487c715dcSDouglas Gilbert 		return;
717587c715dcSDouglas Gilbert 	if (!sip) {
717687c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
717787c715dcSDouglas Gilbert 			return;
717887c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
717987c715dcSDouglas Gilbert 		if (!sip)
718087c715dcSDouglas Gilbert 			return;
718187c715dcSDouglas Gilbert 	}
718287c715dcSDouglas Gilbert 	vfree(sip->map_storep);
718387c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
718487c715dcSDouglas Gilbert 	vfree(sip->storep);
718587c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
718687c715dcSDouglas Gilbert 	kfree(sip);
718787c715dcSDouglas Gilbert }
718887c715dcSDouglas Gilbert 
718987c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
719087c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
719187c715dcSDouglas Gilbert {
719287c715dcSDouglas Gilbert 	unsigned long idx;
719387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
719487c715dcSDouglas Gilbert 
719587c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
719687c715dcSDouglas Gilbert 		if (apart_from_first)
719787c715dcSDouglas Gilbert 			apart_from_first = false;
719887c715dcSDouglas Gilbert 		else
719987c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
720087c715dcSDouglas Gilbert 	}
720187c715dcSDouglas Gilbert 	if (apart_from_first)
720287c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
720387c715dcSDouglas Gilbert }
720487c715dcSDouglas Gilbert 
720587c715dcSDouglas Gilbert /*
720687c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
720787c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
720887c715dcSDouglas Gilbert  */
720987c715dcSDouglas Gilbert static int sdebug_add_store(void)
721087c715dcSDouglas Gilbert {
721187c715dcSDouglas Gilbert 	int res;
721287c715dcSDouglas Gilbert 	u32 n_idx;
721387c715dcSDouglas Gilbert 	unsigned long iflags;
721487c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
721587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
721687c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
721787c715dcSDouglas Gilbert 
721887c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
721987c715dcSDouglas Gilbert 	if (!sip)
722087c715dcSDouglas Gilbert 		return -ENOMEM;
722187c715dcSDouglas Gilbert 
722287c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
722387c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
722487c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
722587c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
722687c715dcSDouglas Gilbert 		kfree(sip);
722787c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
722887c715dcSDouglas Gilbert 		return res;
722987c715dcSDouglas Gilbert 	}
723087c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
723187c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
723287c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
723387c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
723487c715dcSDouglas Gilbert 
723587c715dcSDouglas Gilbert 	res = -ENOMEM;
723687c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
723787c715dcSDouglas Gilbert 	if (!sip->storep) {
723887c715dcSDouglas Gilbert 		pr_err("user data oom\n");
723987c715dcSDouglas Gilbert 		goto err;
724087c715dcSDouglas Gilbert 	}
724187c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
724287c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
724387c715dcSDouglas Gilbert 
724487c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
724587c715dcSDouglas Gilbert 	if (sdebug_dix) {
724687c715dcSDouglas Gilbert 		int dif_size;
724787c715dcSDouglas Gilbert 
724887c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
724987c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
725087c715dcSDouglas Gilbert 
725187c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
725287c715dcSDouglas Gilbert 			sip->dif_storep);
725387c715dcSDouglas Gilbert 
725487c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
725587c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
725687c715dcSDouglas Gilbert 			goto err;
725787c715dcSDouglas Gilbert 		}
725887c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
725987c715dcSDouglas Gilbert 	}
726087c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
726187c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
726287c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
726387c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
726487c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
726587c715dcSDouglas Gilbert 
726687c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
726787c715dcSDouglas Gilbert 
726887c715dcSDouglas Gilbert 		if (!sip->map_storep) {
726987c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
727087c715dcSDouglas Gilbert 			goto err;
727187c715dcSDouglas Gilbert 		}
727287c715dcSDouglas Gilbert 
727387c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
727487c715dcSDouglas Gilbert 
727587c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
727687c715dcSDouglas Gilbert 		if (sdebug_num_parts)
727787c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
727887c715dcSDouglas Gilbert 	}
727987c715dcSDouglas Gilbert 
728087c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
728187c715dcSDouglas Gilbert 	return (int)n_idx;
728287c715dcSDouglas Gilbert err:
728387c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
728487c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
728587c715dcSDouglas Gilbert 	return res;
728687c715dcSDouglas Gilbert }
728787c715dcSDouglas Gilbert 
728887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
728987c715dcSDouglas Gilbert {
729087c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
729187c715dcSDouglas Gilbert 	int error = -ENOMEM;
72921da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72938b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
72941da177e4SLinus Torvalds 
729524669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
729687c715dcSDouglas Gilbert 	if (!sdbg_host)
72971da177e4SLinus Torvalds 		return -ENOMEM;
729887c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
729987c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
730087c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
730187c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
73021da177e4SLinus Torvalds 
73031da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
73041da177e4SLinus Torvalds 
7305773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
73061da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
73075cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
730887c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
73091da177e4SLinus Torvalds 			goto clean;
73101da177e4SLinus Torvalds 	}
73111da177e4SLinus Torvalds 
73120aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
73131da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
73140aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
73151da177e4SLinus Torvalds 
73161da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
73179b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
73181da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
7319f19fe8f3SBart Van Assche 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
73201da177e4SLinus Torvalds 
73211da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
7322e208a1d7SYuan Can 	if (error) {
73230aaa3fadSJohn Garry 		mutex_lock(&sdebug_host_list_mutex);
7324e208a1d7SYuan Can 		list_del(&sdbg_host->host_list);
73250aaa3fadSJohn Garry 		mutex_unlock(&sdebug_host_list_mutex);
73261da177e4SLinus Torvalds 		goto clean;
7327e208a1d7SYuan Can 	}
73281da177e4SLinus Torvalds 
7329f19fe8f3SBart Van Assche 	++sdebug_num_hosts;
733087c715dcSDouglas Gilbert 	return 0;
73311da177e4SLinus Torvalds 
73321da177e4SLinus Torvalds clean:
73338b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73348b40228fSFUJITA Tomonori 				 dev_list) {
73351da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7336f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73371da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73381da177e4SLinus Torvalds 	}
7339e6d773f9SYang Yingliang 	if (sdbg_host->dev.release)
7340e6d773f9SYang Yingliang 		put_device(&sdbg_host->dev);
7341e6d773f9SYang Yingliang 	else
73421da177e4SLinus Torvalds 		kfree(sdbg_host);
734387c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
73441da177e4SLinus Torvalds 	return error;
73451da177e4SLinus Torvalds }
73461da177e4SLinus Torvalds 
734787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
73481da177e4SLinus Torvalds {
734987c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
735087c715dcSDouglas Gilbert 
735187c715dcSDouglas Gilbert 	if (mk_new_store) {
735287c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
735387c715dcSDouglas Gilbert 		if (ph_idx < 0)
735487c715dcSDouglas Gilbert 			return ph_idx;
735587c715dcSDouglas Gilbert 	}
735687c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
735787c715dcSDouglas Gilbert }
735887c715dcSDouglas Gilbert 
735987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
736087c715dcSDouglas Gilbert {
736187c715dcSDouglas Gilbert 	int idx = -1;
73621da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
736387c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
73641da177e4SLinus Torvalds 
73650aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
73661da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
73671da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
73681da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
736987c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
73701da177e4SLinus Torvalds 	}
737187c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
737287c715dcSDouglas Gilbert 		bool unique = true;
737387c715dcSDouglas Gilbert 
737487c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
737587c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
737687c715dcSDouglas Gilbert 				continue;
737787c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
737887c715dcSDouglas Gilbert 				unique = false;
737987c715dcSDouglas Gilbert 				break;
738087c715dcSDouglas Gilbert 			}
738187c715dcSDouglas Gilbert 		}
738287c715dcSDouglas Gilbert 		if (unique) {
738387c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
738487c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
738587c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
738687c715dcSDouglas Gilbert 		}
738787c715dcSDouglas Gilbert 	}
738887c715dcSDouglas Gilbert 	if (sdbg_host)
738987c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
73900aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
73911da177e4SLinus Torvalds 
73921da177e4SLinus Torvalds 	if (!sdbg_host)
73931da177e4SLinus Torvalds 		return;
73941da177e4SLinus Torvalds 
73951da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
7396f19fe8f3SBart Van Assche 	--sdebug_num_hosts;
73971da177e4SLinus Torvalds }
73981da177e4SLinus Torvalds 
7399fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7400cbf67842SDouglas Gilbert {
7401151f0ec9SJohn Garry 	struct sdebug_dev_info *devip = sdev->hostdata;
7402151f0ec9SJohn Garry 
7403151f0ec9SJohn Garry 	if (!devip)
7404151f0ec9SJohn Garry 		return	-ENODEV;
7405cbf67842SDouglas Gilbert 
740625b80b2cSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
7407f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
740825b80b2cSJohn Garry 
7409fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7410fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7411fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7412fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7413fc09acb7SDouglas Gilbert 	}
7414cbf67842SDouglas Gilbert 	if (qdepth < 1)
7415cbf67842SDouglas Gilbert 		qdepth = 1;
7416fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7417db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7418cbf67842SDouglas Gilbert 
741925b80b2cSJohn Garry 	block_unblock_all_queues(false);
742025b80b2cSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
742125b80b2cSJohn Garry 
7422151f0ec9SJohn Garry 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
7423151f0ec9SJohn Garry 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d\n", __func__, qdepth);
742425b80b2cSJohn Garry 
7425cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7426cbf67842SDouglas Gilbert }
7427cbf67842SDouglas Gilbert 
7428c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7429817fd66bSDouglas Gilbert {
7430c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7431773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7432773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7433773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7434c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7435773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7436817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7437c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7438817fd66bSDouglas Gilbert 	}
7439c4837394SDouglas Gilbert 	return false;
7440817fd66bSDouglas Gilbert }
7441817fd66bSDouglas Gilbert 
7442fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
7443fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7444fc13638aSDouglas Gilbert {
7445fc13638aSDouglas Gilbert 	int stopped_state;
7446fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7447fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7448fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7449fc13638aSDouglas Gilbert 
7450fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7451fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7452fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7453fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7454fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7455fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7456fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7457fc13638aSDouglas Gilbert 				return 0;
7458fc13638aSDouglas Gilbert 			}
7459fc13638aSDouglas Gilbert 		}
7460fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7461fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7462fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7463fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7464fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7465fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7466fc13638aSDouglas Gilbert 
7467fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7468fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7469fc13638aSDouglas Gilbert 			else
7470fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7471fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7472fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7473fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7474fc13638aSDouglas Gilbert 						   diff_ns);
7475fc13638aSDouglas Gilbert 			return check_condition_result;
7476fc13638aSDouglas Gilbert 		}
7477fc13638aSDouglas Gilbert 	}
7478fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7479fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7480fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7481fc13638aSDouglas Gilbert 			    my_name);
7482fc13638aSDouglas Gilbert 	return check_condition_result;
7483fc13638aSDouglas Gilbert }
7484fc13638aSDouglas Gilbert 
7485a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost)
7486c4b57d89SKashyap Desai {
7487c4b57d89SKashyap Desai 	int i, qoff;
7488c4b57d89SKashyap Desai 
7489c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7490a4e1d0b7SBart Van Assche 		return;
7491c4b57d89SKashyap Desai 
7492c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7493c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7494c4b57d89SKashyap Desai 
7495c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7496c4b57d89SKashyap Desai 
7497c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7498c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7499c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7500c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7501c4b57d89SKashyap Desai 
7502c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7503c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7504c4b57d89SKashyap Desai 			continue;
7505c4b57d89SKashyap Desai 		}
7506c4b57d89SKashyap Desai 
7507c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7508c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7509c4b57d89SKashyap Desai 
7510c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7511c4b57d89SKashyap Desai 	}
7512c4b57d89SKashyap Desai }
7513c4b57d89SKashyap Desai 
7514*600d9eadSJohn Garry struct sdebug_blk_mq_poll_data {
7515*600d9eadSJohn Garry 	unsigned int queue_num;
7516*600d9eadSJohn Garry 	int *num_entries;
7517*600d9eadSJohn Garry };
7518*600d9eadSJohn Garry 
7519*600d9eadSJohn Garry /*
7520*600d9eadSJohn Garry  * We don't handle aborted commands here, but it does not seem possible to have
7521*600d9eadSJohn Garry  * aborted polled commands from schedule_resp()
7522*600d9eadSJohn Garry  */
7523*600d9eadSJohn Garry static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque)
7524c4b57d89SKashyap Desai {
7525*600d9eadSJohn Garry 	struct sdebug_blk_mq_poll_data *data = opaque;
7526*600d9eadSJohn Garry 	struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
7527*600d9eadSJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd);
75284a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7529*600d9eadSJohn Garry 	u32 unique_tag = blk_mq_unique_tag(rq);
7530*600d9eadSJohn Garry 	u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag);
7531*600d9eadSJohn Garry 	struct sdebug_queued_cmd *sqcp;
7532*600d9eadSJohn Garry 	struct sdebug_queue *sqp;
7533*600d9eadSJohn Garry 	unsigned long flags;
7534*600d9eadSJohn Garry 	int queue_num = data->queue_num;
7535*600d9eadSJohn Garry 	bool retiring = false;
7536*600d9eadSJohn Garry 	int qc_idx;
7537*600d9eadSJohn Garry 	ktime_t time;
7538*600d9eadSJohn Garry 
7539*600d9eadSJohn Garry 	/* We're only interested in one queue for this iteration */
7540*600d9eadSJohn Garry 	if (hwq != queue_num)
7541*600d9eadSJohn Garry 		return true;
7542*600d9eadSJohn Garry 
7543*600d9eadSJohn Garry 	/* Subsequent checks would fail if this failed, but check anyway */
7544*600d9eadSJohn Garry 	if (!test_bit(SCMD_STATE_INFLIGHT, &cmd->state))
7545*600d9eadSJohn Garry 		return true;
7546*600d9eadSJohn Garry 
7547*600d9eadSJohn Garry 	time = ktime_get_boottime();
7548*600d9eadSJohn Garry 
7549*600d9eadSJohn Garry 	spin_lock_irqsave(&sdsc->lock, flags);
7550*600d9eadSJohn Garry 	sqcp = TO_QUEUED_CMD(cmd);
7551*600d9eadSJohn Garry 	if (!sqcp) {
7552*600d9eadSJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7553*600d9eadSJohn Garry 		return true;
7554*600d9eadSJohn Garry 	}
7555c4b57d89SKashyap Desai 
7556c4b57d89SKashyap Desai 	sqp = sdebug_q_arr + queue_num;
75571107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
75581107c7b2SJohn Garry 
7559*600d9eadSJohn Garry 	if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) {
75601107c7b2SJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7561*600d9eadSJohn Garry 		return true;
75621107c7b2SJohn Garry 	}
75631107c7b2SJohn Garry 
7564*600d9eadSJohn Garry 	if (time < sd_dp->cmpl_ts) {
75651107c7b2SJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7566*600d9eadSJohn Garry 		return true;
75671107c7b2SJohn Garry 	}
75681107c7b2SJohn Garry 
7569c4b57d89SKashyap Desai 	if (unlikely(atomic_read(&retired_max_queue) > 0))
75704a0c6f43SDouglas Gilbert 		retiring = true;
7571c4b57d89SKashyap Desai 
7572*600d9eadSJohn Garry 	qc_idx = sd_dp->sqa_idx;
7573*600d9eadSJohn Garry 	sqp->qc_arr[qc_idx] = NULL;
7574c4b57d89SKashyap Desai 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
75751107c7b2SJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7576*600d9eadSJohn Garry 		pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u\n",
7577*600d9eadSJohn Garry 			sqp, queue_num, qc_idx);
75781107c7b2SJohn Garry 		sdebug_free_queued_cmd(sqcp);
7579*600d9eadSJohn Garry 		return true;
7580c4b57d89SKashyap Desai 	}
7581c4b57d89SKashyap Desai 
7582*600d9eadSJohn Garry 	if (unlikely(retiring)) {	/* user has reduced max_queue */
7583*600d9eadSJohn Garry 		int k, retval = atomic_read(&retired_max_queue);
7584*600d9eadSJohn Garry 
7585c4b57d89SKashyap Desai 		if (qc_idx >= retval) {
7586c4b57d89SKashyap Desai 			pr_err("index %d too large\n", retval);
75871107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
75881107c7b2SJohn Garry 			sdebug_free_queued_cmd(sqcp);
7589*600d9eadSJohn Garry 			return true;
7590c4b57d89SKashyap Desai 		}
7591*600d9eadSJohn Garry 
7592c4b57d89SKashyap Desai 		k = find_last_bit(sqp->in_use_bm, retval);
7593c4b57d89SKashyap Desai 		if ((k < sdebug_max_queue) || (k == retval))
7594c4b57d89SKashyap Desai 			atomic_set(&retired_max_queue, 0);
7595c4b57d89SKashyap Desai 		else
7596c4b57d89SKashyap Desai 			atomic_set(&retired_max_queue, k + 1);
7597c4b57d89SKashyap Desai 	}
7598*600d9eadSJohn Garry 
7599*600d9eadSJohn Garry 	ASSIGN_QUEUED_CMD(cmd, NULL);
76001107c7b2SJohn Garry 	spin_unlock_irqrestore(&sdsc->lock, flags);
7601548ebb33SJohn Garry 
7602548ebb33SJohn Garry 	if (sdebug_statistics) {
7603548ebb33SJohn Garry 		atomic_inc(&sdebug_completions);
7604548ebb33SJohn Garry 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
7605548ebb33SJohn Garry 			atomic_inc(&sdebug_miss_cpus);
7606548ebb33SJohn Garry 	}
7607548ebb33SJohn Garry 
76081107c7b2SJohn Garry 	sdebug_free_queued_cmd(sqcp);
76091107c7b2SJohn Garry 
7610*600d9eadSJohn Garry 	scsi_done(cmd); /* callback to mid level */
7611*600d9eadSJohn Garry 	(*data->num_entries)++;
7612*600d9eadSJohn Garry 	return true;
76134a0c6f43SDouglas Gilbert }
76143fd07aecSDamien Le Moal 
7615*600d9eadSJohn Garry static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7616*600d9eadSJohn Garry {
7617*600d9eadSJohn Garry 	int num_entries = 0;
7618*600d9eadSJohn Garry 	unsigned long iflags;
7619*600d9eadSJohn Garry 	struct sdebug_queue *sqp;
7620*600d9eadSJohn Garry 	struct sdebug_blk_mq_poll_data data = {
7621*600d9eadSJohn Garry 		.queue_num = queue_num,
7622*600d9eadSJohn Garry 		.num_entries = &num_entries,
7623*600d9eadSJohn Garry 	};
7624*600d9eadSJohn Garry 	sqp = sdebug_q_arr + queue_num;
76253fd07aecSDamien Le Moal 
7626*600d9eadSJohn Garry 	spin_lock_irqsave(&sqp->qc_lock, iflags);
7627*600d9eadSJohn Garry 
7628*600d9eadSJohn Garry 	blk_mq_tagset_busy_iter(&shost->tag_set, sdebug_blk_mq_poll_iter,
7629*600d9eadSJohn Garry 				&data);
7630*600d9eadSJohn Garry 
7631*600d9eadSJohn Garry 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
76324a0c6f43SDouglas Gilbert 	if (num_entries > 0)
76334a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7634c4b57d89SKashyap Desai 	return num_entries;
7635c4b57d89SKashyap Desai }
7636c4b57d89SKashyap Desai 
7637fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7638fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7639c2248fc9SDouglas Gilbert {
7640c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7641c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7642c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7643c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7644c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7645c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7646c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7647f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7648c2248fc9SDouglas Gilbert 	int k, na;
7649c2248fc9SDouglas Gilbert 	int errsts = 0;
7650ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7651c2248fc9SDouglas Gilbert 	u32 flags;
7652c2248fc9SDouglas Gilbert 	u16 sa;
7653c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7654c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
76553a90a63dSDouglas Gilbert 	bool inject_now;
7656c2248fc9SDouglas Gilbert 
7657c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
76583a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7659c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
76603a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
76613a90a63dSDouglas Gilbert 	} else {
76623a90a63dSDouglas Gilbert 		inject_now = false;
76633a90a63dSDouglas Gilbert 	}
7664f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7665f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7666c2248fc9SDouglas Gilbert 		char b[120];
7667c2248fc9SDouglas Gilbert 		int n, len, sb;
7668c2248fc9SDouglas Gilbert 
7669c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7670c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7671c2248fc9SDouglas Gilbert 		if (len > 32)
7672c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7673c2248fc9SDouglas Gilbert 		else {
7674c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7675c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7676c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7677c2248fc9SDouglas Gilbert 		}
7678458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7679a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7680c2248fc9SDouglas Gilbert 	}
76813a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
76827ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
768334d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7684ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7685f46eb0e9SDouglas Gilbert 		goto err_out;
7686c2248fc9SDouglas Gilbert 
7687c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7688c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7689c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7690f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7691f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7692c2248fc9SDouglas Gilbert 		if (NULL == devip)
7693f46eb0e9SDouglas Gilbert 			goto err_out;
7694c2248fc9SDouglas Gilbert 	}
76953a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
76963a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
76973a90a63dSDouglas Gilbert 
7698c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7699c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7700c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7701c2248fc9SDouglas Gilbert 		r_oip = oip;
7702c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7703c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7704c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7705c2248fc9SDouglas Gilbert 			else
7706c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7707c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7708c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7709c2248fc9SDouglas Gilbert 					break;
7710c2248fc9SDouglas Gilbert 			}
7711c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7712c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7713c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7714c2248fc9SDouglas Gilbert 					break;
7715c2248fc9SDouglas Gilbert 			}
7716c2248fc9SDouglas Gilbert 		}
7717c2248fc9SDouglas Gilbert 		if (k > na) {
7718c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7719c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7720c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7721c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7722c2248fc9SDouglas Gilbert 			else
7723c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7724c2248fc9SDouglas Gilbert 			goto check_cond;
7725c2248fc9SDouglas Gilbert 		}
7726c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7727c2248fc9SDouglas Gilbert 	flags = oip->flags;
7728f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7729c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7730c2248fc9SDouglas Gilbert 		goto check_cond;
7731c2248fc9SDouglas Gilbert 	}
7732f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7733773642d9SDouglas Gilbert 		if (sdebug_verbose)
7734773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7735773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7736c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7737c2248fc9SDouglas Gilbert 		goto check_cond;
7738c2248fc9SDouglas Gilbert 	}
7739f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7740c2248fc9SDouglas Gilbert 		u8 rem;
7741c2248fc9SDouglas Gilbert 		int j;
7742c2248fc9SDouglas Gilbert 
7743c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7744c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7745c2248fc9SDouglas Gilbert 			if (rem) {
7746c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7747c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7748c2248fc9SDouglas Gilbert 						break;
7749c2248fc9SDouglas Gilbert 				}
7750c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7751c2248fc9SDouglas Gilbert 				goto check_cond;
7752c2248fc9SDouglas Gilbert 			}
7753c2248fc9SDouglas Gilbert 		}
7754c2248fc9SDouglas Gilbert 	}
7755f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7756b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7757b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7758f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7759c2248fc9SDouglas Gilbert 		if (errsts)
7760c2248fc9SDouglas Gilbert 			goto check_cond;
7761c2248fc9SDouglas Gilbert 	}
7762fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7763fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7764fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7765fc13638aSDouglas Gilbert 		if (errsts)
7766c2248fc9SDouglas Gilbert 			goto fini;
7767c2248fc9SDouglas Gilbert 	}
7768773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7769c2248fc9SDouglas Gilbert 		goto fini;
7770f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7771c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7772c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7773c2248fc9SDouglas Gilbert 	}
7774f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7775f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7776f66b8517SMartin Wilck 	else
7777f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7778c2248fc9SDouglas Gilbert 
7779c2248fc9SDouglas Gilbert fini:
778067da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7781f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
778275aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
778375aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
778480c49563SDouglas Gilbert 		/*
778575aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
778675aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
778775aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
778875aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
778980c49563SDouglas Gilbert 		 */
779080c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
77914f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
779280c49563SDouglas Gilbert 
77934f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7794f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
779580c49563SDouglas Gilbert 	} else
7796f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
779710bde980SDouglas Gilbert 				     sdebug_ndelay);
7798c2248fc9SDouglas Gilbert check_cond:
7799f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7800f46eb0e9SDouglas Gilbert err_out:
7801f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7802c2248fc9SDouglas Gilbert }
7803c2248fc9SDouglas Gilbert 
78041107c7b2SJohn Garry static int sdebug_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
78051107c7b2SJohn Garry {
78061107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd);
78071107c7b2SJohn Garry 
78081107c7b2SJohn Garry 	spin_lock_init(&sdsc->lock);
78091107c7b2SJohn Garry 
78101107c7b2SJohn Garry 	return 0;
78111107c7b2SJohn Garry }
78121107c7b2SJohn Garry 
78131107c7b2SJohn Garry 
78149e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7815c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7816c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
78179e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
78189e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
78199e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
78209e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
78219e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
78229e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
78239e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7824185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7825cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7826c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7827c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
78289e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
78299e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7830cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7831cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
78329e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7833c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
78349e603ca0SFUJITA Tomonori 	.this_id =		7,
783565e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7836cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
78376bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
783850c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
78399e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7840c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
78411107c7b2SJohn Garry 	.cmd_size = sizeof(struct sdebug_scsi_cmd),
78421107c7b2SJohn Garry 	.init_cmd_priv = sdebug_init_cmd_priv,
78439e603ca0SFUJITA Tomonori };
78449e603ca0SFUJITA Tomonori 
78451da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
78461da177e4SLinus Torvalds {
78471da177e4SLinus Torvalds 	int error = 0;
78481da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
78491da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7850f46eb0e9SDouglas Gilbert 	int hprot;
78511da177e4SLinus Torvalds 
7852785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
78531da177e4SLinus Torvalds 
7854773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7855fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
78562a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
78574af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
78584af14d11SChristoph Hellwig 
7859785d6b7cSJohn Garry 	hpnt = scsi_host_alloc(&sdebug_driver_template, 0);
78601da177e4SLinus Torvalds 	if (NULL == hpnt) {
7861c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
78621da177e4SLinus Torvalds 		error = -ENODEV;
78631da177e4SLinus Torvalds 		return error;
78641da177e4SLinus Torvalds 	}
7865c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
78669b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7867c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7868c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7869c4837394SDouglas Gilbert 	}
7870c10fa55fSJohn Garry 	/*
7871c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7872f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7873c10fa55fSJohn Garry 	 */
7874c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7875f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7876f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
78771da177e4SLinus Torvalds 
7878c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7879c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7880c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7881c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7882c4b57d89SKashyap Desai 		poll_queues = 0;
7883c4b57d89SKashyap Desai 	}
7884c4b57d89SKashyap Desai 
7885c4b57d89SKashyap Desai 	/*
7886c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7887c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7888c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7889c4b57d89SKashyap Desai 	 */
7890c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7891fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7892c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7893fc09acb7SDouglas Gilbert 		else
7894fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7895fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7896c4b57d89SKashyap Desai 		poll_queues = 1;
7897c4b57d89SKashyap Desai 	}
7898c4b57d89SKashyap Desai 	if (poll_queues)
7899c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7900c4b57d89SKashyap Desai 
79011da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
7902773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7903773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
79041da177e4SLinus Torvalds 	else
7905773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7906773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7907f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
79081da177e4SLinus Torvalds 
7909f46eb0e9SDouglas Gilbert 	hprot = 0;
7910c6a44287SMartin K. Petersen 
7911773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7912c6a44287SMartin K. Petersen 
79138475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7914f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7915773642d9SDouglas Gilbert 		if (sdebug_dix)
7916f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7917c6a44287SMartin K. Petersen 		break;
7918c6a44287SMartin K. Petersen 
79198475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7920f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7921773642d9SDouglas Gilbert 		if (sdebug_dix)
7922f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7923c6a44287SMartin K. Petersen 		break;
7924c6a44287SMartin K. Petersen 
79258475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7926f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7927773642d9SDouglas Gilbert 		if (sdebug_dix)
7928f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7929c6a44287SMartin K. Petersen 		break;
7930c6a44287SMartin K. Petersen 
7931c6a44287SMartin K. Petersen 	default:
7932773642d9SDouglas Gilbert 		if (sdebug_dix)
7933f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7934c6a44287SMartin K. Petersen 		break;
7935c6a44287SMartin K. Petersen 	}
7936c6a44287SMartin K. Petersen 
7937f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7938c6a44287SMartin K. Petersen 
7939f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7940c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7941f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7942f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7943f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7944f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7945f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7946f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7947f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7948c6a44287SMartin K. Petersen 
7949773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7950c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7951c6a44287SMartin K. Petersen 	else
7952c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7953c6a44287SMartin K. Petersen 
7954773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7955773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7956c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7957c4837394SDouglas Gilbert 		sdebug_statistics = true;
79581da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
79591da177e4SLinus Torvalds 	if (error) {
7960c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
79611da177e4SLinus Torvalds 		error = -ENODEV;
79621da177e4SLinus Torvalds 		scsi_host_put(hpnt);
796387c715dcSDouglas Gilbert 	} else {
79641da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
796587c715dcSDouglas Gilbert 	}
79661da177e4SLinus Torvalds 
79671da177e4SLinus Torvalds 	return error;
79681da177e4SLinus Torvalds }
79691da177e4SLinus Torvalds 
7970fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
79711da177e4SLinus Torvalds {
79721da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
79738b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
79741da177e4SLinus Torvalds 
7975785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
79761da177e4SLinus Torvalds 
79771da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
79781da177e4SLinus Torvalds 
79798b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
79808b40228fSFUJITA Tomonori 				 dev_list) {
79811da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7982f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
79831da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
79841da177e4SLinus Torvalds 	}
79851da177e4SLinus Torvalds 
79861da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
79871da177e4SLinus Torvalds }
79881da177e4SLinus Torvalds 
79898dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
79908dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
79911da177e4SLinus Torvalds {
79928dea0d02SFUJITA Tomonori 	return 1;
79938dea0d02SFUJITA Tomonori }
79941da177e4SLinus Torvalds 
79958dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
79968dea0d02SFUJITA Tomonori 	.name = "pseudo",
79978dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
79988dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
79998dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
800082069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
80018dea0d02SFUJITA Tomonori };
8002