xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 47742bde)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
51da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
61da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
71da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
81da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91da177e4SLinus Torvalds  *
1048e3bf16SDouglas Gilbert  * Copyright (C) 2001 - 2020 Douglas Gilbert
111da177e4SLinus Torvalds  *
1278d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/genhd.h>
271da177e4SLinus Torvalds #include <linux/fs.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/vmalloc.h>
311da177e4SLinus Torvalds #include <linux/moduleparam.h>
32852e034dSJens Axboe #include <linux/scatterlist.h>
331da177e4SLinus Torvalds #include <linux/blkdev.h>
34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
35cbf67842SDouglas Gilbert #include <linux/spinlock.h>
36cbf67842SDouglas Gilbert #include <linux/interrupt.h>
37cbf67842SDouglas Gilbert #include <linux/atomic.h>
38cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3909ba24c1SDouglas Gilbert #include <linux/uuid.h>
406ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
411442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
420c4bc91dSDouglas Gilbert #include <linux/random.h>
4387c715dcSDouglas Gilbert #include <linux/xarray.h>
44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6348e3bf16SDouglas Gilbert #define SDEBUG_VERSION "0189"	/* format to fit INQUIRY revision field */
6448e3bf16SDouglas Gilbert static const char *sdebug_version_date = "20200421";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
101f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1021da177e4SLinus Torvalds 
1036f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1046f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1056f3cbf55SDouglas Gilbert 
1061da177e4SLinus Torvalds /* Default values for driver parameters */
1071da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1081da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1091da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1111da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1121da177e4SLinus Torvalds  */
1135b94e232SMartin K. Petersen #define DEF_ATO 1
1149b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
115c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1169267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1171da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1189267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1195b94e232SMartin K. Petersen #define DEF_DIF 0
1205b94e232SMartin K. Petersen #define DEF_DIX 0
12187c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1225b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1231da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1245b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1255b94e232SMartin K. Petersen #define DEF_GUARD 0
126cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1275b94e232SMartin K. Petersen #define DEF_LBPU 0
1285b94e232SMartin K. Petersen #define DEF_LBPWS 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS10 0
130be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1315b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
132cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1335b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1341da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1351da177e4SLinus Torvalds #define DEF_OPTS   0
13632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1375b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
139b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1400c4bc91dSDouglas Gilbert #define DEF_RANDOM false
141d986788bSMartin Pitt #define DEF_REMOVABLE false
142760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1435b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1445b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1455b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1466014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1485b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1495b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1505b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
151c2248fc9SDouglas Gilbert #define DEF_STRICT 0
152c4837394SDouglas Gilbert #define DEF_STATISTICS false
153c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
15409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
155c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1561da177e4SLinus Torvalds 
157f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
158f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
159f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
160aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
161f0d1cf93SDouglas Gilbert 
162b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
163b01f6f83SDouglas Gilbert 
164773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
165773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
166773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
167773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
168773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
170773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
171773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
172773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
173773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
174773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
175773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
176773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
177773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
179773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1807ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1817382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
182773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
183773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
185773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
186773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1877ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1887382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1897382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1901da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
191fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1921da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
193773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1946f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
195773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1967382f9d8SDouglas Gilbert  *   - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
1977382f9d8SDouglas Gilbert  *     CMD_ABORT
1981da177e4SLinus Torvalds  *
1997382f9d8SDouglas Gilbert  * When "every_nth" < 0 then after "- every_nth" commands the selected
2007382f9d8SDouglas Gilbert  * error will be injected. The error will be injected on every subsequent
2017382f9d8SDouglas Gilbert  * command until some other action occurs; for example, the user writing
2027382f9d8SDouglas Gilbert  * a new value (other than -1 or 1) to every_nth:
2037382f9d8SDouglas Gilbert  *      echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
2041da177e4SLinus Torvalds  */
2051da177e4SLinus Torvalds 
206cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
207cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
208cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
209cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
210cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
211cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
212cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2130d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
21419c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
215acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
216acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
217acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
218cbf67842SDouglas Gilbert 
219773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2201da177e4SLinus Torvalds  * sector on read commands: */
2211da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
22232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2251da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2261da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2271da177e4SLinus Torvalds 
228c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
229c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
230c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
231c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
232c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
233c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
234c4837394SDouglas Gilbert  */
235c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
236c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
237cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
238cbf67842SDouglas Gilbert 
239fd32119bSDouglas Gilbert #define F_D_IN			1
240fd32119bSDouglas Gilbert #define F_D_OUT			2
241fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
242fd32119bSDouglas Gilbert #define F_D_UNKN		8
243fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
244fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
245fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
246fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
247fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
248fd32119bSDouglas Gilbert #define F_INV_OP		0x200
249fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
250fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
2514f2c8bf6SDouglas Gilbert #define F_SSU_DELAY		0x1000
2524f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY		0x2000
253fd32119bSDouglas Gilbert 
254fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
25546f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
256fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2574f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
258fd32119bSDouglas Gilbert 
259fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
260fd32119bSDouglas Gilbert 
261b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
262fd32119bSDouglas Gilbert 
26387c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
26487c715dcSDouglas Gilbert 
26564e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
26664e14eceSDamien Le Moal enum sdebug_z_type {
26764e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_CNV	= 0x1,
26864e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWR	= 0x2,
26964e14eceSDamien Le Moal 	ZBC_ZONE_TYPE_SWP	= 0x3,
27064e14eceSDamien Le Moal };
27164e14eceSDamien Le Moal 
272f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
273f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
274f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
275f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
276f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
277f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
278f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
279f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
280f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
281f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
282f0d1cf93SDouglas Gilbert };
283f0d1cf93SDouglas Gilbert 
284f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
28564e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
286f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
28764e14eceSDamien Le Moal 	bool z_non_seq_resource;
288f0d1cf93SDouglas Gilbert 	unsigned int z_size;
289f0d1cf93SDouglas Gilbert 	sector_t z_start;
290f0d1cf93SDouglas Gilbert 	sector_t z_wp;
291f0d1cf93SDouglas Gilbert };
292fd32119bSDouglas Gilbert 
293fd32119bSDouglas Gilbert struct sdebug_dev_info {
294fd32119bSDouglas Gilbert 	struct list_head dev_list;
295fd32119bSDouglas Gilbert 	unsigned int channel;
296fd32119bSDouglas Gilbert 	unsigned int target;
297fd32119bSDouglas Gilbert 	u64 lun;
298bf476433SChristoph Hellwig 	uuid_t lu_name;
299fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
300fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
301fd32119bSDouglas Gilbert 	atomic_t num_in_q;
302c4837394SDouglas Gilbert 	atomic_t stopped;
303fd32119bSDouglas Gilbert 	bool used;
304f0d1cf93SDouglas Gilbert 
305f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
30664e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
307f0d1cf93SDouglas Gilbert 	unsigned int zsize;
308f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
309f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
310aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
311f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
312f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
313f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
314f0d1cf93SDouglas Gilbert 	unsigned int max_open;
315f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
316fd32119bSDouglas Gilbert };
317fd32119bSDouglas Gilbert 
318fd32119bSDouglas Gilbert struct sdebug_host_info {
319fd32119bSDouglas Gilbert 	struct list_head host_list;
32087c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
321fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
322fd32119bSDouglas Gilbert 	struct device dev;
323fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
324fd32119bSDouglas Gilbert };
325fd32119bSDouglas Gilbert 
32687c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
32787c715dcSDouglas Gilbert struct sdeb_store_info {
32887c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
32987c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
33087c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
33187c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
33287c715dcSDouglas Gilbert };
33387c715dcSDouglas Gilbert 
334fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
335fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
336fd32119bSDouglas Gilbert 
33710bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
33810bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
33910bde980SDouglas Gilbert 
340fd32119bSDouglas Gilbert struct sdebug_defer {
341fd32119bSDouglas Gilbert 	struct hrtimer hrt;
342fd32119bSDouglas Gilbert 	struct execute_work ew;
343c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
344c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
345c4837394SDouglas Gilbert 	int issuing_cpu;
34610bde980SDouglas Gilbert 	bool init_hrt;
34710bde980SDouglas Gilbert 	bool init_wq;
3487382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34910bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
350fd32119bSDouglas Gilbert };
351fd32119bSDouglas Gilbert 
352fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
353c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
354c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
355c4837394SDouglas Gilbert 	 */
356fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
357fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
358c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
359c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
360c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
361c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
362c4837394SDouglas Gilbert 	unsigned int inj_short:1;
3637ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
3647382f9d8SDouglas Gilbert 	unsigned int inj_cmd_abort:1;
365fd32119bSDouglas Gilbert };
366fd32119bSDouglas Gilbert 
367c4837394SDouglas Gilbert struct sdebug_queue {
368c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
369c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
370c4837394SDouglas Gilbert 	spinlock_t qc_lock;
371c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
372fd32119bSDouglas Gilbert };
373fd32119bSDouglas Gilbert 
374c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
375c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
376c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
377c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
378c4837394SDouglas Gilbert 
379fd32119bSDouglas Gilbert struct opcode_info_t {
380b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
381b01f6f83SDouglas Gilbert 				/* for terminating element */
382fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
383fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
384fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
385fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
386fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3879a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3889a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
389fd32119bSDouglas Gilbert };
390fd32119bSDouglas Gilbert 
391fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
392c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
393c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
394c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
395c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
396c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
397c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
398c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
399c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
400c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
401c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
402c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
403c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
404c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
40546f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
40646f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
407c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
408c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
409c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
410481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
411c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
412c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
413c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
414c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
415c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
416c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
417c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
418c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
419c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
420c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
421c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
422ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
423f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
424f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
425f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
426c2248fc9SDouglas Gilbert };
427c2248fc9SDouglas Gilbert 
428c4837394SDouglas Gilbert 
429c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
430c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
431c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
432c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
433c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
434c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
435c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
436c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
437c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
438c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
439c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
440c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
441ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
442c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
443c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
444c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
445c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
446c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
447c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
448c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
449fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
450c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
451c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
452c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
453c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
454c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
455c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
456c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
457f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
458f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
45946f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
460c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
461c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
462c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
46346f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
46446f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
465c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
466c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
467c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
468c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
469c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
470c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
471c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
472c2248fc9SDouglas Gilbert };
473c2248fc9SDouglas Gilbert 
47480c49563SDouglas Gilbert /*
47580c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
47680c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
47780c49563SDouglas Gilbert  * command completion, they can mask their return value with
47880c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
47980c49563SDouglas Gilbert  */
48080c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
48180c49563SDouglas Gilbert 
482c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
486c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
487c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
488c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
489c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
490c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
491481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
492c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
493c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
494c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
495c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
496c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
49738d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
49838d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
499c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
500c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
501c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
50238d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
503acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
50480c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
505ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
506f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
507f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
508f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
509f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
510f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
511c2248fc9SDouglas Gilbert 
51287c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
51387c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
51487c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
51587c715dcSDouglas Gilbert static int sdebug_add_store(void);
51687c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
51787c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
51887c715dcSDouglas Gilbert 
51946f64e70SDouglas Gilbert /*
52046f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
52146f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
52246f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
52346f64e70SDouglas Gilbert  */
52446f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
525c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
526c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527c2248fc9SDouglas Gilbert };
528c2248fc9SDouglas Gilbert 
52946f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
530c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
531c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
532c2248fc9SDouglas Gilbert };
533c2248fc9SDouglas Gilbert 
53446f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
53546f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
536b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
537c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
53846f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
539c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
54046f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
541b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
542c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
543c2248fc9SDouglas Gilbert };
544c2248fc9SDouglas Gilbert 
54546f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
54646f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
54746f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
54846f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
54946f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
55046f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
55146f64e70SDouglas Gilbert 		   0, 0, 0} },
55246f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
55346f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55446f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
555c2248fc9SDouglas Gilbert };
556c2248fc9SDouglas Gilbert 
557c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
558c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
559c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
560c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
561c3e2fe92SDouglas Gilbert };
562c3e2fe92SDouglas Gilbert 
56346f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
564c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
565c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56646f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
567c2248fc9SDouglas Gilbert };
568c2248fc9SDouglas Gilbert 
56946f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
57046f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
571b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
572c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
573481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
574481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
575481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
576c2248fc9SDouglas Gilbert };
577c2248fc9SDouglas Gilbert 
57846f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
57938d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
580c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
58146f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
58238d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
583c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
58446f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
585c2248fc9SDouglas Gilbert };
586c2248fc9SDouglas Gilbert 
58746f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
58846f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
589c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59046f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
591c2248fc9SDouglas Gilbert };
592c2248fc9SDouglas Gilbert 
59346f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
594c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
595c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
596c2248fc9SDouglas Gilbert };
597c2248fc9SDouglas Gilbert 
59846f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
599c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
600c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
601c2248fc9SDouglas Gilbert };
602c2248fc9SDouglas Gilbert 
60380c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
6044f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
60580c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60680c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
60780c49563SDouglas Gilbert };
60880c49563SDouglas Gilbert 
609ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
610ed9f3e25SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | F_M_ACCESS, resp_pre_fetch, NULL,
611ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
613ed9f3e25SDouglas Gilbert };
614ed9f3e25SDouglas Gilbert 
615f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
616f0d1cf93SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW, resp_close_zone, NULL,
617f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
618f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
619f0d1cf93SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW, resp_finish_zone, NULL,
620f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
621f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
622f0d1cf93SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW, resp_rwp_zone, NULL,
623f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
624f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
625f0d1cf93SDouglas Gilbert };
626f0d1cf93SDouglas Gilbert 
627f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
628f0d1cf93SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN, NULL, NULL,
629f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
630f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
631f0d1cf93SDouglas Gilbert };
632f0d1cf93SDouglas Gilbert 
633c2248fc9SDouglas Gilbert 
634c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
635c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
636c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
637ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
638c2248fc9SDouglas Gilbert /* 0 */
63946f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
640c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64146f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
642c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
643c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
644c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
64546f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
646c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
647c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
648c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
649c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
65046f64e70SDouglas Gilbert /* 5 */
65146f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
65246f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
65346f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65446f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
65546f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
65646f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
65746f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
658c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
659c2248fc9SDouglas Gilbert 	     0, 0, 0} },
66046f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
661c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
662c2248fc9SDouglas Gilbert 	     0, 0} },
66346f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
66446f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
66546f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
666c2248fc9SDouglas Gilbert /* 10 */
66746f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
66846f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
66946f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67080c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6714f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
672c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
67346f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
67446f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
67546f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67646f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
677481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
678481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
679481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
68046f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
68146f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
68246f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
68346f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
68446f64e70SDouglas Gilbert /* 15 */
685c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
686c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
687c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
688c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
689c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
690c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
69146f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
69246f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
69346f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
69446f64e70SDouglas Gilbert 	     0xff, 0xff} },
69546f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
69646f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
697c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
698c2248fc9SDouglas Gilbert 	     0} },
69946f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
70046f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
701c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
702c2248fc9SDouglas Gilbert 	     0} },
703c2248fc9SDouglas Gilbert /* 20 */
704f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
705f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
706c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
707c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
708c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
709c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
710c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
711c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
71246f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
713b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
71446f64e70SDouglas Gilbert /* 25 */
715acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
716acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
717acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
71846f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
71946f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
72046f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
72146f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7224f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
72380c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
724b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
72580c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
72646f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
727c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
728b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
729ed9f3e25SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | F_M_ACCESS,
730ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
731ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
732ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
733c2248fc9SDouglas Gilbert 
734ed9f3e25SDouglas Gilbert /* 30 */
735f0d1cf93SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW,
736f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
737f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
738f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
739f0d1cf93SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_D_IN,
740f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
741f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
742f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
743f0d1cf93SDouglas Gilbert /* sentinel */
744c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
745c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
746c2248fc9SDouglas Gilbert };
747c2248fc9SDouglas Gilbert 
74887c715dcSDouglas Gilbert static int sdebug_num_hosts;
74987c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
750773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7519b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
752c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7539267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
754773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
755773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
756773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
757773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
758773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
759773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
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;
778773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
779773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
780773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
781773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
782773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
783773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
784773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
785773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
786773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
787773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
788773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
78909ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7900c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
79187c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
792773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
793773642d9SDouglas Gilbert static bool sdebug_clustering;
794773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
795773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
796817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
797773642d9SDouglas Gilbert static bool sdebug_verbose;
798f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7994f2c8bf6SDouglas Gilbert static bool write_since_sync;
800c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
8019447b6ceSMartin K. Petersen static bool sdebug_wp;
8029267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
8039267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
8049267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
8051da177e4SLinus Torvalds 
806c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8071da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8101da177e4SLinus Torvalds    may still need them */
8111da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8121da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8131da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8161da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
8171da177e4SLinus Torvalds 
81887c715dcSDouglas Gilbert static struct xarray per_store_arr;
81987c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
82087c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
82187c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
82287c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8231da177e4SLinus Torvalds 
82444d92694SMartin K. Petersen static unsigned long map_size;
825cbf67842SDouglas Gilbert static int num_aborts;
826cbf67842SDouglas Gilbert static int num_dev_resets;
827cbf67842SDouglas Gilbert static int num_target_resets;
828cbf67842SDouglas Gilbert static int num_bus_resets;
829cbf67842SDouglas Gilbert static int num_host_resets;
830c6a44287SMartin K. Petersen static int dix_writes;
831c6a44287SMartin K. Petersen static int dix_reads;
832c6a44287SMartin K. Petersen static int dif_errors;
8331da177e4SLinus Torvalds 
834f0d1cf93SDouglas Gilbert /* ZBC global data */
83564e14eceSDamien Le Moal static bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
83698e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
837380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
838aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
839f0d1cf93SDouglas Gilbert 
840c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
841c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
842fd32119bSDouglas Gilbert 
8431da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
84487c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
84587c715dcSDouglas Gilbert 
84687c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
8471da177e4SLinus Torvalds 
848cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
849cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8541da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8551da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8561da177e4SLinus Torvalds };
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds static const int check_condition_result =
8591da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8601da177e4SLinus Torvalds 
861c6a44287SMartin K. Petersen static const int illegal_condition_result =
862c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
863c6a44287SMartin K. Petersen 
864cbf67842SDouglas Gilbert static const int device_qfull_result =
865cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
866cbf67842SDouglas Gilbert 
867ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
868ed9f3e25SDouglas Gilbert 
869fd32119bSDouglas Gilbert 
870760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
871760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
872760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
873760f3b03SDouglas Gilbert  */
874760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
875fd32119bSDouglas Gilbert {
876fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
877fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
878fd32119bSDouglas Gilbert }
879c65b1445SDouglas Gilbert 
88087c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
88187c715dcSDouglas Gilbert 			    unsigned long long lba)
88214faa944SAkinobu Mita {
88387c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
88414faa944SAkinobu Mita 
88587c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88687c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88787c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
88887c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
88987c715dcSDouglas Gilbert 	}
89087c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
89114faa944SAkinobu Mita }
89214faa944SAkinobu Mita 
89387c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
89487c715dcSDouglas Gilbert 				      sector_t sector)
89514faa944SAkinobu Mita {
89649413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89714faa944SAkinobu Mita 
89887c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
89914faa944SAkinobu Mita }
90014faa944SAkinobu Mita 
9018dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
9028dea0d02SFUJITA Tomonori {
9038dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9048dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9058dea0d02SFUJITA Tomonori 
9068dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
9078dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9088dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9098dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
910773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
911773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9128dea0d02SFUJITA Tomonori 		else
913773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
914773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
915f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9168dea0d02SFUJITA Tomonori 	}
9178dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
9188dea0d02SFUJITA Tomonori }
9198dea0d02SFUJITA Tomonori 
92022017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
92122017ed2SDouglas Gilbert 
92222017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
923fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
924fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92522017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92622017ed2SDouglas Gilbert {
92722017ed2SDouglas Gilbert 	unsigned char *sbuff;
92822017ed2SDouglas Gilbert 	u8 sks[4];
92922017ed2SDouglas Gilbert 	int sl, asc;
93022017ed2SDouglas Gilbert 
93122017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
93222017ed2SDouglas Gilbert 	if (!sbuff) {
93322017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
93422017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93522017ed2SDouglas Gilbert 		return;
93622017ed2SDouglas Gilbert 	}
93722017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
93822017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
939773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
94022017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
94122017ed2SDouglas Gilbert 	sks[0] = 0x80;
94222017ed2SDouglas Gilbert 	if (c_d)
94322017ed2SDouglas Gilbert 		sks[0] |= 0x40;
94422017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94522017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94622017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94722017ed2SDouglas Gilbert 	}
94822017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
949773642d9SDouglas Gilbert 	if (sdebug_dsense) {
95022017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
95122017ed2SDouglas Gilbert 		sbuff[7] = sl;
95222017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
95322017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
95422017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95522017ed2SDouglas Gilbert 	} else
95622017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
957773642d9SDouglas Gilbert 	if (sdebug_verbose)
95822017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
95922017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
96022017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
96122017ed2SDouglas Gilbert }
96222017ed2SDouglas Gilbert 
963cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9648dea0d02SFUJITA Tomonori {
9658dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
9668dea0d02SFUJITA Tomonori 
967cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
968cbf67842SDouglas Gilbert 	if (!sbuff) {
969cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
970cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
971cbf67842SDouglas Gilbert 		return;
972cbf67842SDouglas Gilbert 	}
973cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9748dea0d02SFUJITA Tomonori 
975773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9768dea0d02SFUJITA Tomonori 
977773642d9SDouglas Gilbert 	if (sdebug_verbose)
978cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
979cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
980cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9818dea0d02SFUJITA Tomonori }
9821da177e4SLinus Torvalds 
983fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
98422017ed2SDouglas Gilbert {
98522017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
98622017ed2SDouglas Gilbert }
98722017ed2SDouglas Gilbert 
9886f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9896f4e626fSNathan Chancellor 			    void __user *arg)
9901da177e4SLinus Torvalds {
991773642d9SDouglas Gilbert 	if (sdebug_verbose) {
992cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
993cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
994cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
995cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
996cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
997cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
998cbf67842SDouglas Gilbert 				    __func__);
999cbf67842SDouglas Gilbert 		else
1000cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
1001cbf67842SDouglas Gilbert 				    __func__, cmd);
10021da177e4SLinus Torvalds 	}
10031da177e4SLinus Torvalds 	return -EINVAL;
10041da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
10079b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10089b760fd8SDouglas Gilbert {
10099b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10109b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10119b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10129b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10139b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10149b760fd8SDouglas Gilbert 		break;
10159b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10179b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10189b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10199b760fd8SDouglas Gilbert 		break;
10209b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10229b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10239b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10249b760fd8SDouglas Gilbert 		break;
10259b760fd8SDouglas Gilbert 	case 16:
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10279b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10289b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10299b760fd8SDouglas Gilbert 		break;
10309b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10329b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10339b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10349b760fd8SDouglas Gilbert 		break;
10359b760fd8SDouglas Gilbert 	default:
10369b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10379b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10389b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10399b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10409b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10419b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10429b760fd8SDouglas Gilbert 		break;
10439b760fd8SDouglas Gilbert 	}
10449b760fd8SDouglas Gilbert }
10459b760fd8SDouglas Gilbert 
10469b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10479b760fd8SDouglas Gilbert {
10489b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10499b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10509b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10519b760fd8SDouglas Gilbert 
10529b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
10539b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10549b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10559b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10569b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10579b760fd8SDouglas Gilbert 		}
10589b760fd8SDouglas Gilbert 	}
10599b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
10609b760fd8SDouglas Gilbert }
10619b760fd8SDouglas Gilbert 
106219c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
106319c8ead7SEwan D. Milne {
106419c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
106519c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
106619c8ead7SEwan D. Milne 
106719c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
106819c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
106919c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
107019c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
107119c8ead7SEwan D. Milne 			    (devip->target == dp->target))
107219c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
107319c8ead7SEwan D. Milne 		}
107419c8ead7SEwan D. Milne 	}
107519c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
107619c8ead7SEwan D. Milne }
107719c8ead7SEwan D. Milne 
1078f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10791da177e4SLinus Torvalds {
1080cbf67842SDouglas Gilbert 	int k;
1081cbf67842SDouglas Gilbert 
1082cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1083cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1084cbf67842SDouglas Gilbert 		const char *cp = NULL;
1085cbf67842SDouglas Gilbert 
1086cbf67842SDouglas Gilbert 		switch (k) {
1087cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1088f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1089f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1090773642d9SDouglas Gilbert 			if (sdebug_verbose)
1091cbf67842SDouglas Gilbert 				cp = "power on reset";
1092cbf67842SDouglas Gilbert 			break;
1093cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1094f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1095f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1096773642d9SDouglas Gilbert 			if (sdebug_verbose)
1097cbf67842SDouglas Gilbert 				cp = "bus reset";
1098cbf67842SDouglas Gilbert 			break;
1099cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1100f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1101f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1102773642d9SDouglas Gilbert 			if (sdebug_verbose)
1103cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1104cbf67842SDouglas Gilbert 			break;
11050d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1106f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1107f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1108773642d9SDouglas Gilbert 			if (sdebug_verbose)
11090d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1110f49accf1SEwan D. Milne 			break;
1111acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1112f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1113b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1114b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1115773642d9SDouglas Gilbert 			if (sdebug_verbose)
1116acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1117acafd0b9SEwan D. Milne 			break;
1118acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1119f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1120acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1121acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1122773642d9SDouglas Gilbert 			if (sdebug_verbose)
1123acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1124acafd0b9SEwan D. Milne 			break;
112519c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
112619c8ead7SEwan D. Milne 			/*
112719c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
112819c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
112919c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
113019c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1131773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
113219c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
113319c8ead7SEwan D. Milne 			 */
1134773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
113519c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1136f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
113719c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
113819c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1139773642d9SDouglas Gilbert 			if (sdebug_verbose)
114019c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
114119c8ead7SEwan D. Milne 			break;
1142cbf67842SDouglas Gilbert 		default:
1143773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1144773642d9SDouglas Gilbert 			if (sdebug_verbose)
1145cbf67842SDouglas Gilbert 				cp = "unknown";
1146cbf67842SDouglas Gilbert 			break;
1147cbf67842SDouglas Gilbert 		}
1148cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1149773642d9SDouglas Gilbert 		if (sdebug_verbose)
1150f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1151cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1152cbf67842SDouglas Gilbert 				   my_name, cp);
11531da177e4SLinus Torvalds 		return check_condition_result;
11541da177e4SLinus Torvalds 	}
11551da177e4SLinus Torvalds 	return 0;
11561da177e4SLinus Torvalds }
11571da177e4SLinus Torvalds 
1158fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11591da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11601da177e4SLinus Torvalds 				int arr_len)
11611da177e4SLinus Torvalds {
116221a61829SFUJITA Tomonori 	int act_len;
1163ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11641da177e4SLinus Torvalds 
1165072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11661da177e4SLinus Torvalds 		return 0;
1167ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1168773642d9SDouglas Gilbert 		return DID_ERROR << 16;
116921a61829SFUJITA Tomonori 
117021a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
117121a61829SFUJITA Tomonori 				      arr, arr_len);
117242d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
117321a61829SFUJITA Tomonori 
11741da177e4SLinus Torvalds 	return 0;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
1177fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1178fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1179fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1180fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1181fb0cc8d1SDouglas Gilbert  */
1182fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1183fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1184fb0cc8d1SDouglas Gilbert {
11859237f04eSDamien Le Moal 	unsigned int act_len, n;
1186ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1187fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1188fb0cc8d1SDouglas Gilbert 
1189fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1190fb0cc8d1SDouglas Gilbert 		return 0;
1191ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1192fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1193fb0cc8d1SDouglas Gilbert 
1194fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1195fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1196fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
119742d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
119842d387beSBart Van Assche 		 scsi_get_resid(scp));
11999237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
120087c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1201fb0cc8d1SDouglas Gilbert 	return 0;
1202fb0cc8d1SDouglas Gilbert }
1203fb0cc8d1SDouglas Gilbert 
1204fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1205fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1206fb0cc8d1SDouglas Gilbert  */
12071da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
120821a61829SFUJITA Tomonori 			       int arr_len)
12091da177e4SLinus Torvalds {
121021a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12111da177e4SLinus Torvalds 		return 0;
1212ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12131da177e4SLinus Torvalds 		return -1;
121421a61829SFUJITA Tomonori 
121521a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds 
12181da177e4SLinus Torvalds 
1219e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1220e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12219b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12221b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12231b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12241b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12251b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12261da177e4SLinus Torvalds 
1227cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1228760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12295a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
123009ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1231bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12321da177e4SLinus Torvalds {
1233c65b1445SDouglas Gilbert 	int num, port_a;
1234c65b1445SDouglas Gilbert 	char b[32];
12351da177e4SLinus Torvalds 
1236c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12371da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12381da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12391da177e4SLinus Torvalds 	arr[1] = 0x1;
12401da177e4SLinus Torvalds 	arr[2] = 0x0;
1241e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1242e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12431da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12441da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12451da177e4SLinus Torvalds 	arr[3] = num;
12461da177e4SLinus Torvalds 	num += 4;
1247c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
124809ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
124909ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
125009ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
125109ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
125209ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125309ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
125409ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
125509ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125609ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
125709ba24c1SDouglas Gilbert 			num += 16;
125809ba24c1SDouglas Gilbert 		} else {
12591b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1260c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1261c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1262c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1263c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12641b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1265773642d9SDouglas Gilbert 			num += 8;
126609ba24c1SDouglas Gilbert 		}
1267c65b1445SDouglas Gilbert 		/* Target relative port number */
1268c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1269c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1270c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1271c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1272c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1273c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1274c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1275c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1276c65b1445SDouglas Gilbert 	}
12771b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1278c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1279c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1280c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1281c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12821b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1283773642d9SDouglas Gilbert 	num += 8;
12841b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12855a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12865a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12875a09e398SHannes Reinecke 	arr[num++] = 0x0;
12885a09e398SHannes Reinecke 	arr[num++] = 0x4;
12895a09e398SHannes Reinecke 	arr[num++] = 0;
12905a09e398SHannes Reinecke 	arr[num++] = 0;
1291773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1292773642d9SDouglas Gilbert 	num += 2;
12931b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1294c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1295c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1296c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1297c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12981b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1299773642d9SDouglas Gilbert 	num += 8;
1300c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1301c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1302c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1303c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1304c65b1445SDouglas Gilbert 	arr[num++] = 24;
13051b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1306c65b1445SDouglas Gilbert 	num += 12;
1307c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1308c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1309c65b1445SDouglas Gilbert 	num += 8;
1310c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1311c65b1445SDouglas Gilbert 	num += 4;
1312c65b1445SDouglas Gilbert 	return num;
1313c65b1445SDouglas Gilbert }
1314c65b1445SDouglas Gilbert 
1315c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1316c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1317c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1318c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1319c65b1445SDouglas Gilbert };
1320c65b1445SDouglas Gilbert 
1321cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1322760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1323c65b1445SDouglas Gilbert {
1324c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1325c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1326c65b1445SDouglas Gilbert }
1327c65b1445SDouglas Gilbert 
1328cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1329760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1330c65b1445SDouglas Gilbert {
1331c65b1445SDouglas Gilbert 	int num = 0;
1332c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1333c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1334c65b1445SDouglas Gilbert 	int plen, olen;
1335c65b1445SDouglas Gilbert 
1336c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1337c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1338c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1339c65b1445SDouglas Gilbert 	olen = strlen(na1);
1340c65b1445SDouglas Gilbert 	plen = olen + 1;
1341c65b1445SDouglas Gilbert 	if (plen % 4)
1342c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1343c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1344c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1345c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1346c65b1445SDouglas Gilbert 	num += plen;
1347c65b1445SDouglas Gilbert 
1348c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1349c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1350c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1351c65b1445SDouglas Gilbert 	olen = strlen(na2);
1352c65b1445SDouglas Gilbert 	plen = olen + 1;
1353c65b1445SDouglas Gilbert 	if (plen % 4)
1354c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1355c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1356c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1357c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1358c65b1445SDouglas Gilbert 	num += plen;
1359c65b1445SDouglas Gilbert 
1360c65b1445SDouglas Gilbert 	return num;
1361c65b1445SDouglas Gilbert }
1362c65b1445SDouglas Gilbert 
1363c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1364760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1365c65b1445SDouglas Gilbert {
1366c65b1445SDouglas Gilbert 	int num = 0;
1367c65b1445SDouglas Gilbert 	int port_a, port_b;
1368c65b1445SDouglas Gilbert 
1369c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1370c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1371c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1372c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1374c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1375c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1376c65b1445SDouglas Gilbert 	num += 6;
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1378c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1379c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1380c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1381c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13841b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1385773642d9SDouglas Gilbert 	num += 8;
1386c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1387c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1389c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1390c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1391c65b1445SDouglas Gilbert 	num += 6;
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1393c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1394c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1395c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1396c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1397c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1398c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13991b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1400773642d9SDouglas Gilbert 	num += 8;
1401c65b1445SDouglas Gilbert 
1402c65b1445SDouglas Gilbert 	return num;
1403c65b1445SDouglas Gilbert }
1404c65b1445SDouglas Gilbert 
1405c65b1445SDouglas Gilbert 
1406c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1407c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1408c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1409c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1410c65b1445SDouglas Gilbert '1','2','3','4',
1411c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1412c65b1445SDouglas Gilbert 0xec,0,0,0,
1413c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1414c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1415c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1416c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1417c65b1445SDouglas Gilbert 0x53,0x41,
1418c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1419c65b1445SDouglas Gilbert 0x20,0x20,
1420c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1421c65b1445SDouglas Gilbert 0x10,0x80,
1422c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1423c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1424c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1425c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1426c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1427c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1428c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1429c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1430c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1432c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1433c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1434c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1435c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1438c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1444c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1445c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1446c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1448c65b1445SDouglas Gilbert };
1449c65b1445SDouglas Gilbert 
1450cbf67842SDouglas Gilbert /* ATA Information VPD page */
1451760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1452c65b1445SDouglas Gilbert {
1453c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1454c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1455c65b1445SDouglas Gilbert }
1456c65b1445SDouglas Gilbert 
1457c65b1445SDouglas Gilbert 
1458c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14591e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14601e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14611e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14621e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1463c65b1445SDouglas Gilbert };
1464c65b1445SDouglas Gilbert 
1465cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1466760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1467c65b1445SDouglas Gilbert {
1468ea61fca5SMartin K. Petersen 	unsigned int gran;
1469ea61fca5SMartin K. Petersen 
1470c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1471e308b3d1SMartin K. Petersen 
1472e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
147386e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
147486e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
147586e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
147686e6828aSLukas Herbolt 	else
1477773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1478773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1479e308b3d1SMartin K. Petersen 
1480e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1481773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1482773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
148344d92694SMartin K. Petersen 
1484e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1485773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1486e308b3d1SMartin K. Petersen 
1487773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1488e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1489773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1490e308b3d1SMartin K. Petersen 
1491e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1492773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
149344d92694SMartin K. Petersen 	}
149444d92694SMartin K. Petersen 
1495e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1496773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1497773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
149844d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
149944d92694SMartin K. Petersen 	}
150044d92694SMartin K. Petersen 
1501e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1502773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
15036014759cSMartin K. Petersen 
15045b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1505773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15065b94e232SMartin K. Petersen 
15075b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
150844d92694SMartin K. Petersen 
1509c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
15101da177e4SLinus Torvalds }
15111da177e4SLinus Torvalds 
15121e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
151364e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1514eac6e8e4SMatthew Wilcox {
1515eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1516eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15171e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15181e49f785SDouglas Gilbert 	arr[2] = 0;
15191e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
152064e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
152164e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1522eac6e8e4SMatthew Wilcox 
1523eac6e8e4SMatthew Wilcox 	return 0x3c;
1524eac6e8e4SMatthew Wilcox }
15251da177e4SLinus Torvalds 
1526760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1527760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15286014759cSMartin K. Petersen {
15293f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15306014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1531773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15326014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1533773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15346014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1535773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15365b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1537760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1538760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1539760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1540760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1541760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15423f0bc3b3SMartin K. Petersen 	return 0x4;
15436014759cSMartin K. Petersen }
15446014759cSMartin K. Petersen 
1545d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
1546f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1547d36da305SDouglas Gilbert {
1548d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1549d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1550d36da305SDouglas Gilbert 	/*
1551d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1552d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1553f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1554f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1555d36da305SDouglas Gilbert 	 */
1556d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1557d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
155864e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1559f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1560f0d1cf93SDouglas Gilbert 	else
1561d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
1562d36da305SDouglas Gilbert 	return 0x3c;
1563d36da305SDouglas Gilbert }
1564d36da305SDouglas Gilbert 
15651da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1566c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
15671da177e4SLinus Torvalds 
1568c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15691da177e4SLinus Torvalds {
15701da177e4SLinus Torvalds 	unsigned char pq_pdt;
15715a09e398SHannes Reinecke 	unsigned char *arr;
157201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15735a09e398SHannes Reinecke 	int alloc_len, n, ret;
1574d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15751da177e4SLinus Torvalds 
1576773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15776f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15786f3cbf55SDouglas Gilbert 	if (! arr)
15796f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1580760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
158164e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1582d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1583b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1584c2248fc9SDouglas Gilbert 	if (have_wlun)
1585b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1586b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1587b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1588c65b1445SDouglas Gilbert 	else
1589773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15901da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15911da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
159222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15935a09e398SHannes Reinecke 		kfree(arr);
15941da177e4SLinus Torvalds 		return check_condition_result;
15951da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15965a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1597c65b1445SDouglas Gilbert 		char lu_id_str[6];
1598c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
15991da177e4SLinus Torvalds 
16005a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16015a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1602b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
160323183910SDouglas Gilbert 			host_no = 0;
1604c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1605c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1606c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1607c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1608c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16091da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1610c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1611c65b1445SDouglas Gilbert 			n = 4;
1612c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1613c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1615c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1616c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1617c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1618c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1619c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1620d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1621c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1622760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1623760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1624d36da305SDouglas Gilbert 				if (is_disk)
1625d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
162664e14eceSDamien Le Moal 				if (is_zbc)
1627d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1628760f3b03SDouglas Gilbert 			}
1629c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16301da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1631c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16321da177e4SLinus Torvalds 			arr[3] = len;
1633c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16341da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1635c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1636760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16375a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
163809ba24c1SDouglas Gilbert 						lu_id_str, len,
163909ba24c1SDouglas Gilbert 						&devip->lu_name);
1640c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1641c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1642760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1643c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1644c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1645760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1646c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1647c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1648c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16498475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1650c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1651760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1652c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1653c6a44287SMartin K. Petersen 			else
1654c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1655c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1656c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1657c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1658c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1659c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1660c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1661c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1662c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1663c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1664c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1665760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1666d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1667c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1668760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1669773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1670d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1671c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1672760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1673d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1674eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
167564e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1676760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16776014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1678760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1679d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1680d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1681f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16821da177e4SLinus Torvalds 		} else {
168322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16845a09e398SHannes Reinecke 			kfree(arr);
16851da177e4SLinus Torvalds 			return check_condition_result;
16861da177e4SLinus Torvalds 		}
1687773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
16885a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1689c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
16905a09e398SHannes Reinecke 		kfree(arr);
16915a09e398SHannes Reinecke 		return ret;
16921da177e4SLinus Torvalds 	}
16931da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1694773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1695773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16961da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16971da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1698f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1699b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
170070bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1701c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17021da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1703c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1704e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1705e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1706e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17079b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17089b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17091da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1710760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1711760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1712c65b1445SDouglas Gilbert 	n = 62;
1713760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1714760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1715760f3b03SDouglas Gilbert 		n += 2;
1716760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1717760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1718760f3b03SDouglas Gilbert 		n += 2;
1719d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1720d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1721d36da305SDouglas Gilbert 		n += 2;
17221da177e4SLinus Torvalds 	}
1723760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17245a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
172587c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
17265a09e398SHannes Reinecke 	kfree(arr);
17275a09e398SHannes Reinecke 	return ret;
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds 
1730fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1731fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1732fd32119bSDouglas Gilbert 
17331da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17341da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17351da177e4SLinus Torvalds {
17361da177e4SLinus Torvalds 	unsigned char *sbuff;
173701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1738cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
17392492fc09STomas Winkler 	bool dsense;
17401da177e4SLinus Torvalds 	int len = 18;
17411da177e4SLinus Torvalds 
1742c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1743c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1744cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1745c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1746c2248fc9SDouglas Gilbert 		if (dsense) {
1747c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1748c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1749c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1750c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1751c2248fc9SDouglas Gilbert 			len = 8;
1752c65b1445SDouglas Gilbert 		} else {
1753c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1754c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1755c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1756c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1757c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1758c65b1445SDouglas Gilbert 		}
1759c65b1445SDouglas Gilbert 	} else {
1760cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1761773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1762c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1763c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1764c2248fc9SDouglas Gilbert 			if (dsense) {
1765c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1766c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1767c2248fc9SDouglas Gilbert 				len = 8;
1768c2248fc9SDouglas Gilbert 			} else {
1769c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1770c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1771c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1772c2248fc9SDouglas Gilbert 			}
1773c2248fc9SDouglas Gilbert 		} else if (dsense) {
1774c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
17751da177e4SLinus Torvalds 			arr[0] = 0x72;
17761da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
17771da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
17781da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
17791da177e4SLinus Torvalds 			len = 8;
1780c2248fc9SDouglas Gilbert 		} else {
1781c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1782c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1783c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1784c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1785c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1786c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1787c65b1445SDouglas Gilbert 		}
1788c2248fc9SDouglas Gilbert 
1789c65b1445SDouglas Gilbert 	}
1790cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
17911da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
1794c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1795c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1796c65b1445SDouglas Gilbert {
179701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1798c4837394SDouglas Gilbert 	int power_cond, stop;
17994f2c8bf6SDouglas Gilbert 	bool changing;
1800c65b1445SDouglas Gilbert 
1801c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1802c65b1445SDouglas Gilbert 	if (power_cond) {
180322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1804c65b1445SDouglas Gilbert 		return check_condition_result;
1805c65b1445SDouglas Gilbert 	}
1806c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
18074f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1808c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
18094f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
18104f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18114f2c8bf6SDouglas Gilbert 	else
18124f2c8bf6SDouglas Gilbert 		return 0;
1813c65b1445SDouglas Gilbert }
1814c65b1445SDouglas Gilbert 
181528898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
181628898873SFUJITA Tomonori {
1817773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1818773642d9SDouglas Gilbert 
1819773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1820773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1821773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
182228898873SFUJITA Tomonori 	else
182328898873SFUJITA Tomonori 		return sdebug_store_sectors;
182428898873SFUJITA Tomonori }
182528898873SFUJITA Tomonori 
18261da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
18271da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18281da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18291da177e4SLinus Torvalds {
18301da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1831c65b1445SDouglas Gilbert 	unsigned int capac;
18321da177e4SLinus Torvalds 
1833c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
183428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18351da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1836c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1837c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1838773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1839773642d9SDouglas Gilbert 	} else
1840773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1841773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18421da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18431da177e4SLinus Torvalds }
18441da177e4SLinus Torvalds 
1845c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1846c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1847c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1848c65b1445SDouglas Gilbert {
184901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1850c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1851773642d9SDouglas Gilbert 	int alloc_len;
1852c65b1445SDouglas Gilbert 
1853773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1854c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
185528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1856c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1857773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1858773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1859773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1860773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
186144d92694SMartin K. Petersen 
1862be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18635b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1864760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1865760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1866760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1867760f3b03SDouglas Gilbert 		 */
1868760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1869760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1870be1dd78dSEric Sandeen 	}
187144d92694SMartin K. Petersen 
1872773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1873c6a44287SMartin K. Petersen 
1874760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1875773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1876c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1877c6a44287SMartin K. Petersen 	}
1878c6a44287SMartin K. Petersen 
1879c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
188087c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1881c65b1445SDouglas Gilbert }
1882c65b1445SDouglas Gilbert 
18835a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
18845a09e398SHannes Reinecke 
18855a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
18865a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
18875a09e398SHannes Reinecke {
188801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
18895a09e398SHannes Reinecke 	unsigned char *arr;
18905a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
18915a09e398SHannes Reinecke 	int n, ret, alen, rlen;
18925a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
18935a09e398SHannes Reinecke 
1894773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
18956f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
18966f3cbf55SDouglas Gilbert 	if (! arr)
18976f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
18985a09e398SHannes Reinecke 	/*
18995a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19005a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19015a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19025a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19035a09e398SHannes Reinecke 	 */
19045a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19055a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19065a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19075a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19085a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19095a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19105a09e398SHannes Reinecke 
19115a09e398SHannes Reinecke 	/*
19125a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19135a09e398SHannes Reinecke 	 */
19145a09e398SHannes Reinecke 	n = 4;
1915b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19165a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19175a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19185a09e398SHannes Reinecke 	} else {
19195a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1920773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19215a09e398SHannes Reinecke 	}
1922773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1923773642d9SDouglas Gilbert 	n += 2;
19245a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19255a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19265a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19275a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19285a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19295a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1930773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1931773642d9SDouglas Gilbert 	n += 2;
19325a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19335a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1934773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1935773642d9SDouglas Gilbert 	n += 2;
19365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19395a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19415a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1942773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1943773642d9SDouglas Gilbert 	n += 2;
19445a09e398SHannes Reinecke 
19455a09e398SHannes Reinecke 	rlen = n - 4;
1946773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19475a09e398SHannes Reinecke 
19485a09e398SHannes Reinecke 	/*
19495a09e398SHannes Reinecke 	 * Return the smallest value of either
19505a09e398SHannes Reinecke 	 * - The allocated length
19515a09e398SHannes Reinecke 	 * - The constructed command length
19525a09e398SHannes Reinecke 	 * - The maximum array size
19535a09e398SHannes Reinecke 	 */
195487c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
19555a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
195687c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19575a09e398SHannes Reinecke 	kfree(arr);
19585a09e398SHannes Reinecke 	return ret;
19595a09e398SHannes Reinecke }
19605a09e398SHannes Reinecke 
1961fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1962fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
196338d5c833SDouglas Gilbert {
196438d5c833SDouglas Gilbert 	bool rctd;
196538d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
196638d5c833SDouglas Gilbert 	u16 req_sa, u;
196738d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
196838d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
196938d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
197038d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
197138d5c833SDouglas Gilbert 	u8 *arr;
197238d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
197338d5c833SDouglas Gilbert 
197438d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
197538d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
197638d5c833SDouglas Gilbert 	req_opcode = cmd[3];
197738d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
197838d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
19796d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
198038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
198138d5c833SDouglas Gilbert 		return check_condition_result;
198238d5c833SDouglas Gilbert 	}
198338d5c833SDouglas Gilbert 	if (alloc_len > 8192)
198438d5c833SDouglas Gilbert 		a_len = 8192;
198538d5c833SDouglas Gilbert 	else
198638d5c833SDouglas Gilbert 		a_len = alloc_len;
198799531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
198838d5c833SDouglas Gilbert 	if (NULL == arr) {
198938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
199038d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
199138d5c833SDouglas Gilbert 		return check_condition_result;
199238d5c833SDouglas Gilbert 	}
199338d5c833SDouglas Gilbert 	switch (reporting_opts) {
199438d5c833SDouglas Gilbert 	case 0:	/* all commands */
199538d5c833SDouglas Gilbert 		/* count number of commands */
199638d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
199738d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
199838d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
199938d5c833SDouglas Gilbert 				continue;
200038d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
200138d5c833SDouglas Gilbert 		}
200238d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
200338d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
200438d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
200538d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
200638d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
200738d5c833SDouglas Gilbert 				continue;
200838d5c833SDouglas Gilbert 			na = oip->num_attached;
200938d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
201038d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
201138d5c833SDouglas Gilbert 			if (rctd)
201238d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
201338d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
201438d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
201538d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
201638d5c833SDouglas Gilbert 			if (rctd)
201738d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
201838d5c833SDouglas Gilbert 			r_oip = oip;
201938d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
202038d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
202138d5c833SDouglas Gilbert 					continue;
202238d5c833SDouglas Gilbert 				offset += bump;
202338d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
202438d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
202538d5c833SDouglas Gilbert 				if (rctd)
202638d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
202738d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
202838d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
202938d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
203038d5c833SDouglas Gilbert 						   arr + offset + 6);
203138d5c833SDouglas Gilbert 				if (rctd)
203238d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
203338d5c833SDouglas Gilbert 							   arr + offset + 8);
203438d5c833SDouglas Gilbert 			}
203538d5c833SDouglas Gilbert 			oip = r_oip;
203638d5c833SDouglas Gilbert 			offset += bump;
203738d5c833SDouglas Gilbert 		}
203838d5c833SDouglas Gilbert 		break;
203938d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
204038d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
204138d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
204238d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
204338d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
204438d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
204538d5c833SDouglas Gilbert 			supp = 1;
204638d5c833SDouglas Gilbert 			offset = 4;
204738d5c833SDouglas Gilbert 		} else {
204838d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
204938d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
205038d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
205138d5c833SDouglas Gilbert 							     2, 2);
205238d5c833SDouglas Gilbert 					kfree(arr);
205338d5c833SDouglas Gilbert 					return check_condition_result;
205438d5c833SDouglas Gilbert 				}
205538d5c833SDouglas Gilbert 				req_sa = 0;
205638d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
205738d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
205838d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
205938d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
206038d5c833SDouglas Gilbert 				return check_condition_result;
206138d5c833SDouglas Gilbert 			}
206238d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
206338d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
206438d5c833SDouglas Gilbert 				supp = 3;
206538d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
206638d5c833SDouglas Gilbert 				na = oip->num_attached;
206738d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
206838d5c833SDouglas Gilbert 				     ++k, ++oip) {
206938d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
207038d5c833SDouglas Gilbert 						break;
207138d5c833SDouglas Gilbert 				}
207238d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
207338d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
207438d5c833SDouglas Gilbert 				na = oip->num_attached;
207538d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
207638d5c833SDouglas Gilbert 				     ++k, ++oip) {
207738d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
207838d5c833SDouglas Gilbert 						break;
207938d5c833SDouglas Gilbert 				}
208038d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
208138d5c833SDouglas Gilbert 			} else
208238d5c833SDouglas Gilbert 				supp = 3;
208338d5c833SDouglas Gilbert 			if (3 == supp) {
208438d5c833SDouglas Gilbert 				u = oip->len_mask[0];
208538d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
208638d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
208738d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
208838d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
208938d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
209038d5c833SDouglas Gilbert 				offset = 4 + u;
209138d5c833SDouglas Gilbert 			} else
209238d5c833SDouglas Gilbert 				offset = 4;
209338d5c833SDouglas Gilbert 		}
209438d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
209538d5c833SDouglas Gilbert 		if (rctd) {
209638d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
209738d5c833SDouglas Gilbert 			offset += 12;
209838d5c833SDouglas Gilbert 		}
209938d5c833SDouglas Gilbert 		break;
210038d5c833SDouglas Gilbert 	default:
210138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
210238d5c833SDouglas Gilbert 		kfree(arr);
210338d5c833SDouglas Gilbert 		return check_condition_result;
210438d5c833SDouglas Gilbert 	}
210538d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
210638d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
210738d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
210838d5c833SDouglas Gilbert 	kfree(arr);
210938d5c833SDouglas Gilbert 	return errsts;
211038d5c833SDouglas Gilbert }
211138d5c833SDouglas Gilbert 
2112fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2113fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
211438d5c833SDouglas Gilbert {
211538d5c833SDouglas Gilbert 	bool repd;
211638d5c833SDouglas Gilbert 	u32 alloc_len, len;
211738d5c833SDouglas Gilbert 	u8 arr[16];
211838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
211938d5c833SDouglas Gilbert 
212038d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
212138d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
212238d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
212338d5c833SDouglas Gilbert 	if (alloc_len < 4) {
212438d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
212538d5c833SDouglas Gilbert 		return check_condition_result;
212638d5c833SDouglas Gilbert 	}
212738d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
212838d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
212938d5c833SDouglas Gilbert 	if (repd) {
213038d5c833SDouglas Gilbert 		arr[3] = 0xc;
213138d5c833SDouglas Gilbert 		len = 16;
213238d5c833SDouglas Gilbert 	} else
213338d5c833SDouglas Gilbert 		len = 4;
213438d5c833SDouglas Gilbert 
213538d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
213638d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
213738d5c833SDouglas Gilbert }
213838d5c833SDouglas Gilbert 
21391da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21401da177e4SLinus Torvalds 
21411da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21421da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21431da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21441da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21471da177e4SLinus Torvalds 	if (1 == pcontrol)
21481da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21491da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21501da177e4SLinus Torvalds }
21511da177e4SLinus Torvalds 
21521da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21531da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21541da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21551da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21561da177e4SLinus Torvalds 
21571da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21581da177e4SLinus Torvalds 	if (1 == pcontrol)
21591da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21601da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21611da177e4SLinus Torvalds }
21621da177e4SLinus Torvalds 
21631da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21641da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21651da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21661da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21671da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21681da177e4SLinus Torvalds 
21691da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2170773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2171773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2172773642d9SDouglas Gilbert 	if (sdebug_removable)
21731da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
21741da177e4SLinus Torvalds 	if (1 == pcontrol)
21751da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
21761da177e4SLinus Torvalds 	return sizeof(format_pg);
21771da177e4SLinus Torvalds }
21781da177e4SLinus Torvalds 
2179fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2180fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2181fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2182fd32119bSDouglas Gilbert 
21831da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
21841da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2185cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2186cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2187cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21881da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
21891da177e4SLinus Torvalds 
2190773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2191cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
21921da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
21931da177e4SLinus Torvalds 	if (1 == pcontrol)
2194cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2195cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2196cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
21971da177e4SLinus Torvalds 	return sizeof(caching_pg);
21981da177e4SLinus Torvalds }
21991da177e4SLinus Torvalds 
2200fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2201fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2202fd32119bSDouglas Gilbert 
22031da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22041da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2205c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2206c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2207c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22081da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22091da177e4SLinus Torvalds 
2210773642d9SDouglas Gilbert 	if (sdebug_dsense)
22111da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2212c65b1445SDouglas Gilbert 	else
2213c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2214c6a44287SMartin K. Petersen 
2215773642d9SDouglas Gilbert 	if (sdebug_ato)
2216c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2217c6a44287SMartin K. Petersen 
22181da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22191da177e4SLinus Torvalds 	if (1 == pcontrol)
2220c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2221c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2222c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22231da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22241da177e4SLinus Torvalds }
22251da177e4SLinus Torvalds 
2226c65b1445SDouglas Gilbert 
22271da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22281da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2229c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22301da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2231c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2232c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2233c65b1445SDouglas Gilbert 
22341da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22351da177e4SLinus Torvalds 	if (1 == pcontrol)
2236c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2237c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2238c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22391da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22401da177e4SLinus Torvalds }
22411da177e4SLinus Torvalds 
2242c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2243c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2244c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2245c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2246c65b1445SDouglas Gilbert 
2247c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2248c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2249c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2250c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2251c65b1445SDouglas Gilbert }
2252c65b1445SDouglas Gilbert 
2253c65b1445SDouglas Gilbert 
2254c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2255c65b1445SDouglas Gilbert 			      int target_dev_id)
2256c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2257c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2258c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2259773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2260773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2261c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2262c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2263c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2264c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2265773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2266773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2267c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2268c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2269c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2270c65b1445SDouglas Gilbert 		};
2271c65b1445SDouglas Gilbert 	int port_a, port_b;
2272c65b1445SDouglas Gilbert 
22731b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22741b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22751b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22761b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2277c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2278c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2279c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2280773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2281773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2282c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2283c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2284c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2285c65b1445SDouglas Gilbert }
2286c65b1445SDouglas Gilbert 
2287c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2288c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2289c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2290c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2291c65b1445SDouglas Gilbert 		};
2292c65b1445SDouglas Gilbert 
2293c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2294c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2295c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2296c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2297c65b1445SDouglas Gilbert }
2298c65b1445SDouglas Gilbert 
22991da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23001da177e4SLinus Torvalds 
2301fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2302fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23031da177e4SLinus Torvalds {
230423183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23051da177e4SLinus Torvalds 	unsigned char dev_spec;
2306760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2307c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23081da177e4SLinus Torvalds 	unsigned char *ap;
23091da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
231001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2311d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23121da177e4SLinus Torvalds 
2313760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23141da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23151da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23161da177e4SLinus Torvalds 	subpcode = cmd[3];
23171da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2318760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2319760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
232064e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2321d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
232223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
232323183910SDouglas Gilbert 	else
232423183910SDouglas Gilbert 		bd_len = 0;
2325773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23261da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23271da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2328cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23291da177e4SLinus Torvalds 		return check_condition_result;
23301da177e4SLinus Torvalds 	}
2331c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2332c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2333d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2334d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2335b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23369447b6ceSMartin K. Petersen 		if (sdebug_wp)
23379447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23389447b6ceSMartin K. Petersen 	} else
233923183910SDouglas Gilbert 		dev_spec = 0x0;
23401da177e4SLinus Torvalds 	if (msense_6) {
23411da177e4SLinus Torvalds 		arr[2] = dev_spec;
234223183910SDouglas Gilbert 		arr[3] = bd_len;
23431da177e4SLinus Torvalds 		offset = 4;
23441da177e4SLinus Torvalds 	} else {
23451da177e4SLinus Torvalds 		arr[3] = dev_spec;
234623183910SDouglas Gilbert 		if (16 == bd_len)
234723183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
234823183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23491da177e4SLinus Torvalds 		offset = 8;
23501da177e4SLinus Torvalds 	}
23511da177e4SLinus Torvalds 	ap = arr + offset;
235228898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
235328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
235428898873SFUJITA Tomonori 
235523183910SDouglas Gilbert 	if (8 == bd_len) {
2356773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2357773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2358773642d9SDouglas Gilbert 		else
2359773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2360773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
236123183910SDouglas Gilbert 		offset += bd_len;
236223183910SDouglas Gilbert 		ap = arr + offset;
236323183910SDouglas Gilbert 	} else if (16 == bd_len) {
2364773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2365773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
236623183910SDouglas Gilbert 		offset += bd_len;
236723183910SDouglas Gilbert 		ap = arr + offset;
236823183910SDouglas Gilbert 	}
23691da177e4SLinus Torvalds 
2370c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2371c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
237222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23731da177e4SLinus Torvalds 		return check_condition_result;
23741da177e4SLinus Torvalds 	}
2375760f3b03SDouglas Gilbert 	bad_pcode = false;
2376760f3b03SDouglas Gilbert 
23771da177e4SLinus Torvalds 	switch (pcode) {
23781da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
23791da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
23801da177e4SLinus Torvalds 		offset += len;
23811da177e4SLinus Torvalds 		break;
23821da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
23831da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
23841da177e4SLinus Torvalds 		offset += len;
23851da177e4SLinus Torvalds 		break;
23861da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2387760f3b03SDouglas Gilbert 		if (is_disk) {
23881da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
23891da177e4SLinus Torvalds 			offset += len;
2390760f3b03SDouglas Gilbert 		} else
2391760f3b03SDouglas Gilbert 			bad_pcode = true;
23921da177e4SLinus Torvalds 		break;
23931da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2394d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
23951da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
23961da177e4SLinus Torvalds 			offset += len;
2397760f3b03SDouglas Gilbert 		} else
2398760f3b03SDouglas Gilbert 			bad_pcode = true;
23991da177e4SLinus Torvalds 		break;
24001da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24011da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24021da177e4SLinus Torvalds 		offset += len;
24031da177e4SLinus Torvalds 		break;
2404c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2405c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
240622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2407c65b1445SDouglas Gilbert 			return check_condition_result;
2408c65b1445SDouglas Gilbert 		}
2409c65b1445SDouglas Gilbert 		len = 0;
2410c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2411c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2412c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2413c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2414c65b1445SDouglas Gilbert 						  target_dev_id);
2415c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2416c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2417c65b1445SDouglas Gilbert 		offset += len;
2418c65b1445SDouglas Gilbert 		break;
24191da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24201da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24211da177e4SLinus Torvalds 		offset += len;
24221da177e4SLinus Torvalds 		break;
24231da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2424c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24251da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24261da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2427760f3b03SDouglas Gilbert 			if (is_disk) {
2428760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2429760f3b03SDouglas Gilbert 						      target);
2430760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2431760f3b03SDouglas Gilbert 						       target);
2432d36da305SDouglas Gilbert 			} else if (is_zbc) {
2433d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2434d36da305SDouglas Gilbert 						       target);
2435760f3b03SDouglas Gilbert 			}
24361da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2437c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2438c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2439c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2440c65b1445SDouglas Gilbert 						  target, target_dev_id);
2441c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2442c65b1445SDouglas Gilbert 			}
24431da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2444760f3b03SDouglas Gilbert 			offset += len;
2445c65b1445SDouglas Gilbert 		} else {
244622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2447c65b1445SDouglas Gilbert 			return check_condition_result;
2448c65b1445SDouglas Gilbert 		}
24491da177e4SLinus Torvalds 		break;
24501da177e4SLinus Torvalds 	default:
2451760f3b03SDouglas Gilbert 		bad_pcode = true;
2452760f3b03SDouglas Gilbert 		break;
2453760f3b03SDouglas Gilbert 	}
2454760f3b03SDouglas Gilbert 	if (bad_pcode) {
245522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24561da177e4SLinus Torvalds 		return check_condition_result;
24571da177e4SLinus Torvalds 	}
24581da177e4SLinus Torvalds 	if (msense_6)
24591da177e4SLinus Torvalds 		arr[0] = offset - 1;
2460773642d9SDouglas Gilbert 	else
2461773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
246287c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
24631da177e4SLinus Torvalds }
24641da177e4SLinus Torvalds 
2465c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2466c65b1445SDouglas Gilbert 
2467fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2468fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2469c65b1445SDouglas Gilbert {
2470c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2471c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2472c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
247301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2474c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2475c65b1445SDouglas Gilbert 
2476c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2477c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2478c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2479773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2480c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
248122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2482c65b1445SDouglas Gilbert 		return check_condition_result;
2483c65b1445SDouglas Gilbert 	}
2484c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2485c65b1445SDouglas Gilbert 	if (-1 == res)
2486773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2487773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2488cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2489cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2490cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2491773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2492773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
249323183910SDouglas Gilbert 	if (md_len > 2) {
249422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2495c65b1445SDouglas Gilbert 		return check_condition_result;
2496c65b1445SDouglas Gilbert 	}
2497c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2498c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2499c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2500c65b1445SDouglas Gilbert 	if (ps) {
250122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2502c65b1445SDouglas Gilbert 		return check_condition_result;
2503c65b1445SDouglas Gilbert 	}
2504c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2505773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2506c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2507c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2508cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2509c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2510c65b1445SDouglas Gilbert 		return check_condition_result;
2511c65b1445SDouglas Gilbert 	}
2512c65b1445SDouglas Gilbert 	switch (mpage) {
2513cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2514cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2515cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2516cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2517cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2518cbf67842SDouglas Gilbert 		}
2519cbf67842SDouglas Gilbert 		break;
2520c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2521c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2522c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2523c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25249447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25259447b6ceSMartin K. Petersen 				sdebug_wp = true;
25269447b6ceSMartin K. Petersen 			else
25279447b6ceSMartin K. Petersen 				sdebug_wp = false;
2528773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2529cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2530c65b1445SDouglas Gilbert 		}
2531c65b1445SDouglas Gilbert 		break;
2532c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2533c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2534c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2535c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2536cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2537c65b1445SDouglas Gilbert 		}
2538c65b1445SDouglas Gilbert 		break;
2539c65b1445SDouglas Gilbert 	default:
2540c65b1445SDouglas Gilbert 		break;
2541c65b1445SDouglas Gilbert 	}
254222017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2543c65b1445SDouglas Gilbert 	return check_condition_result;
2544cbf67842SDouglas Gilbert set_mode_changed_ua:
2545cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2546cbf67842SDouglas Gilbert 	return 0;
2547c65b1445SDouglas Gilbert }
2548c65b1445SDouglas Gilbert 
2549c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2550c65b1445SDouglas Gilbert {
2551c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2552c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2553c65b1445SDouglas Gilbert 		};
2554c65b1445SDouglas Gilbert 
2555c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2556c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2557c65b1445SDouglas Gilbert }
2558c65b1445SDouglas Gilbert 
2559c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2560c65b1445SDouglas Gilbert {
2561c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2562c65b1445SDouglas Gilbert 		};
2563c65b1445SDouglas Gilbert 
2564c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2565c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2566c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2567c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2568c65b1445SDouglas Gilbert 	}
2569c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2570c65b1445SDouglas Gilbert }
2571c65b1445SDouglas Gilbert 
2572c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2573c65b1445SDouglas Gilbert 
2574c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2575c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2576c65b1445SDouglas Gilbert {
2577ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2578c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
257901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2580c65b1445SDouglas Gilbert 
2581c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2582c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2583c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2584c65b1445SDouglas Gilbert 	if (ppc || sp) {
258522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2586c65b1445SDouglas Gilbert 		return check_condition_result;
2587c65b1445SDouglas Gilbert 	}
2588c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
258923183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2590773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2591c65b1445SDouglas Gilbert 	arr[0] = pcode;
259223183910SDouglas Gilbert 	if (0 == subpcode) {
2593c65b1445SDouglas Gilbert 		switch (pcode) {
2594c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2595c65b1445SDouglas Gilbert 			n = 4;
2596c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2597c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2598c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2599c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2600c65b1445SDouglas Gilbert 			break;
2601c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2602c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2603c65b1445SDouglas Gilbert 			break;
2604c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2605c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2606c65b1445SDouglas Gilbert 			break;
2607c65b1445SDouglas Gilbert 		default:
260822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2609c65b1445SDouglas Gilbert 			return check_condition_result;
2610c65b1445SDouglas Gilbert 		}
261123183910SDouglas Gilbert 	} else if (0xff == subpcode) {
261223183910SDouglas Gilbert 		arr[0] |= 0x40;
261323183910SDouglas Gilbert 		arr[1] = subpcode;
261423183910SDouglas Gilbert 		switch (pcode) {
261523183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
261623183910SDouglas Gilbert 			n = 4;
261723183910SDouglas Gilbert 			arr[n++] = 0x0;
261823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
261923183910SDouglas Gilbert 			arr[n++] = 0x0;
262023183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
262123183910SDouglas Gilbert 			arr[n++] = 0xd;
262223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
262323183910SDouglas Gilbert 			arr[n++] = 0x2f;
262423183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
262523183910SDouglas Gilbert 			arr[3] = n - 4;
262623183910SDouglas Gilbert 			break;
262723183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
262823183910SDouglas Gilbert 			n = 4;
262923183910SDouglas Gilbert 			arr[n++] = 0xd;
263023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
263123183910SDouglas Gilbert 			arr[3] = n - 4;
263223183910SDouglas Gilbert 			break;
263323183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
263423183910SDouglas Gilbert 			n = 4;
263523183910SDouglas Gilbert 			arr[n++] = 0x2f;
263623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
263723183910SDouglas Gilbert 			arr[3] = n - 4;
263823183910SDouglas Gilbert 			break;
263923183910SDouglas Gilbert 		default:
264022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
264123183910SDouglas Gilbert 			return check_condition_result;
264223183910SDouglas Gilbert 		}
264323183910SDouglas Gilbert 	} else {
264422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
264523183910SDouglas Gilbert 		return check_condition_result;
264623183910SDouglas Gilbert 	}
264787c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2648c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
264987c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2650c65b1445SDouglas Gilbert }
2651c65b1445SDouglas Gilbert 
2652f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2653f0d1cf93SDouglas Gilbert {
2654f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2655f0d1cf93SDouglas Gilbert }
2656f0d1cf93SDouglas Gilbert 
2657f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2658f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2659f0d1cf93SDouglas Gilbert {
2660108e36f0SDamien Le Moal 	return &devip->zstate[lba >> devip->zsize_shift];
2661f0d1cf93SDouglas Gilbert }
2662f0d1cf93SDouglas Gilbert 
2663f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2664f0d1cf93SDouglas Gilbert {
266564e14eceSDamien Le Moal 	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
2666f0d1cf93SDouglas Gilbert }
2667f0d1cf93SDouglas Gilbert 
2668f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2669f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2670f0d1cf93SDouglas Gilbert {
2671f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2672f0d1cf93SDouglas Gilbert 
2673f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2674f0d1cf93SDouglas Gilbert 		return;
2675f0d1cf93SDouglas Gilbert 
2676f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2677f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2678f0d1cf93SDouglas Gilbert 		return;
2679f0d1cf93SDouglas Gilbert 
2680f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2681f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2682f0d1cf93SDouglas Gilbert 	else
2683f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2684f0d1cf93SDouglas Gilbert 
2685f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2686f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2687f0d1cf93SDouglas Gilbert 	} else {
2688f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2689f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2690f0d1cf93SDouglas Gilbert 	}
2691f0d1cf93SDouglas Gilbert }
2692f0d1cf93SDouglas Gilbert 
2693f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2694f0d1cf93SDouglas Gilbert {
2695f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2696f0d1cf93SDouglas Gilbert 	unsigned int i;
2697f0d1cf93SDouglas Gilbert 
2698f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2699f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2700f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2701f0d1cf93SDouglas Gilbert 			return;
2702f0d1cf93SDouglas Gilbert 		}
2703f0d1cf93SDouglas Gilbert 	}
2704f0d1cf93SDouglas Gilbert }
2705f0d1cf93SDouglas Gilbert 
2706f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2707f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2708f0d1cf93SDouglas Gilbert {
2709f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2710f0d1cf93SDouglas Gilbert 
2711f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2712f0d1cf93SDouglas Gilbert 		return;
2713f0d1cf93SDouglas Gilbert 
2714f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2715f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2716f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2717f0d1cf93SDouglas Gilbert 		return;
2718f0d1cf93SDouglas Gilbert 
2719f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2720f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2721f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2722f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2723f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2724f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2725f0d1cf93SDouglas Gilbert 
2726f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2727f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2728f0d1cf93SDouglas Gilbert 	if (explicit) {
2729f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2730f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2731f0d1cf93SDouglas Gilbert 	} else {
2732f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2733f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2734f0d1cf93SDouglas Gilbert 	}
2735f0d1cf93SDouglas Gilbert }
2736f0d1cf93SDouglas Gilbert 
2737f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2738f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2739f0d1cf93SDouglas Gilbert {
2740f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
274164e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2742f0d1cf93SDouglas Gilbert 
2743f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
2744f0d1cf93SDouglas Gilbert 		return;
2745f0d1cf93SDouglas Gilbert 
274664e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2747f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
274864e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2749f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC5_FULL;
275064e14eceSDamien Le Moal 		return;
275164e14eceSDamien Le Moal 	}
275264e14eceSDamien Le Moal 
275364e14eceSDamien Le Moal 	while (num) {
275464e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
275564e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
275664e14eceSDamien Le Moal 
275764e14eceSDamien Le Moal 		end = lba + num;
275864e14eceSDamien Le Moal 		if (end >= zend) {
275964e14eceSDamien Le Moal 			n = zend - lba;
276064e14eceSDamien Le Moal 			zsp->z_wp = zend;
276164e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
276264e14eceSDamien Le Moal 			n = num;
276364e14eceSDamien Le Moal 			zsp->z_wp = end;
276464e14eceSDamien Le Moal 		} else {
276564e14eceSDamien Le Moal 			n = num;
276664e14eceSDamien Le Moal 		}
276764e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
276864e14eceSDamien Le Moal 			zsp->z_cond = ZC5_FULL;
276964e14eceSDamien Le Moal 
277064e14eceSDamien Le Moal 		num -= n;
277164e14eceSDamien Le Moal 		lba += n;
277264e14eceSDamien Le Moal 		if (num) {
277364e14eceSDamien Le Moal 			zsp++;
277464e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
277564e14eceSDamien Le Moal 		}
277664e14eceSDamien Le Moal 	}
2777f0d1cf93SDouglas Gilbert }
2778f0d1cf93SDouglas Gilbert 
2779f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
27809447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
27811da177e4SLinus Torvalds {
2782f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2783f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2784f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2785f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2786f0d1cf93SDouglas Gilbert 
2787f0d1cf93SDouglas Gilbert 	if (!write) {
278864e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
278964e14eceSDamien Le Moal 			return 0;
279064e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
2791f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp &&
2792f0d1cf93SDouglas Gilbert 		    zbc_zone_is_conv(zsp) &&
2793f0d1cf93SDouglas Gilbert 		    !zbc_zone_is_conv(zsp_end)) {
2794f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2795f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2796f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2797f0d1cf93SDouglas Gilbert 			return check_condition_result;
2798f0d1cf93SDouglas Gilbert 		}
2799f0d1cf93SDouglas Gilbert 		return 0;
2800f0d1cf93SDouglas Gilbert 	}
2801f0d1cf93SDouglas Gilbert 
2802f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2803f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2804f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2805f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2806f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2807f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2808f0d1cf93SDouglas Gilbert 			return check_condition_result;
2809f0d1cf93SDouglas Gilbert 		}
2810f0d1cf93SDouglas Gilbert 		return 0;
2811f0d1cf93SDouglas Gilbert 	}
2812f0d1cf93SDouglas Gilbert 
281364e14eceSDamien Le Moal 	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2814f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2815f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2816f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2817f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2818f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2819f0d1cf93SDouglas Gilbert 			return check_condition_result;
2820f0d1cf93SDouglas Gilbert 		}
2821f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2822f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2823f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2824f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2825f0d1cf93SDouglas Gilbert 			return check_condition_result;
2826f0d1cf93SDouglas Gilbert 		}
2827f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2828f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2829f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2830f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2831f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2832f0d1cf93SDouglas Gilbert 			return check_condition_result;
2833f0d1cf93SDouglas Gilbert 		}
283464e14eceSDamien Le Moal 	}
2835f0d1cf93SDouglas Gilbert 
2836f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2837f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2838f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2839f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2840f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2841f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2842f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2843f0d1cf93SDouglas Gilbert 			return check_condition_result;
2844f0d1cf93SDouglas Gilbert 		}
2845f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2846f0d1cf93SDouglas Gilbert 	}
2847f0d1cf93SDouglas Gilbert 
2848f0d1cf93SDouglas Gilbert 	return 0;
2849f0d1cf93SDouglas Gilbert }
2850f0d1cf93SDouglas Gilbert 
2851f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2852f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2853f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2854f0d1cf93SDouglas Gilbert {
2855f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2856f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2857f0d1cf93SDouglas Gilbert 
2858c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
285922017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28601da177e4SLinus Torvalds 		return check_condition_result;
28611da177e4SLinus Torvalds 	}
2862c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2863c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
286422017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2865cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2866c65b1445SDouglas Gilbert 		return check_condition_result;
2867c65b1445SDouglas Gilbert 	}
28689447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
28699447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
28709447b6ceSMartin K. Petersen 		return check_condition_result;
28719447b6ceSMartin K. Petersen 	}
2872f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2873f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2874f0d1cf93SDouglas Gilbert 
287519789100SFUJITA Tomonori 	return 0;
287619789100SFUJITA Tomonori }
287719789100SFUJITA Tomonori 
287887c715dcSDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip)
287987c715dcSDouglas Gilbert {
288087c715dcSDouglas Gilbert 	return sdebug_fake_rw ?
288187c715dcSDouglas Gilbert 			NULL : xa_load(per_store_ap, devip->sdbg_host->si_idx);
288287c715dcSDouglas Gilbert }
288387c715dcSDouglas Gilbert 
2884a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
288587c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
288687c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
288719789100SFUJITA Tomonori {
288819789100SFUJITA Tomonori 	int ret;
2889c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2890a4517511SAkinobu Mita 	enum dma_data_direction dir;
289187c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
289287c715dcSDouglas Gilbert 	u8 *fsp;
289319789100SFUJITA Tomonori 
2894c2248fc9SDouglas Gilbert 	if (do_write) {
2895a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
28964f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2897a4517511SAkinobu Mita 	} else {
2898a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2899a4517511SAkinobu Mita 	}
2900a4517511SAkinobu Mita 
290187c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2902a4517511SAkinobu Mita 		return 0;
290387c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2904a4517511SAkinobu Mita 		return -1;
290587c715dcSDouglas Gilbert 	fsp = sip->storep;
290619789100SFUJITA Tomonori 
290719789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
290819789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
290919789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
291019789100SFUJITA Tomonori 
2911386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
291287c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
29130a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2914773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2915a4517511SAkinobu Mita 		return ret;
2916a4517511SAkinobu Mita 
2917a4517511SAkinobu Mita 	if (rest) {
2918386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
291987c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
29200a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
29210a7e69c7SDouglas Gilbert 			    do_write);
2922a4517511SAkinobu Mita 	}
292319789100SFUJITA Tomonori 
292419789100SFUJITA Tomonori 	return ret;
292519789100SFUJITA Tomonori }
292619789100SFUJITA Tomonori 
292787c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
292887c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
292987c715dcSDouglas Gilbert {
293087c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
293187c715dcSDouglas Gilbert 
293287c715dcSDouglas Gilbert 	if (!sdb->length)
293387c715dcSDouglas Gilbert 		return 0;
293487c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
293587c715dcSDouglas Gilbert 		return -1;
293687c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
293787c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
293887c715dcSDouglas Gilbert }
293987c715dcSDouglas Gilbert 
294087c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
294187c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
294238d5c833SDouglas Gilbert  * return false. */
294387c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2944c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
294538d5c833SDouglas Gilbert {
294638d5c833SDouglas Gilbert 	bool res;
294738d5c833SDouglas Gilbert 	u64 block, rest = 0;
294838d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2949773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
295087c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
295138d5c833SDouglas Gilbert 
295238d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
295338d5c833SDouglas Gilbert 	if (block + num > store_blks)
295438d5c833SDouglas Gilbert 		rest = block + num - store_blks;
295538d5c833SDouglas Gilbert 
295687c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
295738d5c833SDouglas Gilbert 	if (!res)
295838d5c833SDouglas Gilbert 		return res;
295938d5c833SDouglas Gilbert 	if (rest)
296087c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
296138d5c833SDouglas Gilbert 			     rest * lb_size);
296238d5c833SDouglas Gilbert 	if (!res)
296338d5c833SDouglas Gilbert 		return res;
2964c3e2fe92SDouglas Gilbert 	if (compare_only)
2965c3e2fe92SDouglas Gilbert 		return true;
296638d5c833SDouglas Gilbert 	arr += num * lb_size;
296787c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
296838d5c833SDouglas Gilbert 	if (rest)
296987c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
297038d5c833SDouglas Gilbert 	return res;
297138d5c833SDouglas Gilbert }
297238d5c833SDouglas Gilbert 
297351d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2974beb40ea4SAkinobu Mita {
297551d648afSAkinobu Mita 	__be16 csum;
2976beb40ea4SAkinobu Mita 
2977773642d9SDouglas Gilbert 	if (sdebug_guard)
297851d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
297951d648afSAkinobu Mita 	else
2980beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
298151d648afSAkinobu Mita 
2982beb40ea4SAkinobu Mita 	return csum;
2983beb40ea4SAkinobu Mita }
2984beb40ea4SAkinobu Mita 
29856ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2986beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2987beb40ea4SAkinobu Mita {
2988773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2989beb40ea4SAkinobu Mita 
2990beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2991c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2992beb40ea4SAkinobu Mita 			(unsigned long)sector,
2993beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2994beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2995beb40ea4SAkinobu Mita 		return 0x01;
2996beb40ea4SAkinobu Mita 	}
29978475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2998beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2999c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3000c1287970STomas Winkler 			(unsigned long)sector);
3001beb40ea4SAkinobu Mita 		return 0x03;
3002beb40ea4SAkinobu Mita 	}
30038475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3004beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3005c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3006c1287970STomas Winkler 			(unsigned long)sector);
3007beb40ea4SAkinobu Mita 		return 0x03;
3008beb40ea4SAkinobu Mita 	}
3009beb40ea4SAkinobu Mita 	return 0;
3010beb40ea4SAkinobu Mita }
3011beb40ea4SAkinobu Mita 
301287c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
301365f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3014c6a44287SMartin K. Petersen {
3015be4e11beSAkinobu Mita 	size_t resid;
3016c6a44287SMartin K. Petersen 	void *paddr;
301787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
301887c715dcSDouglas Gilbert 						scp->device->hostdata);
301987c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
302014faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3021be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3022c6a44287SMartin K. Petersen 
3023e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3024e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3025c6a44287SMartin K. Petersen 
302687c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
302787c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3028be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3029be4e11beSAkinobu Mita 
3030be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
303187c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
303287c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3033be4e11beSAkinobu Mita 		size_t rest = 0;
303414faa944SAkinobu Mita 
303514faa944SAkinobu Mita 		if (dif_store_end < start + len)
303614faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3037c6a44287SMartin K. Petersen 
3038be4e11beSAkinobu Mita 		paddr = miter.addr;
303914faa944SAkinobu Mita 
304065f72f2aSAkinobu Mita 		if (read)
304165f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
304265f72f2aSAkinobu Mita 		else
304365f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
304465f72f2aSAkinobu Mita 
304565f72f2aSAkinobu Mita 		if (rest) {
304665f72f2aSAkinobu Mita 			if (read)
304714faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
304865f72f2aSAkinobu Mita 			else
304965f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
305065f72f2aSAkinobu Mita 		}
3051c6a44287SMartin K. Petersen 
3052e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3053c6a44287SMartin K. Petersen 		resid -= len;
3054c6a44287SMartin K. Petersen 	}
3055be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3056bb8c063cSAkinobu Mita }
3057c6a44287SMartin K. Petersen 
305887c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3059bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3060bb8c063cSAkinobu Mita {
3061bb8c063cSAkinobu Mita 	unsigned int i;
3062bb8c063cSAkinobu Mita 	sector_t sector;
306387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
306487c715dcSDouglas Gilbert 						scp->device->hostdata);
306587c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3066bb8c063cSAkinobu Mita 
3067c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3068bb8c063cSAkinobu Mita 		int ret;
3069bb8c063cSAkinobu Mita 
3070bb8c063cSAkinobu Mita 		sector = start_sec + i;
307187c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3072bb8c063cSAkinobu Mita 
307351d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3074bb8c063cSAkinobu Mita 			continue;
3075bb8c063cSAkinobu Mita 
307687c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
307787c715dcSDouglas Gilbert 				 ei_lba);
3078bb8c063cSAkinobu Mita 		if (ret) {
3079bb8c063cSAkinobu Mita 			dif_errors++;
3080bb8c063cSAkinobu Mita 			return ret;
3081bb8c063cSAkinobu Mita 		}
3082bb8c063cSAkinobu Mita 	}
3083bb8c063cSAkinobu Mita 
308487c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3085c6a44287SMartin K. Petersen 	dix_reads++;
3086c6a44287SMartin K. Petersen 
3087c6a44287SMartin K. Petersen 	return 0;
3088c6a44287SMartin K. Petersen }
3089c6a44287SMartin K. Petersen 
3090fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
309119789100SFUJITA Tomonori {
309287c715dcSDouglas Gilbert 	bool check_prot;
3093c2248fc9SDouglas Gilbert 	u32 num;
3094c2248fc9SDouglas Gilbert 	u32 ei_lba;
309519789100SFUJITA Tomonori 	int ret;
309687c715dcSDouglas Gilbert 	u64 lba;
309787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
309887c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
309987c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
310087c715dcSDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
310119789100SFUJITA Tomonori 
3102c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3103c2248fc9SDouglas Gilbert 	case READ_16:
3104c2248fc9SDouglas Gilbert 		ei_lba = 0;
3105c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3106c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3107c2248fc9SDouglas Gilbert 		check_prot = true;
3108c2248fc9SDouglas Gilbert 		break;
3109c2248fc9SDouglas Gilbert 	case READ_10:
3110c2248fc9SDouglas Gilbert 		ei_lba = 0;
3111c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3112c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3113c2248fc9SDouglas Gilbert 		check_prot = true;
3114c2248fc9SDouglas Gilbert 		break;
3115c2248fc9SDouglas Gilbert 	case READ_6:
3116c2248fc9SDouglas Gilbert 		ei_lba = 0;
3117c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3118c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3119c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3120c2248fc9SDouglas Gilbert 		check_prot = true;
3121c2248fc9SDouglas Gilbert 		break;
3122c2248fc9SDouglas Gilbert 	case READ_12:
3123c2248fc9SDouglas Gilbert 		ei_lba = 0;
3124c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3125c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3126c2248fc9SDouglas Gilbert 		check_prot = true;
3127c2248fc9SDouglas Gilbert 		break;
3128c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3129c2248fc9SDouglas Gilbert 		ei_lba = 0;
3130c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3131c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3132c2248fc9SDouglas Gilbert 		check_prot = false;
3133c2248fc9SDouglas Gilbert 		break;
3134c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3135c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3136c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3137c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3138c2248fc9SDouglas Gilbert 		check_prot = false;
3139c2248fc9SDouglas Gilbert 		break;
3140c2248fc9SDouglas Gilbert 	}
3141f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31428475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3143c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3144c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3145c2248fc9SDouglas Gilbert 			return check_condition_result;
3146c2248fc9SDouglas Gilbert 		}
31478475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31488475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3149c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3150c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3151c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3152c2248fc9SDouglas Gilbert 	}
3153f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3154c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
3155c2248fc9SDouglas Gilbert 
3156c4837394SDouglas Gilbert 		if (sqcp) {
3157c4837394SDouglas Gilbert 			if (sqcp->inj_short)
3158c2248fc9SDouglas Gilbert 				num /= 2;
3159c2248fc9SDouglas Gilbert 		}
3160c4837394SDouglas Gilbert 	} else
3161c4837394SDouglas Gilbert 		sqcp = NULL;
3162c2248fc9SDouglas Gilbert 
31639447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
31649447b6ceSMartin K. Petersen 	if (ret)
31659447b6ceSMartin K. Petersen 		return ret;
3166f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3167d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3168d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3169c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3170c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3171c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3172c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3173c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
317432f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
317532f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3176c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3177c65b1445SDouglas Gilbert 		}
3178c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
31791da177e4SLinus Torvalds 		return check_condition_result;
31801da177e4SLinus Torvalds 	}
3181c6a44287SMartin K. Petersen 
318267da413fSDouglas Gilbert 	read_lock(macc_lckp);
31836c78cc06SAkinobu Mita 
3184c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3185f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3186c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
3187c6a44287SMartin K. Petersen 
3188c6a44287SMartin K. Petersen 		if (prot_ret) {
318967da413fSDouglas Gilbert 			read_unlock(macc_lckp);
3190c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
3191c6a44287SMartin K. Petersen 			return illegal_condition_result;
3192c6a44287SMartin K. Petersen 		}
3193c6a44287SMartin K. Petersen 	}
3194c6a44287SMartin K. Petersen 
319587c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
319667da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3197f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3198a4517511SAkinobu Mita 		return DID_ERROR << 16;
3199a4517511SAkinobu Mita 
320042d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3201a4517511SAkinobu Mita 
3202c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
3203c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
3204c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
3205c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
3206c2248fc9SDouglas Gilbert 			return check_condition_result;
3207c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
3208c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
3209c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3210c2248fc9SDouglas Gilbert 			return check_condition_result;
3211c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
3212c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3213c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3214c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3215c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
3216c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3217c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3218c2248fc9SDouglas Gilbert 		}
3219c2248fc9SDouglas Gilbert 	}
3220a4517511SAkinobu Mita 	return 0;
32211da177e4SLinus Torvalds }
32221da177e4SLinus Torvalds 
322358a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
3224c6a44287SMartin K. Petersen {
3225cbf67842SDouglas Gilbert 	int i, j, n;
3226c6a44287SMartin K. Petersen 
3227cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
3228c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
3229cbf67842SDouglas Gilbert 		char b[128];
3230c6a44287SMartin K. Petersen 
3231cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
3232c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
3233c6a44287SMartin K. Petersen 
3234cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
3235cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3236cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
3237cbf67842SDouglas Gilbert 			else
3238cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
3239cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
3240cbf67842SDouglas Gilbert 		}
3241cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
3242c6a44287SMartin K. Petersen 	}
3243c6a44287SMartin K. Petersen }
3244c6a44287SMartin K. Petersen 
3245c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3246395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3247c6a44287SMartin K. Petersen {
3248be4e11beSAkinobu Mita 	int ret;
32496ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3250be4e11beSAkinobu Mita 	void *daddr;
325165f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3252c6a44287SMartin K. Petersen 	int ppage_offset;
3253be4e11beSAkinobu Mita 	int dpage_offset;
3254be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3255be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3256c6a44287SMartin K. Petersen 
3257c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3258c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3259c6a44287SMartin K. Petersen 
3260be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3261be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3262be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3263be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3264be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3265c6a44287SMartin K. Petersen 
3266be4e11beSAkinobu Mita 	/* For each protection page */
3267be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3268be4e11beSAkinobu Mita 		dpage_offset = 0;
3269be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3270be4e11beSAkinobu Mita 			ret = 0x01;
3271be4e11beSAkinobu Mita 			goto out;
3272c6a44287SMartin K. Petersen 		}
3273c6a44287SMartin K. Petersen 
3274be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
32756ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3276be4e11beSAkinobu Mita 			/* If we're at the end of the current
3277be4e11beSAkinobu Mita 			 * data page advance to the next one
3278be4e11beSAkinobu Mita 			 */
3279be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3280be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3281be4e11beSAkinobu Mita 					ret = 0x01;
3282be4e11beSAkinobu Mita 					goto out;
3283be4e11beSAkinobu Mita 				}
3284be4e11beSAkinobu Mita 				dpage_offset = 0;
3285be4e11beSAkinobu Mita 			}
3286c6a44287SMartin K. Petersen 
3287be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3288be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3289be4e11beSAkinobu Mita 
3290be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
3291beb40ea4SAkinobu Mita 			if (ret) {
3292773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
3293395cef03SMartin K. Petersen 				goto out;
3294395cef03SMartin K. Petersen 			}
3295395cef03SMartin K. Petersen 
3296c6a44287SMartin K. Petersen 			sector++;
3297395cef03SMartin K. Petersen 			ei_lba++;
3298773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3299c6a44287SMartin K. Petersen 		}
3300be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3301be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3302c6a44287SMartin K. Petersen 	}
3303be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3304c6a44287SMartin K. Petersen 
330565f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3306c6a44287SMartin K. Petersen 	dix_writes++;
3307c6a44287SMartin K. Petersen 
3308c6a44287SMartin K. Petersen 	return 0;
3309c6a44287SMartin K. Petersen 
3310c6a44287SMartin K. Petersen out:
3311c6a44287SMartin K. Petersen 	dif_errors++;
3312be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3313be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3314c6a44287SMartin K. Petersen 	return ret;
3315c6a44287SMartin K. Petersen }
3316c6a44287SMartin K. Petersen 
3317b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3318b90ebc3dSAkinobu Mita {
3319773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3320773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3321773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3322b90ebc3dSAkinobu Mita 	return lba;
3323b90ebc3dSAkinobu Mita }
3324b90ebc3dSAkinobu Mita 
3325b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3326b90ebc3dSAkinobu Mita {
3327773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3328a027b5b9SAkinobu Mita 
3329773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3330773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3331a027b5b9SAkinobu Mita 	return lba;
3332a027b5b9SAkinobu Mita }
3333a027b5b9SAkinobu Mita 
333487c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
333587c715dcSDouglas Gilbert 			      unsigned int *num)
333644d92694SMartin K. Petersen {
3337b90ebc3dSAkinobu Mita 	sector_t end;
3338b90ebc3dSAkinobu Mita 	unsigned int mapped;
3339b90ebc3dSAkinobu Mita 	unsigned long index;
3340b90ebc3dSAkinobu Mita 	unsigned long next;
334144d92694SMartin K. Petersen 
3342b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
334387c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
334444d92694SMartin K. Petersen 
334544d92694SMartin K. Petersen 	if (mapped)
334687c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
334744d92694SMartin K. Petersen 	else
334887c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
334944d92694SMartin K. Petersen 
3350b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
335144d92694SMartin K. Petersen 	*num = end - lba;
335244d92694SMartin K. Petersen 	return mapped;
335344d92694SMartin K. Petersen }
335444d92694SMartin K. Petersen 
335587c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
335687c715dcSDouglas Gilbert 		       unsigned int len)
335744d92694SMartin K. Petersen {
335844d92694SMartin K. Petersen 	sector_t end = lba + len;
335944d92694SMartin K. Petersen 
336044d92694SMartin K. Petersen 	while (lba < end) {
3361b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
336244d92694SMartin K. Petersen 
3363b90ebc3dSAkinobu Mita 		if (index < map_size)
336487c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
336544d92694SMartin K. Petersen 
3366b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
336744d92694SMartin K. Petersen 	}
336844d92694SMartin K. Petersen }
336944d92694SMartin K. Petersen 
337087c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
337187c715dcSDouglas Gilbert 			 unsigned int len)
337244d92694SMartin K. Petersen {
337344d92694SMartin K. Petersen 	sector_t end = lba + len;
337487c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
337544d92694SMartin K. Petersen 
337644d92694SMartin K. Petersen 	while (lba < end) {
3377b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
337844d92694SMartin K. Petersen 
3379b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3380773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3381b90ebc3dSAkinobu Mita 		    index < map_size) {
338287c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3383760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
338487c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3385760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3386773642d9SDouglas Gilbert 				       sdebug_sector_size *
3387773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3388be1dd78dSEric Sandeen 			}
338987c715dcSDouglas Gilbert 			if (sip->dif_storep) {
339087c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
339187c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3392773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3393e9926b43SAkinobu Mita 			}
3394b90ebc3dSAkinobu Mita 		}
3395b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
339644d92694SMartin K. Petersen 	}
339744d92694SMartin K. Petersen }
339844d92694SMartin K. Petersen 
3399fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34001da177e4SLinus Torvalds {
340187c715dcSDouglas Gilbert 	bool check_prot;
3402c2248fc9SDouglas Gilbert 	u32 num;
3403c2248fc9SDouglas Gilbert 	u32 ei_lba;
340419789100SFUJITA Tomonori 	int ret;
340587c715dcSDouglas Gilbert 	u64 lba;
340687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
340787c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
340887c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
34091da177e4SLinus Torvalds 
3410c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3411c2248fc9SDouglas Gilbert 	case WRITE_16:
3412c2248fc9SDouglas Gilbert 		ei_lba = 0;
3413c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3414c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3415c2248fc9SDouglas Gilbert 		check_prot = true;
3416c2248fc9SDouglas Gilbert 		break;
3417c2248fc9SDouglas Gilbert 	case WRITE_10:
3418c2248fc9SDouglas Gilbert 		ei_lba = 0;
3419c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3420c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3421c2248fc9SDouglas Gilbert 		check_prot = true;
3422c2248fc9SDouglas Gilbert 		break;
3423c2248fc9SDouglas Gilbert 	case WRITE_6:
3424c2248fc9SDouglas Gilbert 		ei_lba = 0;
3425c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3426c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3427c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3428c2248fc9SDouglas Gilbert 		check_prot = true;
3429c2248fc9SDouglas Gilbert 		break;
3430c2248fc9SDouglas Gilbert 	case WRITE_12:
3431c2248fc9SDouglas Gilbert 		ei_lba = 0;
3432c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3433c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3434c2248fc9SDouglas Gilbert 		check_prot = true;
3435c2248fc9SDouglas Gilbert 		break;
3436c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3437c2248fc9SDouglas Gilbert 		ei_lba = 0;
3438c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3439c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3440c2248fc9SDouglas Gilbert 		check_prot = false;
3441c2248fc9SDouglas Gilbert 		break;
3442c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3443c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3444c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3445c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3446c2248fc9SDouglas Gilbert 		check_prot = false;
3447c2248fc9SDouglas Gilbert 		break;
3448c2248fc9SDouglas Gilbert 	}
3449f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
34508475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3451c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3452c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3453c2248fc9SDouglas Gilbert 			return check_condition_result;
3454c2248fc9SDouglas Gilbert 		}
34558475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34568475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3457c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3458c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3459c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3460c2248fc9SDouglas Gilbert 	}
3461f0d1cf93SDouglas Gilbert 
346267da413fSDouglas Gilbert 	write_lock(macc_lckp);
3463f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3464f0d1cf93SDouglas Gilbert 	if (ret) {
3465f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3466f0d1cf93SDouglas Gilbert 		return ret;
3467f0d1cf93SDouglas Gilbert 	}
34686c78cc06SAkinobu Mita 
3469c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3470f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3471c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3472c6a44287SMartin K. Petersen 
3473c6a44287SMartin K. Petersen 		if (prot_ret) {
347467da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3475c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3476c6a44287SMartin K. Petersen 			return illegal_condition_result;
3477c6a44287SMartin K. Petersen 		}
3478c6a44287SMartin K. Petersen 	}
3479c6a44287SMartin K. Petersen 
348087c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3481f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
348287c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3483f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3484f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3485f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
348667da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3487f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3488773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3489c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3490c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3491c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3492cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3493773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
349444d92694SMartin K. Petersen 
3495f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3496c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3497c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3498c2248fc9SDouglas Gilbert 
3499c4837394SDouglas Gilbert 		if (sqcp) {
3500c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3501c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3502c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3503c2248fc9SDouglas Gilbert 				return check_condition_result;
3504c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3505c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3506c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3507c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3508c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3509c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3510c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3511c2248fc9SDouglas Gilbert 			}
3512c2248fc9SDouglas Gilbert 		}
3513c4837394SDouglas Gilbert 	}
35141da177e4SLinus Torvalds 	return 0;
35151da177e4SLinus Torvalds }
35161da177e4SLinus Torvalds 
3517481b5e5cSDouglas Gilbert /*
3518481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3519481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3520481b5e5cSDouglas Gilbert  */
3521481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3522481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3523481b5e5cSDouglas Gilbert {
3524481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3525481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3526481b5e5cSDouglas Gilbert 	u8 *up;
352787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
352887c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3529481b5e5cSDouglas Gilbert 	u8 wrprotect;
3530481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3531481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3532481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3533481b5e5cSDouglas Gilbert 	u32 ei_lba;
3534481b5e5cSDouglas Gilbert 	u64 lba;
3535481b5e5cSDouglas Gilbert 	int ret, res;
3536481b5e5cSDouglas Gilbert 	bool is_16;
3537481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3538481b5e5cSDouglas Gilbert 
3539481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3540481b5e5cSDouglas Gilbert 		is_16 = false;
3541481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3542481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3543481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3544481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3545481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3546481b5e5cSDouglas Gilbert 		is_16 = true;
3547481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3548481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3549481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3550481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3551481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3552481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3553481b5e5cSDouglas Gilbert 			    wrprotect) {
3554481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3555481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3556481b5e5cSDouglas Gilbert 			}
3557481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3558481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3559481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3560481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3561481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3562481b5e5cSDouglas Gilbert 		}
3563481b5e5cSDouglas Gilbert 	}
3564481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3565481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3566481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3567481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3568481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3569481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3570481b5e5cSDouglas Gilbert 				my_name, __func__);
3571481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3572481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3573481b5e5cSDouglas Gilbert 	}
3574481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3575481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3576481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3577481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3578481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3579481b5e5cSDouglas Gilbert 				my_name, __func__);
3580481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3581481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3582481b5e5cSDouglas Gilbert 	}
3583481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3584481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3585481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3586481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3587481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3588481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3589481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3590481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3591481b5e5cSDouglas Gilbert 	if (res == -1) {
3592481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3593481b5e5cSDouglas Gilbert 		goto err_out;
3594481b5e5cSDouglas Gilbert 	}
3595481b5e5cSDouglas Gilbert 
359667da413fSDouglas Gilbert 	write_lock(macc_lckp);
3597481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3598481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3599481b5e5cSDouglas Gilbert 	cum_lb = 0;
3600481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3601481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3602481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3603481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3604481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3605481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3606481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3607481b5e5cSDouglas Gilbert 		if (num == 0)
3608481b5e5cSDouglas Gilbert 			continue;
36099447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3610481b5e5cSDouglas Gilbert 		if (ret)
3611481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3612481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3613481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3614481b5e5cSDouglas Gilbert 
3615481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3616481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3617481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3618481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3619481b5e5cSDouglas Gilbert 				    my_name, __func__);
3620481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3621481b5e5cSDouglas Gilbert 					0);
3622481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3623481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3624481b5e5cSDouglas Gilbert 		}
3625481b5e5cSDouglas Gilbert 
3626481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3627481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3628481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3629481b5e5cSDouglas Gilbert 							 ei_lba);
3630481b5e5cSDouglas Gilbert 
3631481b5e5cSDouglas Gilbert 			if (prot_ret) {
3632481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3633481b5e5cSDouglas Gilbert 						prot_ret);
3634481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3635481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3636481b5e5cSDouglas Gilbert 			}
3637481b5e5cSDouglas Gilbert 		}
3638481b5e5cSDouglas Gilbert 
363987c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3640f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3641f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3642f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3643481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
364487c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3645481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3646481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3647481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3648481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3649481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3650481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3651481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3652481b5e5cSDouglas Gilbert 
3653481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3654481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3655481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3656481b5e5cSDouglas Gilbert 
3657481b5e5cSDouglas Gilbert 			if (sqcp) {
3658481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3659481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3660481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3661481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3662481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3663481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3664481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3665481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3666481b5e5cSDouglas Gilbert 							0x10, 1);
3667481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3668481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3669481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3670481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3671481b5e5cSDouglas Gilbert 							0x10, 1);
3672481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3673481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3674481b5e5cSDouglas Gilbert 				}
3675481b5e5cSDouglas Gilbert 			}
3676481b5e5cSDouglas Gilbert 		}
3677481b5e5cSDouglas Gilbert 		sg_off += num_by;
3678481b5e5cSDouglas Gilbert 		cum_lb += num;
3679481b5e5cSDouglas Gilbert 	}
3680481b5e5cSDouglas Gilbert 	ret = 0;
3681481b5e5cSDouglas Gilbert err_out_unlock:
368267da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3683481b5e5cSDouglas Gilbert err_out:
3684481b5e5cSDouglas Gilbert 	kfree(lrdp);
3685481b5e5cSDouglas Gilbert 	return ret;
3686481b5e5cSDouglas Gilbert }
3687481b5e5cSDouglas Gilbert 
3688fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3689fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
369044d92694SMartin K. Petersen {
3691f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3692f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
369344d92694SMartin K. Petersen 	unsigned long long i;
369440d07b52SDouglas Gilbert 	u64 block, lbaa;
369587c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
369687c715dcSDouglas Gilbert 	int ret;
369787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
369887c715dcSDouglas Gilbert 						scp->device->hostdata);
369987c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
370040d07b52SDouglas Gilbert 	u8 *fs1p;
370187c715dcSDouglas Gilbert 	u8 *fsp;
370244d92694SMartin K. Petersen 
370367da413fSDouglas Gilbert 	write_lock(macc_lckp);
370444d92694SMartin K. Petersen 
3705f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3706f0d1cf93SDouglas Gilbert 	if (ret) {
3707f0d1cf93SDouglas Gilbert 		write_unlock(macc_lckp);
3708f0d1cf93SDouglas Gilbert 		return ret;
3709f0d1cf93SDouglas Gilbert 	}
3710f0d1cf93SDouglas Gilbert 
37119ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
371287c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
371344d92694SMartin K. Petersen 		goto out;
371444d92694SMartin K. Petersen 	}
371540d07b52SDouglas Gilbert 	lbaa = lba;
371640d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3717c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
371887c715dcSDouglas Gilbert 	fsp = sip->storep;
371987c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3720c2248fc9SDouglas Gilbert 	if (ndob) {
372140d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3722c2248fc9SDouglas Gilbert 		ret = 0;
3723c2248fc9SDouglas Gilbert 	} else
372440d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
372544d92694SMartin K. Petersen 
372644d92694SMartin K. Petersen 	if (-1 == ret) {
372767da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3728773642d9SDouglas Gilbert 		return DID_ERROR << 16;
372940d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3730c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3731e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
373240d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
373344d92694SMartin K. Petersen 
373444d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
373540d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
373640d07b52SDouglas Gilbert 		lbaa = lba + i;
373740d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
373887c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
373940d07b52SDouglas Gilbert 	}
37409ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
374187c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3742f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3743f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3744f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
374544d92694SMartin K. Petersen out:
374667da413fSDouglas Gilbert 	write_unlock(macc_lckp);
374744d92694SMartin K. Petersen 
374844d92694SMartin K. Petersen 	return 0;
374944d92694SMartin K. Petersen }
375044d92694SMartin K. Petersen 
3751fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3752fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3753c2248fc9SDouglas Gilbert {
3754c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3755c2248fc9SDouglas Gilbert 	u32 lba;
3756c2248fc9SDouglas Gilbert 	u16 num;
3757c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3758c2248fc9SDouglas Gilbert 	bool unmap = false;
3759c2248fc9SDouglas Gilbert 
3760c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3761773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3762c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3763c2248fc9SDouglas Gilbert 			return check_condition_result;
3764c2248fc9SDouglas Gilbert 		} else
3765c2248fc9SDouglas Gilbert 			unmap = true;
3766c2248fc9SDouglas Gilbert 	}
3767c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3768c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3769773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3770c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3771c2248fc9SDouglas Gilbert 		return check_condition_result;
3772c2248fc9SDouglas Gilbert 	}
3773c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3774c2248fc9SDouglas Gilbert }
3775c2248fc9SDouglas Gilbert 
3776fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3777fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3778c2248fc9SDouglas Gilbert {
3779c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3780c2248fc9SDouglas Gilbert 	u64 lba;
3781c2248fc9SDouglas Gilbert 	u32 num;
3782c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3783c2248fc9SDouglas Gilbert 	bool unmap = false;
3784c2248fc9SDouglas Gilbert 	bool ndob = false;
3785c2248fc9SDouglas Gilbert 
3786c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3787773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3788c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3789c2248fc9SDouglas Gilbert 			return check_condition_result;
3790c2248fc9SDouglas Gilbert 		} else
3791c2248fc9SDouglas Gilbert 			unmap = true;
3792c2248fc9SDouglas Gilbert 	}
3793c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3794c2248fc9SDouglas Gilbert 		ndob = true;
3795c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3796c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3797773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3798c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3799c2248fc9SDouglas Gilbert 		return check_condition_result;
3800c2248fc9SDouglas Gilbert 	}
3801c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3802c2248fc9SDouglas Gilbert }
3803c2248fc9SDouglas Gilbert 
3804acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3805acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3806acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3807fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3808fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3809acafd0b9SEwan D. Milne {
3810acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3811acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3812acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3813acafd0b9SEwan D. Milne 	u8 mode;
3814acafd0b9SEwan D. Milne 
3815acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3816acafd0b9SEwan D. Milne 	switch (mode) {
3817acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3818acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3819acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3820acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3821acafd0b9SEwan D. Milne 		break;
3822acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3823acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3824acafd0b9SEwan D. Milne 		break;
3825acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3826acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3827acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3828acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3829acafd0b9SEwan D. Milne 				    dev_list)
3830acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3831acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3832acafd0b9SEwan D. Milne 				if (devip != dp)
3833acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3834acafd0b9SEwan D. Milne 						dp->uas_bm);
3835acafd0b9SEwan D. Milne 			}
3836acafd0b9SEwan D. Milne 		break;
3837acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3838acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3839acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3840acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3841acafd0b9SEwan D. Milne 				    dev_list)
3842acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3843acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3844acafd0b9SEwan D. Milne 					dp->uas_bm);
3845acafd0b9SEwan D. Milne 		break;
3846acafd0b9SEwan D. Milne 	default:
3847acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3848acafd0b9SEwan D. Milne 		break;
3849acafd0b9SEwan D. Milne 	}
3850acafd0b9SEwan D. Milne 	return 0;
3851acafd0b9SEwan D. Milne }
3852acafd0b9SEwan D. Milne 
3853fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3854fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
385538d5c833SDouglas Gilbert {
385638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
385738d5c833SDouglas Gilbert 	u8 *arr;
385887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
385987c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
386038d5c833SDouglas Gilbert 	u64 lba;
386138d5c833SDouglas Gilbert 	u32 dnum;
3862773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
386338d5c833SDouglas Gilbert 	u8 num;
386438d5c833SDouglas Gilbert 	int ret;
3865d467d31fSDouglas Gilbert 	int retval = 0;
386638d5c833SDouglas Gilbert 
3867d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
386838d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
386938d5c833SDouglas Gilbert 	if (0 == num)
387038d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
38718475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
387238d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
387338d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
387438d5c833SDouglas Gilbert 		return check_condition_result;
387538d5c833SDouglas Gilbert 	}
38768475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
38778475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
387838d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
387938d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
388038d5c833SDouglas Gilbert 			    "to DIF device\n");
38819447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
38829447b6ceSMartin K. Petersen 	if (ret)
38839447b6ceSMartin K. Petersen 		return ret;
3884d467d31fSDouglas Gilbert 	dnum = 2 * num;
38856396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3886d467d31fSDouglas Gilbert 	if (NULL == arr) {
3887d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3888d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3889d467d31fSDouglas Gilbert 		return check_condition_result;
3890d467d31fSDouglas Gilbert 	}
389138d5c833SDouglas Gilbert 
389267da413fSDouglas Gilbert 	write_lock(macc_lckp);
389338d5c833SDouglas Gilbert 
389487c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
389538d5c833SDouglas Gilbert 	if (ret == -1) {
3896d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3897d467d31fSDouglas Gilbert 		goto cleanup;
3898773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
389938d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
390038d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
390138d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3902c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
390338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3904d467d31fSDouglas Gilbert 		retval = check_condition_result;
3905d467d31fSDouglas Gilbert 		goto cleanup;
390638d5c833SDouglas Gilbert 	}
390738d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
390887c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3909d467d31fSDouglas Gilbert cleanup:
391067da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3911d467d31fSDouglas Gilbert 	kfree(arr);
3912d467d31fSDouglas Gilbert 	return retval;
391338d5c833SDouglas Gilbert }
391438d5c833SDouglas Gilbert 
391544d92694SMartin K. Petersen struct unmap_block_desc {
391644d92694SMartin K. Petersen 	__be64	lba;
391744d92694SMartin K. Petersen 	__be32	blocks;
391844d92694SMartin K. Petersen 	__be32	__reserved;
391944d92694SMartin K. Petersen };
392044d92694SMartin K. Petersen 
3921fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
392244d92694SMartin K. Petersen {
392344d92694SMartin K. Petersen 	unsigned char *buf;
392444d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
392587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
392687c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
392744d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
392844d92694SMartin K. Petersen 	int ret;
392944d92694SMartin K. Petersen 
3930c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3931c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3932c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3933c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
393444d92694SMartin K. Petersen 
393544d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3936773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3937c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
393844d92694SMartin K. Petersen 		return check_condition_result;
3939c2248fc9SDouglas Gilbert 	}
394044d92694SMartin K. Petersen 
3941b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3942c2248fc9SDouglas Gilbert 	if (!buf) {
3943c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3944c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3945c2248fc9SDouglas Gilbert 		return check_condition_result;
3946c2248fc9SDouglas Gilbert 	}
3947c2248fc9SDouglas Gilbert 
3948c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
394944d92694SMartin K. Petersen 
395044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
395144d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
395244d92694SMartin K. Petersen 
395344d92694SMartin K. Petersen 	desc = (void *)&buf[8];
395444d92694SMartin K. Petersen 
395567da413fSDouglas Gilbert 	write_lock(macc_lckp);
39566c78cc06SAkinobu Mita 
395744d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
395844d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
395944d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
396044d92694SMartin K. Petersen 
39619447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
396244d92694SMartin K. Petersen 		if (ret)
396344d92694SMartin K. Petersen 			goto out;
396444d92694SMartin K. Petersen 
396587c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
396644d92694SMartin K. Petersen 	}
396744d92694SMartin K. Petersen 
396844d92694SMartin K. Petersen 	ret = 0;
396944d92694SMartin K. Petersen 
397044d92694SMartin K. Petersen out:
397167da413fSDouglas Gilbert 	write_unlock(macc_lckp);
397244d92694SMartin K. Petersen 	kfree(buf);
397344d92694SMartin K. Petersen 
397444d92694SMartin K. Petersen 	return ret;
397544d92694SMartin K. Petersen }
397644d92694SMartin K. Petersen 
397744d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
397844d92694SMartin K. Petersen 
3979fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3980fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
398144d92694SMartin K. Petersen {
3982c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
398387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
3984c2248fc9SDouglas Gilbert 	u64 lba;
3985c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
398644d92694SMartin K. Petersen 	int ret;
398787c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
398844d92694SMartin K. Petersen 
3989c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3990c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
399144d92694SMartin K. Petersen 
399244d92694SMartin K. Petersen 	if (alloc_len < 24)
399344d92694SMartin K. Petersen 		return 0;
399444d92694SMartin K. Petersen 
39959447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
399644d92694SMartin K. Petersen 	if (ret)
399744d92694SMartin K. Petersen 		return ret;
399844d92694SMartin K. Petersen 
3999c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
400087c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4001c2248fc9SDouglas Gilbert 	else {
4002c2248fc9SDouglas Gilbert 		mapped = 1;
4003c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4004c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4005c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4006c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4007c2248fc9SDouglas Gilbert 		else
4008c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4009c2248fc9SDouglas Gilbert 	}
401044d92694SMartin K. Petersen 
401144d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4012c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4013c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4014c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4015c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
401644d92694SMartin K. Petersen 
4017c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
401844d92694SMartin K. Petersen }
401944d92694SMartin K. Petersen 
402080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
402180c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
402280c49563SDouglas Gilbert {
40234f2c8bf6SDouglas Gilbert 	int res = 0;
402480c49563SDouglas Gilbert 	u64 lba;
402580c49563SDouglas Gilbert 	u32 num_blocks;
402680c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
402780c49563SDouglas Gilbert 
402880c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
402980c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
403080c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
403180c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
403280c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
403380c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
403480c49563SDouglas Gilbert 	}
403580c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
403680c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
403780c49563SDouglas Gilbert 		return check_condition_result;
403880c49563SDouglas Gilbert 	}
40394f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
40404f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
40414f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
40424f2c8bf6SDouglas Gilbert 		write_since_sync = false;
40434f2c8bf6SDouglas Gilbert 	return res;
404480c49563SDouglas Gilbert }
404580c49563SDouglas Gilbert 
4046ed9f3e25SDouglas Gilbert /*
4047ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4048ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4049ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4050ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4051ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4052ed9f3e25SDouglas Gilbert  */
4053ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4054ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4055ed9f3e25SDouglas Gilbert {
4056ed9f3e25SDouglas Gilbert 	int res = 0;
4057ed9f3e25SDouglas Gilbert 	u64 lba;
4058ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4059ed9f3e25SDouglas Gilbert 	u32 nblks;
4060ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4061ed9f3e25SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4062ed9f3e25SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4063ed9f3e25SDouglas Gilbert 	u8 *fsp = sip ? sip->storep : NULL;
4064ed9f3e25SDouglas Gilbert 
4065ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4066ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4067ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4068ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4069ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4070ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4071ed9f3e25SDouglas Gilbert 	}
4072ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4073ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4074ed9f3e25SDouglas Gilbert 		return check_condition_result;
4075ed9f3e25SDouglas Gilbert 	}
4076ed9f3e25SDouglas Gilbert 	if (!fsp)
4077ed9f3e25SDouglas Gilbert 		goto fini;
4078ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4079ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4080ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4081ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4082ed9f3e25SDouglas Gilbert 
4083ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
4084ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
4085ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4086ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4087ed9f3e25SDouglas Gilbert 	if (rest)
4088ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
4089ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
4090ed9f3e25SDouglas Gilbert fini:
4091ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4092ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4093ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4094ed9f3e25SDouglas Gilbert }
4095ed9f3e25SDouglas Gilbert 
4096fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4097fb0cc8d1SDouglas Gilbert 
40988d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
40998d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
41008d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
41018d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41028d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
41038d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
41048d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
41058d039e22SDouglas Gilbert  */
41061da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
41071da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
41081da177e4SLinus Torvalds {
410901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
41108d039e22SDouglas Gilbert 	unsigned int alloc_len;
41118d039e22SDouglas Gilbert 	unsigned char select_report;
41128d039e22SDouglas Gilbert 	u64 lun;
41138d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4114fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41158d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41168d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
41178d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
41188d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4119fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4120fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4121fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
41221da177e4SLinus Torvalds 
412319c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
41248d039e22SDouglas Gilbert 
41258d039e22SDouglas Gilbert 	select_report = cmd[2];
41268d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
41278d039e22SDouglas Gilbert 
41288d039e22SDouglas Gilbert 	if (alloc_len < 4) {
41298d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
41308d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41311da177e4SLinus Torvalds 		return check_condition_result;
41321da177e4SLinus Torvalds 	}
41338d039e22SDouglas Gilbert 
41348d039e22SDouglas Gilbert 	switch (select_report) {
41358d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4136773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41378d039e22SDouglas Gilbert 		wlun_cnt = 0;
41388d039e22SDouglas Gilbert 		break;
41398d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4140c65b1445SDouglas Gilbert 		lun_cnt = 0;
41418d039e22SDouglas Gilbert 		wlun_cnt = 1;
41428d039e22SDouglas Gilbert 		break;
41438d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
41448d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
41458d039e22SDouglas Gilbert 		wlun_cnt = 1;
41468d039e22SDouglas Gilbert 		break;
41478d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
41488d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
41498d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41508d039e22SDouglas Gilbert 	default:
41518d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
41528d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41538d039e22SDouglas Gilbert 		return check_condition_result;
41548d039e22SDouglas Gilbert 	}
41558d039e22SDouglas Gilbert 
41568d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4157c65b1445SDouglas Gilbert 		--lun_cnt;
41588d039e22SDouglas Gilbert 
41598d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4160fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4161fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
41628d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41638d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
41648d039e22SDouglas Gilbert 
4165fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
41668d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4167fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4168fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4169fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4170fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4171fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4172fb0cc8d1SDouglas Gilbert 			++lun_p;
4173fb0cc8d1SDouglas Gilbert 			j = 1;
4174fb0cc8d1SDouglas Gilbert 		}
4175fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4176fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4177fb0cc8d1SDouglas Gilbert 				break;
4178fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4179fb0cc8d1SDouglas Gilbert 		}
4180fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4181fb0cc8d1SDouglas Gilbert 			break;
4182fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4183fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4184fb0cc8d1SDouglas Gilbert 		if (res)
4185fb0cc8d1SDouglas Gilbert 			return res;
4186fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4187fb0cc8d1SDouglas Gilbert 	}
4188fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4189fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4190fb0cc8d1SDouglas Gilbert 		++j;
4191fb0cc8d1SDouglas Gilbert 	}
4192fb0cc8d1SDouglas Gilbert 	if (j > 0)
4193fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
41948d039e22SDouglas Gilbert 	return res;
41951da177e4SLinus Torvalds }
41961da177e4SLinus Torvalds 
4197c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4198c3e2fe92SDouglas Gilbert {
4199c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4200c3e2fe92SDouglas Gilbert 	u8 bytchk;
4201c3e2fe92SDouglas Gilbert 	int ret, j;
4202c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4203c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4204c3e2fe92SDouglas Gilbert 	u64 lba;
4205c3e2fe92SDouglas Gilbert 	u8 *arr;
4206c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4207c3e2fe92SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4208c3e2fe92SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4209c3e2fe92SDouglas Gilbert 
4210c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4211c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4212c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4213c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4214c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4215c3e2fe92SDouglas Gilbert 		return check_condition_result;
4216c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4217c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4218c3e2fe92SDouglas Gilbert 	}
4219c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4220c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4221c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4222c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4223c3e2fe92SDouglas Gilbert 		break;
4224c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4225c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4226c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4227c3e2fe92SDouglas Gilbert 		break;
4228c3e2fe92SDouglas Gilbert 	default:
4229c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4230c3e2fe92SDouglas Gilbert 		return check_condition_result;
4231c3e2fe92SDouglas Gilbert 	}
4232c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4233c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4234c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4235c3e2fe92SDouglas Gilbert 	if (ret)
4236c3e2fe92SDouglas Gilbert 		return ret;
4237c3e2fe92SDouglas Gilbert 
4238c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4239c3e2fe92SDouglas Gilbert 	if (!arr) {
4240c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4241c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4242c3e2fe92SDouglas Gilbert 		return check_condition_result;
4243c3e2fe92SDouglas Gilbert 	}
4244c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
424567da413fSDouglas Gilbert 	read_lock(macc_lckp);
4246c3e2fe92SDouglas Gilbert 
4247c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4248c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4249c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4250c3e2fe92SDouglas Gilbert 		goto cleanup;
4251c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4252c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4253c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4254c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4255c3e2fe92SDouglas Gilbert 	}
4256c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4257c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4258c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4259c3e2fe92SDouglas Gilbert 	}
4260c3e2fe92SDouglas Gilbert 	ret = 0;
4261c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4262c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4263c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4264c3e2fe92SDouglas Gilbert 		goto cleanup;
4265c3e2fe92SDouglas Gilbert 	}
4266c3e2fe92SDouglas Gilbert cleanup:
426767da413fSDouglas Gilbert 	read_unlock(macc_lckp);
4268c3e2fe92SDouglas Gilbert 	kfree(arr);
4269c3e2fe92SDouglas Gilbert 	return ret;
4270c3e2fe92SDouglas Gilbert }
4271c3e2fe92SDouglas Gilbert 
4272f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4273f0d1cf93SDouglas Gilbert 
4274f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */
4275f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4276f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4277f0d1cf93SDouglas Gilbert {
4278f0d1cf93SDouglas Gilbert 	unsigned int i, max_zones, rep_max_zones, nrz = 0;
4279f0d1cf93SDouglas Gilbert 	int ret = 0;
4280f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4281f0d1cf93SDouglas Gilbert 	bool partial;
4282f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4283f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4284f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4285f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4286f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4287f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4288f0d1cf93SDouglas Gilbert 
4289f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4290f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4291f0d1cf93SDouglas Gilbert 		return check_condition_result;
4292f0d1cf93SDouglas Gilbert 	}
4293f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4294f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
4295f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4296f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4297f0d1cf93SDouglas Gilbert 
4298f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4299f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4300f0d1cf93SDouglas Gilbert 		return check_condition_result;
4301f0d1cf93SDouglas Gilbert 	}
4302f0d1cf93SDouglas Gilbert 
4303108e36f0SDamien Le Moal 	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
4304f0d1cf93SDouglas Gilbert 	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4305f0d1cf93SDouglas Gilbert 			    max_zones);
4306f0d1cf93SDouglas Gilbert 
4307f0d1cf93SDouglas Gilbert 	arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4308f0d1cf93SDouglas Gilbert 	if (!arr) {
4309f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4310f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4311f0d1cf93SDouglas Gilbert 		return check_condition_result;
4312f0d1cf93SDouglas Gilbert 	}
4313f0d1cf93SDouglas Gilbert 
4314f0d1cf93SDouglas Gilbert 	read_lock(macc_lckp);
4315f0d1cf93SDouglas Gilbert 
4316f0d1cf93SDouglas Gilbert 	desc = arr + 64;
4317f0d1cf93SDouglas Gilbert 	for (i = 0; i < max_zones; i++) {
4318f0d1cf93SDouglas Gilbert 		lba = zs_lba + devip->zsize * i;
4319f0d1cf93SDouglas Gilbert 		if (lba > sdebug_capacity)
4320f0d1cf93SDouglas Gilbert 			break;
4321f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4322f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4323f0d1cf93SDouglas Gilbert 		case 0x00:
4324f0d1cf93SDouglas Gilbert 			/* All zones */
4325f0d1cf93SDouglas Gilbert 			break;
4326f0d1cf93SDouglas Gilbert 		case 0x01:
4327f0d1cf93SDouglas Gilbert 			/* Empty zones */
4328f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4329f0d1cf93SDouglas Gilbert 				continue;
4330f0d1cf93SDouglas Gilbert 			break;
4331f0d1cf93SDouglas Gilbert 		case 0x02:
4332f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4333f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4334f0d1cf93SDouglas Gilbert 				continue;
4335f0d1cf93SDouglas Gilbert 			break;
4336f0d1cf93SDouglas Gilbert 		case 0x03:
4337f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4338f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4339f0d1cf93SDouglas Gilbert 				continue;
4340f0d1cf93SDouglas Gilbert 			break;
4341f0d1cf93SDouglas Gilbert 		case 0x04:
4342f0d1cf93SDouglas Gilbert 			/* Closed zones */
4343f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4344f0d1cf93SDouglas Gilbert 				continue;
4345f0d1cf93SDouglas Gilbert 			break;
4346f0d1cf93SDouglas Gilbert 		case 0x05:
4347f0d1cf93SDouglas Gilbert 			/* Full zones */
4348f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4349f0d1cf93SDouglas Gilbert 				continue;
4350f0d1cf93SDouglas Gilbert 			break;
4351f0d1cf93SDouglas Gilbert 		case 0x06:
4352f0d1cf93SDouglas Gilbert 		case 0x07:
4353f0d1cf93SDouglas Gilbert 		case 0x10:
4354f0d1cf93SDouglas Gilbert 			/*
435564e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
435664e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4357f0d1cf93SDouglas Gilbert 			 */
4358f0d1cf93SDouglas Gilbert 			continue;
435964e14eceSDamien Le Moal 		case 0x11:
436064e14eceSDamien Le Moal 			/* non-seq-resource set */
436164e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
436264e14eceSDamien Le Moal 				continue;
436364e14eceSDamien Le Moal 			break;
4364f0d1cf93SDouglas Gilbert 		case 0x3f:
4365f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
4366f0d1cf93SDouglas Gilbert 			if (!zbc_zone_is_conv(zsp))
4367f0d1cf93SDouglas Gilbert 				continue;
4368f0d1cf93SDouglas Gilbert 			break;
4369f0d1cf93SDouglas Gilbert 		default:
4370f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4371f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4372f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4373f0d1cf93SDouglas Gilbert 			goto fini;
4374f0d1cf93SDouglas Gilbert 		}
4375f0d1cf93SDouglas Gilbert 
4376f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4377f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
437864e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4379f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
438064e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
438164e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4382f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4383f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4384f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4385f0d1cf93SDouglas Gilbert 			desc += 64;
4386f0d1cf93SDouglas Gilbert 		}
4387f0d1cf93SDouglas Gilbert 
4388f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4389f0d1cf93SDouglas Gilbert 			break;
4390f0d1cf93SDouglas Gilbert 
4391f0d1cf93SDouglas Gilbert 		nrz++;
4392f0d1cf93SDouglas Gilbert 	}
4393f0d1cf93SDouglas Gilbert 
4394f0d1cf93SDouglas Gilbert 	/* Report header */
4395f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4396f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4397f0d1cf93SDouglas Gilbert 
4398f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
4399f0d1cf93SDouglas Gilbert 	ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4400f0d1cf93SDouglas Gilbert 
4401f0d1cf93SDouglas Gilbert fini:
4402f0d1cf93SDouglas Gilbert 	read_unlock(macc_lckp);
4403f0d1cf93SDouglas Gilbert 	kfree(arr);
4404f0d1cf93SDouglas Gilbert 	return ret;
4405f0d1cf93SDouglas Gilbert }
4406f0d1cf93SDouglas Gilbert 
4407f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
4408f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4409f0d1cf93SDouglas Gilbert {
4410f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4411f0d1cf93SDouglas Gilbert 	unsigned int i;
4412f0d1cf93SDouglas Gilbert 
4413f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4414f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4415f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4416f0d1cf93SDouglas Gilbert 	}
4417f0d1cf93SDouglas Gilbert }
4418f0d1cf93SDouglas Gilbert 
4419f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4420f0d1cf93SDouglas Gilbert {
4421f0d1cf93SDouglas Gilbert 	int res = 0;
4422f0d1cf93SDouglas Gilbert 	u64 z_id;
4423f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4424f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4425f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4426f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4427f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4428f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4429f0d1cf93SDouglas Gilbert 
4430f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4431f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4432f0d1cf93SDouglas Gilbert 		return check_condition_result;
4433f0d1cf93SDouglas Gilbert 	}
4434f0d1cf93SDouglas Gilbert 
4435f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4436f0d1cf93SDouglas Gilbert 
4437f0d1cf93SDouglas Gilbert 	if (all) {
4438f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4439f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4440f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4441f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4442f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4443f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4444f0d1cf93SDouglas Gilbert 			goto fini;
4445f0d1cf93SDouglas Gilbert 		}
4446f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4447f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4448f0d1cf93SDouglas Gilbert 		goto fini;
4449f0d1cf93SDouglas Gilbert 	}
4450f0d1cf93SDouglas Gilbert 
4451f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4452f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4453f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4454f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4455f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4456f0d1cf93SDouglas Gilbert 		goto fini;
4457f0d1cf93SDouglas Gilbert 	}
4458f0d1cf93SDouglas Gilbert 
4459f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4460f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4461f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4462f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4463f0d1cf93SDouglas Gilbert 		goto fini;
4464f0d1cf93SDouglas Gilbert 	}
4465f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4466f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4467f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4468f0d1cf93SDouglas Gilbert 		goto fini;
4469f0d1cf93SDouglas Gilbert 	}
4470f0d1cf93SDouglas Gilbert 
4471f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4472f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4473f0d1cf93SDouglas Gilbert 		goto fini;
4474f0d1cf93SDouglas Gilbert 
4475f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4476f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4477f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4478f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4479f0d1cf93SDouglas Gilbert 		goto fini;
4480f0d1cf93SDouglas Gilbert 	}
4481f0d1cf93SDouglas Gilbert 
4482f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
4483f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4484f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4485f0d1cf93SDouglas Gilbert fini:
4486f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4487f0d1cf93SDouglas Gilbert 	return res;
4488f0d1cf93SDouglas Gilbert }
4489f0d1cf93SDouglas Gilbert 
4490f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4491f0d1cf93SDouglas Gilbert {
4492f0d1cf93SDouglas Gilbert 	unsigned int i;
4493f0d1cf93SDouglas Gilbert 
4494f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4495f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4496f0d1cf93SDouglas Gilbert }
4497f0d1cf93SDouglas Gilbert 
4498f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4499f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4500f0d1cf93SDouglas Gilbert {
4501f0d1cf93SDouglas Gilbert 	int res = 0;
4502f0d1cf93SDouglas Gilbert 	u64 z_id;
4503f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4504f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4505f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4506f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4507f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4508f0d1cf93SDouglas Gilbert 
4509f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4510f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4511f0d1cf93SDouglas Gilbert 		return check_condition_result;
4512f0d1cf93SDouglas Gilbert 	}
4513f0d1cf93SDouglas Gilbert 
4514f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4515f0d1cf93SDouglas Gilbert 
4516f0d1cf93SDouglas Gilbert 	if (all) {
4517f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4518f0d1cf93SDouglas Gilbert 		goto fini;
4519f0d1cf93SDouglas Gilbert 	}
4520f0d1cf93SDouglas Gilbert 
4521f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4522f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4523f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4524f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4525f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4526f0d1cf93SDouglas Gilbert 		goto fini;
4527f0d1cf93SDouglas Gilbert 	}
4528f0d1cf93SDouglas Gilbert 
4529f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4530f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4531f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4532f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4533f0d1cf93SDouglas Gilbert 		goto fini;
4534f0d1cf93SDouglas Gilbert 	}
4535f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4536f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4537f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4538f0d1cf93SDouglas Gilbert 		goto fini;
4539f0d1cf93SDouglas Gilbert 	}
4540f0d1cf93SDouglas Gilbert 
4541f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4542f0d1cf93SDouglas Gilbert fini:
4543f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4544f0d1cf93SDouglas Gilbert 	return res;
4545f0d1cf93SDouglas Gilbert }
4546f0d1cf93SDouglas Gilbert 
4547f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4548f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4549f0d1cf93SDouglas Gilbert {
4550f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4551f0d1cf93SDouglas Gilbert 
4552f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4553f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4554f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4555f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4556f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4557f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4558f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4559f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4560f0d1cf93SDouglas Gilbert 	}
4561f0d1cf93SDouglas Gilbert }
4562f0d1cf93SDouglas Gilbert 
4563f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4564f0d1cf93SDouglas Gilbert {
4565f0d1cf93SDouglas Gilbert 	unsigned int i;
4566f0d1cf93SDouglas Gilbert 
4567f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4568f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4569f0d1cf93SDouglas Gilbert }
4570f0d1cf93SDouglas Gilbert 
4571f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4572f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4573f0d1cf93SDouglas Gilbert {
4574f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4575f0d1cf93SDouglas Gilbert 	int res = 0;
4576f0d1cf93SDouglas Gilbert 	u64 z_id;
4577f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4578f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4579f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4580f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4581f0d1cf93SDouglas Gilbert 
4582f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4583f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4584f0d1cf93SDouglas Gilbert 		return check_condition_result;
4585f0d1cf93SDouglas Gilbert 	}
4586f0d1cf93SDouglas Gilbert 
4587f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4588f0d1cf93SDouglas Gilbert 
4589f0d1cf93SDouglas Gilbert 	if (all) {
4590f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4591f0d1cf93SDouglas Gilbert 		goto fini;
4592f0d1cf93SDouglas Gilbert 	}
4593f0d1cf93SDouglas Gilbert 
4594f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4595f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4596f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4597f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4598f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4599f0d1cf93SDouglas Gilbert 		goto fini;
4600f0d1cf93SDouglas Gilbert 	}
4601f0d1cf93SDouglas Gilbert 
4602f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4603f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4604f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4605f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4606f0d1cf93SDouglas Gilbert 		goto fini;
4607f0d1cf93SDouglas Gilbert 	}
4608f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4609f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4610f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4611f0d1cf93SDouglas Gilbert 		goto fini;
4612f0d1cf93SDouglas Gilbert 	}
4613f0d1cf93SDouglas Gilbert 
4614f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4615f0d1cf93SDouglas Gilbert fini:
4616f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4617f0d1cf93SDouglas Gilbert 	return res;
4618f0d1cf93SDouglas Gilbert }
4619f0d1cf93SDouglas Gilbert 
4620f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4621f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4622f0d1cf93SDouglas Gilbert {
4623f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4624f0d1cf93SDouglas Gilbert 
4625f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp))
4626f0d1cf93SDouglas Gilbert 		return;
4627f0d1cf93SDouglas Gilbert 
4628f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4629f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4630f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4631f0d1cf93SDouglas Gilbert 
4632f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4633f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4634f0d1cf93SDouglas Gilbert 
463564e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4636f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4637f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4638f0d1cf93SDouglas Gilbert }
4639f0d1cf93SDouglas Gilbert 
4640f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4641f0d1cf93SDouglas Gilbert {
4642f0d1cf93SDouglas Gilbert 	unsigned int i;
4643f0d1cf93SDouglas Gilbert 
4644f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4645f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4646f0d1cf93SDouglas Gilbert }
4647f0d1cf93SDouglas Gilbert 
4648f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4649f0d1cf93SDouglas Gilbert {
4650f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4651f0d1cf93SDouglas Gilbert 	int res = 0;
4652f0d1cf93SDouglas Gilbert 	u64 z_id;
4653f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4654f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4655f0d1cf93SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
4656f0d1cf93SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4657f0d1cf93SDouglas Gilbert 
4658f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4659f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4660f0d1cf93SDouglas Gilbert 		return check_condition_result;
4661f0d1cf93SDouglas Gilbert 	}
4662f0d1cf93SDouglas Gilbert 
4663f0d1cf93SDouglas Gilbert 	write_lock(macc_lckp);
4664f0d1cf93SDouglas Gilbert 
4665f0d1cf93SDouglas Gilbert 	if (all) {
4666f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4667f0d1cf93SDouglas Gilbert 		goto fini;
4668f0d1cf93SDouglas Gilbert 	}
4669f0d1cf93SDouglas Gilbert 
4670f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4671f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4672f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4673f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4674f0d1cf93SDouglas Gilbert 		goto fini;
4675f0d1cf93SDouglas Gilbert 	}
4676f0d1cf93SDouglas Gilbert 
4677f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4678f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4679f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4680f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4681f0d1cf93SDouglas Gilbert 		goto fini;
4682f0d1cf93SDouglas Gilbert 	}
4683f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4684f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4685f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4686f0d1cf93SDouglas Gilbert 		goto fini;
4687f0d1cf93SDouglas Gilbert 	}
4688f0d1cf93SDouglas Gilbert 
4689f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4690f0d1cf93SDouglas Gilbert fini:
4691f0d1cf93SDouglas Gilbert 	write_unlock(macc_lckp);
4692f0d1cf93SDouglas Gilbert 	return res;
4693f0d1cf93SDouglas Gilbert }
4694f0d1cf93SDouglas Gilbert 
4695c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4696c4837394SDouglas Gilbert {
4697c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
4698c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
4699c4837394SDouglas Gilbert 
4700458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4701458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
4702458df78bSBart Van Assche 		hwq = 0;
4703458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
4704c4837394SDouglas Gilbert }
4705c4837394SDouglas Gilbert 
4706c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
4707fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47081da177e4SLinus Torvalds {
47097382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
4710c4837394SDouglas Gilbert 	int qc_idx;
4711cbf67842SDouglas Gilbert 	int retiring = 0;
47121da177e4SLinus Torvalds 	unsigned long iflags;
4713c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4714cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4715cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
4716cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
47171da177e4SLinus Torvalds 
471810bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
47197382f9d8SDouglas Gilbert 	if (unlikely(aborted))
47207382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
4721c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
4722c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
4723c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4724cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4725c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4726c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4727c4837394SDouglas Gilbert 	}
4728c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4729c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
47301da177e4SLinus Torvalds 		return;
47311da177e4SLinus Torvalds 	}
4732c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4733c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
4734cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
4735b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
4736c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4737c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
4738c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
47391da177e4SLinus Torvalds 		return;
47401da177e4SLinus Torvalds 	}
4741cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
4742f46eb0e9SDouglas Gilbert 	if (likely(devip))
4743cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
4744cbf67842SDouglas Gilbert 	else
4745c1287970STomas Winkler 		pr_err("devip=NULL\n");
4746f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
4747cbf67842SDouglas Gilbert 		retiring = 1;
4748cbf67842SDouglas Gilbert 
4749cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
4750c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4751c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4752c1287970STomas Winkler 		pr_err("Unexpected completion\n");
4753cbf67842SDouglas Gilbert 		return;
47541da177e4SLinus Torvalds 	}
47551da177e4SLinus Torvalds 
4756cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
4757cbf67842SDouglas Gilbert 		int k, retval;
4758cbf67842SDouglas Gilbert 
4759cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
4760c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
4761c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4762c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
4763cbf67842SDouglas Gilbert 			return;
4764cbf67842SDouglas Gilbert 		}
4765c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
4766773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
4767cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4768cbf67842SDouglas Gilbert 		else
4769cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4770cbf67842SDouglas Gilbert 	}
4771c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47727382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
47737382f9d8SDouglas Gilbert 		if (sdebug_verbose)
47747382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
47757382f9d8SDouglas Gilbert 		return;
47767382f9d8SDouglas Gilbert 	}
4777cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4778cbf67842SDouglas Gilbert }
4779cbf67842SDouglas Gilbert 
4780cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4781fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4782cbf67842SDouglas Gilbert {
4783a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4784a10bc12aSDouglas Gilbert 						  hrt);
4785a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4786cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4787cbf67842SDouglas Gilbert }
47881da177e4SLinus Torvalds 
4789a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4790fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4791a10bc12aSDouglas Gilbert {
4792a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4793a10bc12aSDouglas Gilbert 						  ew.work);
4794a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4795a10bc12aSDouglas Gilbert }
4796a10bc12aSDouglas Gilbert 
479709ba24c1SDouglas Gilbert static bool got_shared_uuid;
4798bf476433SChristoph Hellwig static uuid_t shared_uuid;
479909ba24c1SDouglas Gilbert 
4800f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4801f0d1cf93SDouglas Gilbert {
4802f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4803f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
4804f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4805f0d1cf93SDouglas Gilbert 	unsigned int i;
4806f0d1cf93SDouglas Gilbert 
4807f0d1cf93SDouglas Gilbert 	/*
480898e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
480998e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4810f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4811f0d1cf93SDouglas Gilbert 	 * created for the device.
4812f0d1cf93SDouglas Gilbert 	 */
481398e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4814f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4815f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4816f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4817f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4818f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4819f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4820f0d1cf93SDouglas Gilbert 			return -EINVAL;
4821f0d1cf93SDouglas Gilbert 		}
4822f0d1cf93SDouglas Gilbert 	} else {
4823108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4824108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4825108e36f0SDamien Le Moal 			return -EINVAL;
4826108e36f0SDamien Le Moal 		}
482798e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4828f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4829f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4830f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4831f0d1cf93SDouglas Gilbert 			return -EINVAL;
4832f0d1cf93SDouglas Gilbert 		}
4833f0d1cf93SDouglas Gilbert 	}
4834f0d1cf93SDouglas Gilbert 
4835f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4836f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4837f0d1cf93SDouglas Gilbert 
4838aa8fecf9SDamien Le Moal 	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4839aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
4840aa8fecf9SDamien Le Moal 		return -EINVAL;
4841aa8fecf9SDamien Le Moal 	}
4842aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
4843aa8fecf9SDamien Le Moal 
484464e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
484564e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
4846380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4847f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
4848f0d1cf93SDouglas Gilbert 		else
4849380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
485064e14eceSDamien Le Moal 	}
4851f0d1cf93SDouglas Gilbert 
4852f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
4853f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
4854f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
4855f0d1cf93SDouglas Gilbert 		return -ENOMEM;
4856f0d1cf93SDouglas Gilbert 
4857f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
4858f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
4859f0d1cf93SDouglas Gilbert 
4860f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
4861f0d1cf93SDouglas Gilbert 
4862aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
486364e14eceSDamien Le Moal 			zsp->z_type = ZBC_ZONE_TYPE_CNV;
4864f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4865f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
4866f0d1cf93SDouglas Gilbert 		} else {
486764e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
486864e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWR;
486964e14eceSDamien Le Moal 			else
487064e14eceSDamien Le Moal 				zsp->z_type = ZBC_ZONE_TYPE_SWP;
4871f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
4872f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
4873f0d1cf93SDouglas Gilbert 		}
4874f0d1cf93SDouglas Gilbert 
4875f0d1cf93SDouglas Gilbert 		if (zsp->z_start + devip->zsize < capacity)
4876f0d1cf93SDouglas Gilbert 			zsp->z_size = devip->zsize;
4877f0d1cf93SDouglas Gilbert 		else
4878f0d1cf93SDouglas Gilbert 			zsp->z_size = capacity - zsp->z_start;
4879f0d1cf93SDouglas Gilbert 
4880f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
4881f0d1cf93SDouglas Gilbert 	}
4882f0d1cf93SDouglas Gilbert 
4883f0d1cf93SDouglas Gilbert 	return 0;
4884f0d1cf93SDouglas Gilbert }
4885f0d1cf93SDouglas Gilbert 
4886fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4887fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
48885cb2fc06SFUJITA Tomonori {
48895cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
48905cb2fc06SFUJITA Tomonori 
48915cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
48925cb2fc06SFUJITA Tomonori 	if (devip) {
489309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4894bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
489509ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
489609ba24c1SDouglas Gilbert 			if (got_shared_uuid)
489709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
489809ba24c1SDouglas Gilbert 			else {
4899bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
490009ba24c1SDouglas Gilbert 				got_shared_uuid = true;
490109ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
490209ba24c1SDouglas Gilbert 			}
490309ba24c1SDouglas Gilbert 		}
49045cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
4905f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
490664e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
4907f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
4908f0d1cf93SDouglas Gilbert 				kfree(devip);
4909f0d1cf93SDouglas Gilbert 				return NULL;
4910f0d1cf93SDouglas Gilbert 			}
491164e14eceSDamien Le Moal 		} else {
491264e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
4913f0d1cf93SDouglas Gilbert 		}
4914f0d1cf93SDouglas Gilbert 		devip->sdbg_host = sdbg_host;
49155cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49165cb2fc06SFUJITA Tomonori 	}
49175cb2fc06SFUJITA Tomonori 	return devip;
49185cb2fc06SFUJITA Tomonori }
49195cb2fc06SFUJITA Tomonori 
4920f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49211da177e4SLinus Torvalds {
49221da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
49231da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4924f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
49251da177e4SLinus Torvalds 
4926d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49271da177e4SLinus Torvalds 	if (!sdbg_host) {
4928c1287970STomas Winkler 		pr_err("Host info NULL\n");
49291da177e4SLinus Torvalds 		return NULL;
49301da177e4SLinus Torvalds 	}
49311da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49321da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
49331da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
49341da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
49351da177e4SLinus Torvalds 			return devip;
49361da177e4SLinus Torvalds 		else {
49371da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
49381da177e4SLinus Torvalds 				open_devip = devip;
49391da177e4SLinus Torvalds 		}
49401da177e4SLinus Torvalds 	}
49415cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
49425cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49435cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4944c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49451da177e4SLinus Torvalds 			return NULL;
49461da177e4SLinus Torvalds 		}
49471da177e4SLinus Torvalds 	}
4948a75869d1SFUJITA Tomonori 
49491da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
49501da177e4SLinus Torvalds 	open_devip->target = sdev->id;
49511da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
49521da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4953cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4954cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4955c2248fc9SDouglas Gilbert 	open_devip->used = true;
49561da177e4SLinus Torvalds 	return open_devip;
49571da177e4SLinus Torvalds }
49581da177e4SLinus Torvalds 
49598dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
49601da177e4SLinus Torvalds {
4961773642d9SDouglas Gilbert 	if (sdebug_verbose)
4962c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
49638dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49648dea0d02SFUJITA Tomonori 	return 0;
49658dea0d02SFUJITA Tomonori }
49661da177e4SLinus Torvalds 
49678dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
49688dea0d02SFUJITA Tomonori {
4969f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4970f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4971a34c4e98SFUJITA Tomonori 
4972773642d9SDouglas Gilbert 	if (sdebug_verbose)
4973c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
49748dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4975b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4976b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4977b01f6f83SDouglas Gilbert 	if (devip == NULL) {
4978f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
4979b01f6f83SDouglas Gilbert 		if (devip == NULL)
49808dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
4981f46eb0e9SDouglas Gilbert 	}
4982c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
4983773642d9SDouglas Gilbert 	if (sdebug_no_uld)
498478d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
49859b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
49868dea0d02SFUJITA Tomonori 	return 0;
49878dea0d02SFUJITA Tomonori }
49888dea0d02SFUJITA Tomonori 
49898dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
49908dea0d02SFUJITA Tomonori {
49918dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
49928dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
49938dea0d02SFUJITA Tomonori 
4994773642d9SDouglas Gilbert 	if (sdebug_verbose)
4995c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
49968dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
49978dea0d02SFUJITA Tomonori 	if (devip) {
499825985edcSLucas De Marchi 		/* make this slot available for re-use */
4999c2248fc9SDouglas Gilbert 		devip->used = false;
50008dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
50018dea0d02SFUJITA Tomonori 	}
50028dea0d02SFUJITA Tomonori }
50038dea0d02SFUJITA Tomonori 
500410bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
500510bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5006c4837394SDouglas Gilbert {
5007c4837394SDouglas Gilbert 	if (!sd_dp)
5008c4837394SDouglas Gilbert 		return;
500910bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
5010c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
501110bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
5012c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
5013c4837394SDouglas Gilbert }
5014c4837394SDouglas Gilbert 
5015a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
5016a10bc12aSDouglas Gilbert    returns false */
5017a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50188dea0d02SFUJITA Tomonori {
50198dea0d02SFUJITA Tomonori 	unsigned long iflags;
5020c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
502110bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5022c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50238dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5024cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5025a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50268dea0d02SFUJITA Tomonori 
5027c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5028c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5029773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
5030cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
5031cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
5032cbf67842SDouglas Gilbert 			qmax = r_qmax;
5033cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
5034c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5035c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5036a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
5037a10bc12aSDouglas Gilbert 					continue;
5038c4837394SDouglas Gilbert 				/* found */
5039db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5040db525fceSDouglas Gilbert 						cmnd->device->hostdata;
5041db525fceSDouglas Gilbert 				if (devip)
5042db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5043db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5044a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
504510bde980SDouglas Gilbert 				if (sd_dp) {
504610bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
504710bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
504810bde980SDouglas Gilbert 				} else
504910bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5050c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
505110bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5052c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5053a10bc12aSDouglas Gilbert 				return true;
50548dea0d02SFUJITA Tomonori 			}
5055cbf67842SDouglas Gilbert 		}
5056c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5057c4837394SDouglas Gilbert 	}
5058a10bc12aSDouglas Gilbert 	return false;
50598dea0d02SFUJITA Tomonori }
50608dea0d02SFUJITA Tomonori 
5061a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
50628dea0d02SFUJITA Tomonori static void stop_all_queued(void)
50638dea0d02SFUJITA Tomonori {
50648dea0d02SFUJITA Tomonori 	unsigned long iflags;
5065c4837394SDouglas Gilbert 	int j, k;
506610bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
5067c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
50688dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
5069cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5070a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
50718dea0d02SFUJITA Tomonori 
5072c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5073c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
5074c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5075c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
5076c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
5077c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
5078a10bc12aSDouglas Gilbert 					continue;
5079db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
5080db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
5081db525fceSDouglas Gilbert 				if (devip)
5082db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5083db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
5084a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
508510bde980SDouglas Gilbert 				if (sd_dp) {
508610bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
508710bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
508810bde980SDouglas Gilbert 				} else
508910bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
5090c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
509110bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
5092c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
5093c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
50948dea0d02SFUJITA Tomonori 			}
50958dea0d02SFUJITA Tomonori 		}
5096c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5097c4837394SDouglas Gilbert 	}
5098cbf67842SDouglas Gilbert }
5099cbf67842SDouglas Gilbert 
5100cbf67842SDouglas Gilbert /* Free queued command memory on heap */
5101cbf67842SDouglas Gilbert static void free_all_queued(void)
5102cbf67842SDouglas Gilbert {
5103c4837394SDouglas Gilbert 	int j, k;
5104c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5105cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5106cbf67842SDouglas Gilbert 
5107c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5108c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5109c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
5110a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
5111a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
5112cbf67842SDouglas Gilbert 		}
51131da177e4SLinus Torvalds 	}
5114c4837394SDouglas Gilbert }
51151da177e4SLinus Torvalds 
51161da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51171da177e4SLinus Torvalds {
5118a10bc12aSDouglas Gilbert 	bool ok;
5119a10bc12aSDouglas Gilbert 
51201da177e4SLinus Torvalds 	++num_aborts;
5121cbf67842SDouglas Gilbert 	if (SCpnt) {
5122a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
5123a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5124a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
5125a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
5126a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
5127cbf67842SDouglas Gilbert 	}
51281da177e4SLinus Torvalds 	return SUCCESS;
51291da177e4SLinus Torvalds }
51301da177e4SLinus Torvalds 
51311da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51321da177e4SLinus Torvalds {
51331da177e4SLinus Torvalds 	++num_dev_resets;
5134cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
5135cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
5136f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
5137f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
5138cbf67842SDouglas Gilbert 
5139773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5140cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51411da177e4SLinus Torvalds 		if (devip)
5142cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51431da177e4SLinus Torvalds 	}
51441da177e4SLinus Torvalds 	return SUCCESS;
51451da177e4SLinus Torvalds }
51461da177e4SLinus Torvalds 
5147cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5148cbf67842SDouglas Gilbert {
5149cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
5150cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5151cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
5152cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
5153cbf67842SDouglas Gilbert 	int k = 0;
5154cbf67842SDouglas Gilbert 
5155cbf67842SDouglas Gilbert 	++num_target_resets;
5156cbf67842SDouglas Gilbert 	if (!SCpnt)
5157cbf67842SDouglas Gilbert 		goto lie;
5158cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5159cbf67842SDouglas Gilbert 	if (!sdp)
5160cbf67842SDouglas Gilbert 		goto lie;
5161773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5162cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5163cbf67842SDouglas Gilbert 	hp = sdp->host;
5164cbf67842SDouglas Gilbert 	if (!hp)
5165cbf67842SDouglas Gilbert 		goto lie;
5166cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5167cbf67842SDouglas Gilbert 	if (sdbg_host) {
5168cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
5169cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
5170cbf67842SDouglas Gilbert 				    dev_list)
5171cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
5172cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5173cbf67842SDouglas Gilbert 				++k;
5174cbf67842SDouglas Gilbert 			}
5175cbf67842SDouglas Gilbert 	}
5176773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5177cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5178cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5179cbf67842SDouglas Gilbert lie:
5180cbf67842SDouglas Gilbert 	return SUCCESS;
5181cbf67842SDouglas Gilbert }
5182cbf67842SDouglas Gilbert 
51831da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
51841da177e4SLinus Torvalds {
51851da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5186cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
51871da177e4SLinus Torvalds 	struct scsi_device *sdp;
51881da177e4SLinus Torvalds 	struct Scsi_Host *hp;
5189cbf67842SDouglas Gilbert 	int k = 0;
51901da177e4SLinus Torvalds 
51911da177e4SLinus Torvalds 	++num_bus_resets;
5192cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
5193cbf67842SDouglas Gilbert 		goto lie;
5194cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
5195773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5196cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5197cbf67842SDouglas Gilbert 	hp = sdp->host;
5198cbf67842SDouglas Gilbert 	if (hp) {
5199d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52001da177e4SLinus Torvalds 		if (sdbg_host) {
5201cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
52021da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
5203cbf67842SDouglas Gilbert 					    dev_list) {
5204cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5205cbf67842SDouglas Gilbert 				++k;
52061da177e4SLinus Torvalds 			}
52071da177e4SLinus Torvalds 		}
5208cbf67842SDouglas Gilbert 	}
5209773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5210cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5211cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
5212cbf67842SDouglas Gilbert lie:
52131da177e4SLinus Torvalds 	return SUCCESS;
52141da177e4SLinus Torvalds }
52151da177e4SLinus Torvalds 
52161da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52171da177e4SLinus Torvalds {
52181da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5219cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5220cbf67842SDouglas Gilbert 	int k = 0;
52211da177e4SLinus Torvalds 
52221da177e4SLinus Torvalds 	++num_host_resets;
5223773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5224cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52251da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52261da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5227cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5228cbf67842SDouglas Gilbert 				    dev_list) {
5229cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5230cbf67842SDouglas Gilbert 			++k;
5231cbf67842SDouglas Gilbert 		}
52321da177e4SLinus Torvalds 	}
52331da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52341da177e4SLinus Torvalds 	stop_all_queued();
5235773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5236cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5237cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
52381da177e4SLinus Torvalds 	return SUCCESS;
52391da177e4SLinus Torvalds }
52401da177e4SLinus Torvalds 
524187c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52421da177e4SLinus Torvalds {
52431442f76dSChristoph Hellwig 	struct msdos_partition *pp;
52441da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
52451da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
52461da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
52471da177e4SLinus Torvalds 
52481da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5249773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
52501da177e4SLinus Torvalds 		return;
5251773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5252773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5253c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
52541da177e4SLinus Torvalds 	}
5255c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
52561da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5257773642d9SDouglas Gilbert 			   / sdebug_num_parts;
52581da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
52591da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5260773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
52611da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
52621da177e4SLinus Torvalds 			    * heads_by_sects;
5263773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5264773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
52651da177e4SLinus Torvalds 
52661da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
52671da177e4SLinus Torvalds 	ramp[511] = 0xAA;
52681442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
52691da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
52701da177e4SLinus Torvalds 		start_sec = starts[k];
52711da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
52721da177e4SLinus Torvalds 		pp->boot_ind = 0;
52731da177e4SLinus Torvalds 
52741da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
52751da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
52761da177e4SLinus Torvalds 			   / sdebug_sectors_per;
52771da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
52781da177e4SLinus Torvalds 
52791da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
52801da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
52811da177e4SLinus Torvalds 			       / sdebug_sectors_per;
52821da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
52831da177e4SLinus Torvalds 
5284150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5285150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
52861da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
52871da177e4SLinus Torvalds 	}
52881da177e4SLinus Torvalds }
52891da177e4SLinus Torvalds 
5290c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
5291c4837394SDouglas Gilbert {
5292c4837394SDouglas Gilbert 	int j;
5293c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5294c4837394SDouglas Gilbert 
5295c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5296c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
5297c4837394SDouglas Gilbert }
5298c4837394SDouglas Gilbert 
5299c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5300c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5301c4837394SDouglas Gilbert  */
5302c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5303c4837394SDouglas Gilbert {
5304c4837394SDouglas Gilbert 	int count, modulo;
5305c4837394SDouglas Gilbert 
5306c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5307c4837394SDouglas Gilbert 	if (modulo < 2)
5308c4837394SDouglas Gilbert 		return;
5309c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5310c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5311c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5312c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5313c4837394SDouglas Gilbert }
5314c4837394SDouglas Gilbert 
5315c4837394SDouglas Gilbert static void clear_queue_stats(void)
5316c4837394SDouglas Gilbert {
5317c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5318c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5319c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5320c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5321c4837394SDouglas Gilbert }
5322c4837394SDouglas Gilbert 
5323c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
5324c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
5325c4837394SDouglas Gilbert {
5326f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
5327f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
5328f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
5329f9ba7af8SMartin Wilck 				= sqcp->inj_dif
53307382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
53317382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
5332c4837394SDouglas Gilbert 		return;
5333f9ba7af8SMartin Wilck 	}
5334c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
5335c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
5336c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
5337c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
5338c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
53397ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
53407382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
5341c4837394SDouglas Gilbert }
5342c4837394SDouglas Gilbert 
5343a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5344a2aede97SDouglas Gilbert 
5345c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5346c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5347c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5348c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5349c4837394SDouglas Gilbert  */
5350fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5351f66b8517SMartin Wilck 			 int scsi_result,
5352f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
5353f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
5354f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
53551da177e4SLinus Torvalds {
5356a2aede97SDouglas Gilbert 	bool new_sd_dp;
5357cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
5358a2aede97SDouglas Gilbert 	unsigned long iflags;
5359a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5360c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
5361c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5362299b6c07STomas Winkler 	struct scsi_device *sdp;
5363a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
53641da177e4SLinus Torvalds 
5365b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5366b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5367f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5368f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
53691da177e4SLinus Torvalds 	}
5370299b6c07STomas Winkler 	sdp = cmnd->device;
5371299b6c07STomas Winkler 
5372cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
5373cd62b7daSDouglas Gilbert 		goto respond_in_thread;
53741da177e4SLinus Torvalds 
5375c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
5376c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
5377c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
5378c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5379c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
5380c4837394SDouglas Gilbert 	}
5381cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5382cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
5383cbf67842SDouglas Gilbert 	inject = 0;
5384f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
5385cd62b7daSDouglas Gilbert 		if (scsi_result) {
5386c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5387cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5388cd62b7daSDouglas Gilbert 		} else
5389cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5390c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
5391773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5392f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
5393cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
5394cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5395773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5396cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
5397cbf67842SDouglas Gilbert 			inject = 1;
5398cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
53991da177e4SLinus Torvalds 		}
5400cbf67842SDouglas Gilbert 	}
5401cbf67842SDouglas Gilbert 
5402c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
5403f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
5404c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5405cd62b7daSDouglas Gilbert 		if (scsi_result)
5406cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5407773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
5408cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5409773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
5410cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
5411cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
5412773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
5413cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
5414cbf67842SDouglas Gilbert 						    "report: host busy"));
5415cd62b7daSDouglas Gilbert 		if (scsi_result)
5416cd62b7daSDouglas Gilbert 			goto respond_in_thread;
5417cd62b7daSDouglas Gilbert 		else
5418cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
54191da177e4SLinus Torvalds 	}
5420c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
5421cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
5422c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
54231da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
5424c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
5425a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
5426c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5427c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
5428c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
542910bde980SDouglas Gilbert 	if (sd_dp == NULL) {
543010bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
543110bde980SDouglas Gilbert 		if (sd_dp == NULL)
543210bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
5433a2aede97SDouglas Gilbert 		new_sd_dp = true;
5434a2aede97SDouglas Gilbert 	} else {
5435a2aede97SDouglas Gilbert 		new_sd_dp = false;
543610bde980SDouglas Gilbert 	}
5437f66b8517SMartin Wilck 
5438a2aede97SDouglas Gilbert 	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
5439a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5440a2aede97SDouglas Gilbert 
5441a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
5442f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5443f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5444f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5445f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5446f66b8517SMartin Wilck 	}
5447f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5448f66b8517SMartin Wilck 		cmnd->result = scsi_result;
5449f66b8517SMartin Wilck 
5450f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5451f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5452f66b8517SMartin Wilck 			    __func__, cmnd->result);
5453f66b8517SMartin Wilck 
545410bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5455b333a819SDouglas Gilbert 		ktime_t kt;
5456cbf67842SDouglas Gilbert 
5457b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
54580c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
54590c4bc91dSDouglas Gilbert 
54600c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
54610c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
54620c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
54630c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
54640c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
54650c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
54660c4bc91dSDouglas Gilbert 				ns <<= 12;
54670c4bc91dSDouglas Gilbert 			}
54680c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
54690c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
54700c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
54710c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5472a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5473a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5474a2aede97SDouglas Gilbert 
5475a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5476a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
5477a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
5478a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
5479a2aede97SDouglas Gilbert 					if (new_sd_dp)
5480a2aede97SDouglas Gilbert 						kfree(sd_dp);
5481a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
5482a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
5483a2aede97SDouglas Gilbert 					return 0;
5484a2aede97SDouglas Gilbert 				}
5485a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5486a2aede97SDouglas Gilbert 				kt -= d;
5487a2aede97SDouglas Gilbert 			}
54880c4bc91dSDouglas Gilbert 		}
548910bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
549010bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
5491a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5492a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5493c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
5494a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5495c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5496c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5497cbf67842SDouglas Gilbert 		}
5498c4837394SDouglas Gilbert 		if (sdebug_statistics)
5499c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
550010bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
5501a2aede97SDouglas Gilbert 		/* schedule the invocation of scsi_done() for a later time */
5502c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
5503c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
550410bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
550510bde980SDouglas Gilbert 			sd_dp->init_wq = true;
5506a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
5507c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
5508c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
5509a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5510cbf67842SDouglas Gilbert 		}
5511c4837394SDouglas Gilbert 		if (sdebug_statistics)
5512c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
551310bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
55147382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
55157382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
5516a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
55177382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
55187382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
55197382f9d8SDouglas Gilbert 				    cmnd->request->tag);
55207382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
55217382f9d8SDouglas Gilbert 		}
5522cbf67842SDouglas Gilbert 	}
5523f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
5524f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
5525cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5526cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
5527cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
5528cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
55291da177e4SLinus Torvalds 	return 0;
5530cd62b7daSDouglas Gilbert 
5531cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5532f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5533f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5534f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5535cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
5536cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
5537cd62b7daSDouglas Gilbert 	return 0;
55381da177e4SLinus Torvalds }
5539cbf67842SDouglas Gilbert 
554023183910SDouglas Gilbert /* Note: The following macros create attribute files in the
554123183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
554223183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
554323183910SDouglas Gilbert    as it can when the corresponding attribute in the
554423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
554523183910SDouglas Gilbert  */
5546773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5547773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
55489b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5549773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5550c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5551773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5552773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5553773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5554773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5555773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5556773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5557773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5558773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5559e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5560e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5561e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5562e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
55635d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
55645d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
55655d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5566773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5567773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5568773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5569773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5570773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5571773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
55725d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
55735d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
55745d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
55755d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5576773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5577773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5578773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5579773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5580773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5581773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
55825d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5583773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
558487c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
558587c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5586773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5587773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
55880c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5589773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5590773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5591773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5592c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5593773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5594c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5595773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5596773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5597773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5598773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
559909ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
56005d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5601773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
560223183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
56039447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5604773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
56055b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
56069267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
5607380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5608aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
560998e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56101da177e4SLinus Torvalds 
56111da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56121da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
56131da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5614b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
56151da177e4SLinus Torvalds 
56165d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56175b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56189b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56190759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5620cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5621c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
56225b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
56235b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5624c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5625beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
562623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
56275b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5628185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5629e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
56309b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
56319b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
56325d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
56335d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
56345d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
56355b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
56365b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
56375b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
56385b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5639c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5640cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5641d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
56425d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5643cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5644c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
564578d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
56461da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5647c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
564832c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
564986e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
56505d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
56515d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
56525d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
56531da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
56540c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5655d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5656760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5657ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5658c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5659c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5660c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
56615b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
56625b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
56636014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
56646014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
566509ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
566609ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5667c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
56685b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
56699447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
56705b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
56719267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
5672380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5673aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
567498e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
56751da177e4SLinus Torvalds 
5676760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5677760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
56781da177e4SLinus Torvalds 
56791da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
56801da177e4SLinus Torvalds {
5681c4837394SDouglas Gilbert 	int k;
5682c4837394SDouglas Gilbert 
5683760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5684760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5685760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5686c4837394SDouglas Gilbert 		return sdebug_info;
5687760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5688760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5689760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5690760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
56911da177e4SLinus Torvalds 	return sdebug_info;
56921da177e4SLinus Torvalds }
56931da177e4SLinus Torvalds 
5694cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
5695fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5696fd32119bSDouglas Gilbert 				 int length)
56971da177e4SLinus Torvalds {
56981da177e4SLinus Torvalds 	char arr[16];
5699c8ed555aSAl Viro 	int opts;
57001da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
57011da177e4SLinus Torvalds 
57021da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
57031da177e4SLinus Torvalds 		return -EACCES;
57041da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
57051da177e4SLinus Torvalds 	arr[minLen] = '\0';
5706c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
57071da177e4SLinus Torvalds 		return -EINVAL;
5708773642d9SDouglas Gilbert 	sdebug_opts = opts;
5709773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5710773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5711773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5712c4837394SDouglas Gilbert 		tweak_cmnd_count();
57131da177e4SLinus Torvalds 	return length;
57141da177e4SLinus Torvalds }
5715c8ed555aSAl Viro 
5716cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5717cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5718cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
5719c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5720c8ed555aSAl Viro {
5721c4837394SDouglas Gilbert 	int f, j, l;
5722c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
572387c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5724cbf67842SDouglas Gilbert 
5725c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5726c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5727c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5728c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5729c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5730c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5731c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5732c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5733c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5734c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5735c4837394SDouglas Gilbert 		   num_aborts);
5736c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5737c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5738c4837394SDouglas Gilbert 		   num_host_resets);
5739c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5740c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5741458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5742458df78bSBart Van Assche 		   sdebug_statistics);
5743c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
5744c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5745c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5746c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
5747c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
5748cbf67842SDouglas Gilbert 
5749c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5750c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5751c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5752c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5753773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
5754c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5755c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5756c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5757c4837394SDouglas Gilbert 		}
5758cbf67842SDouglas Gilbert 	}
575987c715dcSDouglas Gilbert 
576087c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
576187c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
576287c715dcSDouglas Gilbert 		bool niu;
576387c715dcSDouglas Gilbert 		int idx;
576487c715dcSDouglas Gilbert 		unsigned long l_idx;
576587c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
576687c715dcSDouglas Gilbert 
576787c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
576887c715dcSDouglas Gilbert 		j = 0;
576987c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
577087c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
577187c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
577287c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
577387c715dcSDouglas Gilbert 			++j;
577487c715dcSDouglas Gilbert 		}
577587c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
577687c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
577787c715dcSDouglas Gilbert 		j = 0;
577887c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
577987c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
578087c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
578187c715dcSDouglas Gilbert 			idx = (int)l_idx;
578287c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
578387c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
578487c715dcSDouglas Gilbert 			++j;
578587c715dcSDouglas Gilbert 		}
578687c715dcSDouglas Gilbert 	}
5787c8ed555aSAl Viro 	return 0;
57881da177e4SLinus Torvalds }
57891da177e4SLinus Torvalds 
579082069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
57911da177e4SLinus Torvalds {
5792c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
57931da177e4SLinus Torvalds }
5794c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5795c4837394SDouglas Gilbert  * of delay is jiffies.
5796c4837394SDouglas Gilbert  */
579782069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
579882069379SAkinobu Mita 			   size_t count)
57991da177e4SLinus Torvalds {
5800c2206098SDouglas Gilbert 	int jdelay, res;
58011da177e4SLinus Torvalds 
5802b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
5803cbf67842SDouglas Gilbert 		res = count;
5804c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
5805c4837394SDouglas Gilbert 			int j, k;
5806c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5807cbf67842SDouglas Gilbert 
5808c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5809c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5810c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5811c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5812c4837394SDouglas Gilbert 						   sdebug_max_queue);
5813c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5814c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5815c4837394SDouglas Gilbert 					break;
5816c4837394SDouglas Gilbert 				}
5817c4837394SDouglas Gilbert 			}
5818c4837394SDouglas Gilbert 			if (res > 0) {
5819c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
5820773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
58211da177e4SLinus Torvalds 			}
5822c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5823cbf67842SDouglas Gilbert 		}
5824cbf67842SDouglas Gilbert 		return res;
58251da177e4SLinus Torvalds 	}
58261da177e4SLinus Torvalds 	return -EINVAL;
58271da177e4SLinus Torvalds }
582882069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
58291da177e4SLinus Torvalds 
5830cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5831cbf67842SDouglas Gilbert {
5832773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
5833cbf67842SDouglas Gilbert }
5834cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
5835c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
5836cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
5837cbf67842SDouglas Gilbert 			    size_t count)
5838cbf67842SDouglas Gilbert {
5839c4837394SDouglas Gilbert 	int ndelay, res;
5840cbf67842SDouglas Gilbert 
5841cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
5842c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
5843cbf67842SDouglas Gilbert 		res = count;
5844773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
5845c4837394SDouglas Gilbert 			int j, k;
5846c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
5847c4837394SDouglas Gilbert 
5848c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
5849c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5850c4837394SDouglas Gilbert 			     ++j, ++sqp) {
5851c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
5852c4837394SDouglas Gilbert 						   sdebug_max_queue);
5853c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
5854c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
5855c4837394SDouglas Gilbert 					break;
5856c4837394SDouglas Gilbert 				}
5857c4837394SDouglas Gilbert 			}
5858c4837394SDouglas Gilbert 			if (res > 0) {
5859773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
5860c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
5861c2206098SDouglas Gilbert 							: DEF_JDELAY;
5862cbf67842SDouglas Gilbert 			}
5863c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
5864cbf67842SDouglas Gilbert 		}
5865cbf67842SDouglas Gilbert 		return res;
5866cbf67842SDouglas Gilbert 	}
5867cbf67842SDouglas Gilbert 	return -EINVAL;
5868cbf67842SDouglas Gilbert }
5869cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
5870cbf67842SDouglas Gilbert 
587182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
58721da177e4SLinus Torvalds {
5873773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
58741da177e4SLinus Torvalds }
58751da177e4SLinus Torvalds 
587682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
587782069379SAkinobu Mita 			  size_t count)
58781da177e4SLinus Torvalds {
58791da177e4SLinus Torvalds 	int opts;
58801da177e4SLinus Torvalds 	char work[20];
58811da177e4SLinus Torvalds 
58829a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
58839a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
58849a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
58851da177e4SLinus Torvalds 				goto opts_done;
58861da177e4SLinus Torvalds 		} else {
58879a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
58881da177e4SLinus Torvalds 				goto opts_done;
58891da177e4SLinus Torvalds 		}
58901da177e4SLinus Torvalds 	}
58911da177e4SLinus Torvalds 	return -EINVAL;
58921da177e4SLinus Torvalds opts_done:
5893773642d9SDouglas Gilbert 	sdebug_opts = opts;
5894773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5895773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5896c4837394SDouglas Gilbert 	tweak_cmnd_count();
58971da177e4SLinus Torvalds 	return count;
58981da177e4SLinus Torvalds }
589982069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
59001da177e4SLinus Torvalds 
590182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
59021da177e4SLinus Torvalds {
5903773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
59041da177e4SLinus Torvalds }
590582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
590682069379SAkinobu Mita 			   size_t count)
59071da177e4SLinus Torvalds {
59081da177e4SLinus Torvalds 	int n;
59091da177e4SLinus Torvalds 
5910f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
5911f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
5912f0d1cf93SDouglas Gilbert 		return -EINVAL;
5913f0d1cf93SDouglas Gilbert 
59141da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5915f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
5916f0d1cf93SDouglas Gilbert 			return -EINVAL;
5917773642d9SDouglas Gilbert 		sdebug_ptype = n;
59181da177e4SLinus Torvalds 		return count;
59191da177e4SLinus Torvalds 	}
59201da177e4SLinus Torvalds 	return -EINVAL;
59211da177e4SLinus Torvalds }
592282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
59231da177e4SLinus Torvalds 
592482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
59251da177e4SLinus Torvalds {
5926773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
59271da177e4SLinus Torvalds }
592882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
592982069379SAkinobu Mita 			    size_t count)
59301da177e4SLinus Torvalds {
59311da177e4SLinus Torvalds 	int n;
59321da177e4SLinus Torvalds 
59331da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5934773642d9SDouglas Gilbert 		sdebug_dsense = n;
59351da177e4SLinus Torvalds 		return count;
59361da177e4SLinus Torvalds 	}
59371da177e4SLinus Torvalds 	return -EINVAL;
59381da177e4SLinus Torvalds }
593982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
59401da177e4SLinus Torvalds 
594182069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
594223183910SDouglas Gilbert {
5943773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
594423183910SDouglas Gilbert }
594582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
594682069379SAkinobu Mita 			     size_t count)
594723183910SDouglas Gilbert {
594887c715dcSDouglas Gilbert 	int n, idx;
594923183910SDouglas Gilbert 
595023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
595187c715dcSDouglas Gilbert 		bool want_store = (n == 0);
595287c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
595387c715dcSDouglas Gilbert 
5954cbf67842SDouglas Gilbert 		n = (n > 0);
5955773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
595687c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
595787c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
5958cbf67842SDouglas Gilbert 
595987c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
596087c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
596187c715dcSDouglas Gilbert 				idx = sdebug_add_store();
596287c715dcSDouglas Gilbert 				if (idx < 0)
596387c715dcSDouglas Gilbert 					return idx;
596487c715dcSDouglas Gilbert 			} else {
596587c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
596687c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
596787c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
5968cbf67842SDouglas Gilbert 			}
596987c715dcSDouglas Gilbert 			/* make all hosts use same store */
597087c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
597187c715dcSDouglas Gilbert 					    host_list) {
597287c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
597387c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
597487c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
597587c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
597687c715dcSDouglas Gilbert 				}
597787c715dcSDouglas Gilbert 			}
597887c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
597987c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
598087c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
5981cbf67842SDouglas Gilbert 		}
5982773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
598323183910SDouglas Gilbert 		return count;
598423183910SDouglas Gilbert 	}
598523183910SDouglas Gilbert 	return -EINVAL;
598623183910SDouglas Gilbert }
598782069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
598823183910SDouglas Gilbert 
598982069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
5990c65b1445SDouglas Gilbert {
5991773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
5992c65b1445SDouglas Gilbert }
599382069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
599482069379SAkinobu Mita 			      size_t count)
5995c65b1445SDouglas Gilbert {
5996c65b1445SDouglas Gilbert 	int n;
5997c65b1445SDouglas Gilbert 
5998c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5999773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6000c65b1445SDouglas Gilbert 		return count;
6001c65b1445SDouglas Gilbert 	}
6002c65b1445SDouglas Gilbert 	return -EINVAL;
6003c65b1445SDouglas Gilbert }
600482069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6005c65b1445SDouglas Gilbert 
600682069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
60071da177e4SLinus Torvalds {
6008773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60091da177e4SLinus Torvalds }
601082069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
601182069379SAkinobu Mita 			      size_t count)
60121da177e4SLinus Torvalds {
60131da177e4SLinus Torvalds 	int n;
60141da177e4SLinus Torvalds 
60151da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6016773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
60171da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
60181da177e4SLinus Torvalds 		return count;
60191da177e4SLinus Torvalds 	}
60201da177e4SLinus Torvalds 	return -EINVAL;
60211da177e4SLinus Torvalds }
602282069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
60231da177e4SLinus Torvalds 
602482069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
60251da177e4SLinus Torvalds {
6026773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
60271da177e4SLinus Torvalds }
602882069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
60291da177e4SLinus Torvalds 
603087c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
603187c715dcSDouglas Gilbert {
603287c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
603387c715dcSDouglas Gilbert }
603487c715dcSDouglas Gilbert 
603587c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
603687c715dcSDouglas Gilbert 				    size_t count)
603787c715dcSDouglas Gilbert {
603887c715dcSDouglas Gilbert 	bool v;
603987c715dcSDouglas Gilbert 
604087c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
604187c715dcSDouglas Gilbert 		return -EINVAL;
604287c715dcSDouglas Gilbert 
604387c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
604487c715dcSDouglas Gilbert 	return count;
604587c715dcSDouglas Gilbert }
604687c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
604787c715dcSDouglas Gilbert 
604882069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
60491da177e4SLinus Torvalds {
6050773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
60511da177e4SLinus Torvalds }
605282069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
60531da177e4SLinus Torvalds 
605482069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
60551da177e4SLinus Torvalds {
6056773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
60571da177e4SLinus Torvalds }
605882069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
605982069379SAkinobu Mita 			       size_t count)
60601da177e4SLinus Torvalds {
60611da177e4SLinus Torvalds 	int nth;
60621da177e4SLinus Torvalds 
60631da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
6064773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
6065c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
6066c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
6067c4837394SDouglas Gilbert 			sdebug_statistics = true;
6068c4837394SDouglas Gilbert 		}
6069c4837394SDouglas Gilbert 		tweak_cmnd_count();
60701da177e4SLinus Torvalds 		return count;
60711da177e4SLinus Torvalds 	}
60721da177e4SLinus Torvalds 	return -EINVAL;
60731da177e4SLinus Torvalds }
607482069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
60751da177e4SLinus Torvalds 
607682069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
60771da177e4SLinus Torvalds {
6078773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
60791da177e4SLinus Torvalds }
608082069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
608182069379SAkinobu Mita 			      size_t count)
60821da177e4SLinus Torvalds {
60831da177e4SLinus Torvalds 	int n;
608419c8ead7SEwan D. Milne 	bool changed;
60851da177e4SLinus Torvalds 
60861da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60878d039e22SDouglas Gilbert 		if (n > 256) {
60888d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
60898d039e22SDouglas Gilbert 			return -EINVAL;
60908d039e22SDouglas Gilbert 		}
6091773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6092773642d9SDouglas Gilbert 		sdebug_max_luns = n;
60931da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6094773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
609519c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
609619c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
609719c8ead7SEwan D. Milne 
609819c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
609919c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
610019c8ead7SEwan D. Milne 					    host_list) {
610119c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
610219c8ead7SEwan D. Milne 						    dev_list) {
610319c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
610419c8ead7SEwan D. Milne 						dp->uas_bm);
610519c8ead7SEwan D. Milne 				}
610619c8ead7SEwan D. Milne 			}
610719c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
610819c8ead7SEwan D. Milne 		}
61091da177e4SLinus Torvalds 		return count;
61101da177e4SLinus Torvalds 	}
61111da177e4SLinus Torvalds 	return -EINVAL;
61121da177e4SLinus Torvalds }
611382069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
61141da177e4SLinus Torvalds 
611582069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
611678d4e5a0SDouglas Gilbert {
6117773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
611878d4e5a0SDouglas Gilbert }
6119cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6120cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
612182069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
612282069379SAkinobu Mita 			       size_t count)
612378d4e5a0SDouglas Gilbert {
6124c4837394SDouglas Gilbert 	int j, n, k, a;
6125c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
612678d4e5a0SDouglas Gilbert 
612778d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6128c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
6129c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
6130c4837394SDouglas Gilbert 		k = 0;
6131c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6132c4837394SDouglas Gilbert 		     ++j, ++sqp) {
6133c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6134c4837394SDouglas Gilbert 			if (a > k)
6135c4837394SDouglas Gilbert 				k = a;
6136c4837394SDouglas Gilbert 		}
6137773642d9SDouglas Gilbert 		sdebug_max_queue = n;
6138c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
6139cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6140cbf67842SDouglas Gilbert 		else if (k >= n)
6141cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
6142cbf67842SDouglas Gilbert 		else
6143cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
6144c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
614578d4e5a0SDouglas Gilbert 		return count;
614678d4e5a0SDouglas Gilbert 	}
614778d4e5a0SDouglas Gilbert 	return -EINVAL;
614878d4e5a0SDouglas Gilbert }
614982069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
615078d4e5a0SDouglas Gilbert 
615182069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
615278d4e5a0SDouglas Gilbert {
6153773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
615478d4e5a0SDouglas Gilbert }
615582069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
615678d4e5a0SDouglas Gilbert 
615782069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
61581da177e4SLinus Torvalds {
6159773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
61601da177e4SLinus Torvalds }
616182069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
61621da177e4SLinus Torvalds 
616382069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6164c65b1445SDouglas Gilbert {
6165773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6166c65b1445SDouglas Gilbert }
616782069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
616882069379SAkinobu Mita 				size_t count)
6169c65b1445SDouglas Gilbert {
6170c65b1445SDouglas Gilbert 	int n;
61710d01c5dfSDouglas Gilbert 	bool changed;
6172c65b1445SDouglas Gilbert 
6173f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6174f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6175f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6176f0d1cf93SDouglas Gilbert 
6177c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6178773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6179773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
618028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
61810d01c5dfSDouglas Gilbert 		if (changed) {
61820d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
61830d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
618428898873SFUJITA Tomonori 
61854bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
61860d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
61870d01c5dfSDouglas Gilbert 					    host_list) {
61880d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
61890d01c5dfSDouglas Gilbert 						    dev_list) {
61900d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
61910d01c5dfSDouglas Gilbert 						dp->uas_bm);
61920d01c5dfSDouglas Gilbert 				}
61930d01c5dfSDouglas Gilbert 			}
61944bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
61950d01c5dfSDouglas Gilbert 		}
6196c65b1445SDouglas Gilbert 		return count;
6197c65b1445SDouglas Gilbert 	}
6198c65b1445SDouglas Gilbert 	return -EINVAL;
6199c65b1445SDouglas Gilbert }
620082069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6201c65b1445SDouglas Gilbert 
620282069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
62031da177e4SLinus Torvalds {
620487c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
620587c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
62061da177e4SLinus Torvalds }
62071da177e4SLinus Torvalds 
620882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
620982069379SAkinobu Mita 			      size_t count)
62101da177e4SLinus Torvalds {
621187c715dcSDouglas Gilbert 	bool found;
621287c715dcSDouglas Gilbert 	unsigned long idx;
621387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
621487c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
62151da177e4SLinus Torvalds 	int delta_hosts;
62161da177e4SLinus Torvalds 
6217f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
62181da177e4SLinus Torvalds 		return -EINVAL;
62191da177e4SLinus Torvalds 	if (delta_hosts > 0) {
62201da177e4SLinus Torvalds 		do {
622187c715dcSDouglas Gilbert 			found = false;
622287c715dcSDouglas Gilbert 			if (want_phs) {
622387c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
622487c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
622587c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
622687c715dcSDouglas Gilbert 					found = true;
622787c715dcSDouglas Gilbert 					break;
622887c715dcSDouglas Gilbert 				}
622987c715dcSDouglas Gilbert 				if (found)	/* re-use case */
623087c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
623187c715dcSDouglas Gilbert 				else
623287c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
623387c715dcSDouglas Gilbert 			} else {
623487c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
623587c715dcSDouglas Gilbert 			}
62361da177e4SLinus Torvalds 		} while (--delta_hosts);
62371da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
62381da177e4SLinus Torvalds 		do {
623987c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
62401da177e4SLinus Torvalds 		} while (++delta_hosts);
62411da177e4SLinus Torvalds 	}
62421da177e4SLinus Torvalds 	return count;
62431da177e4SLinus Torvalds }
624482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
62451da177e4SLinus Torvalds 
624682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
624723183910SDouglas Gilbert {
6248773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
624923183910SDouglas Gilbert }
625082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
625182069379SAkinobu Mita 				    size_t count)
625223183910SDouglas Gilbert {
625323183910SDouglas Gilbert 	int n;
625423183910SDouglas Gilbert 
625523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6256773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
625723183910SDouglas Gilbert 		return count;
625823183910SDouglas Gilbert 	}
625923183910SDouglas Gilbert 	return -EINVAL;
626023183910SDouglas Gilbert }
626182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
626223183910SDouglas Gilbert 
6263c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6264c4837394SDouglas Gilbert {
6265c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6266c4837394SDouglas Gilbert }
6267c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6268c4837394SDouglas Gilbert 				size_t count)
6269c4837394SDouglas Gilbert {
6270c4837394SDouglas Gilbert 	int n;
6271c4837394SDouglas Gilbert 
6272c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6273c4837394SDouglas Gilbert 		if (n > 0)
6274c4837394SDouglas Gilbert 			sdebug_statistics = true;
6275c4837394SDouglas Gilbert 		else {
6276c4837394SDouglas Gilbert 			clear_queue_stats();
6277c4837394SDouglas Gilbert 			sdebug_statistics = false;
6278c4837394SDouglas Gilbert 		}
6279c4837394SDouglas Gilbert 		return count;
6280c4837394SDouglas Gilbert 	}
6281c4837394SDouglas Gilbert 	return -EINVAL;
6282c4837394SDouglas Gilbert }
6283c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6284c4837394SDouglas Gilbert 
628582069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6286597136abSMartin K. Petersen {
6287773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6288597136abSMartin K. Petersen }
628982069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6290597136abSMartin K. Petersen 
6291c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6292c4837394SDouglas Gilbert {
6293c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6294c4837394SDouglas Gilbert }
6295c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6296c4837394SDouglas Gilbert 
629782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6298c6a44287SMartin K. Petersen {
6299773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6300c6a44287SMartin K. Petersen }
630182069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6302c6a44287SMartin K. Petersen 
630382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6304c6a44287SMartin K. Petersen {
6305773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6306c6a44287SMartin K. Petersen }
630782069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6308c6a44287SMartin K. Petersen 
630982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6310c6a44287SMartin K. Petersen {
6311773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6312c6a44287SMartin K. Petersen }
631382069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6314c6a44287SMartin K. Petersen 
631582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6316c6a44287SMartin K. Petersen {
6317773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6318c6a44287SMartin K. Petersen }
631982069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6320c6a44287SMartin K. Petersen 
632182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
632244d92694SMartin K. Petersen {
632387c715dcSDouglas Gilbert 	ssize_t count = 0;
632444d92694SMartin K. Petersen 
63255b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
632644d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
632744d92694SMartin K. Petersen 				 sdebug_store_sectors);
632844d92694SMartin K. Petersen 
632987c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
633087c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
633187c715dcSDouglas Gilbert 
633287c715dcSDouglas Gilbert 		if (sip)
6333c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
633487c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
633587c715dcSDouglas Gilbert 	}
633644d92694SMartin K. Petersen 	buf[count++] = '\n';
6337c7badc90STejun Heo 	buf[count] = '\0';
633844d92694SMartin K. Petersen 
633944d92694SMartin K. Petersen 	return count;
634044d92694SMartin K. Petersen }
634182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
634244d92694SMartin K. Petersen 
63430c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
63440c4bc91dSDouglas Gilbert {
63450c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
63460c4bc91dSDouglas Gilbert }
63470c4bc91dSDouglas Gilbert 
63480c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
63490c4bc91dSDouglas Gilbert 			    size_t count)
63500c4bc91dSDouglas Gilbert {
63510c4bc91dSDouglas Gilbert 	bool v;
63520c4bc91dSDouglas Gilbert 
63530c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
63540c4bc91dSDouglas Gilbert 		return -EINVAL;
63550c4bc91dSDouglas Gilbert 
63560c4bc91dSDouglas Gilbert 	sdebug_random = v;
63570c4bc91dSDouglas Gilbert 	return count;
63580c4bc91dSDouglas Gilbert }
63590c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
63600c4bc91dSDouglas Gilbert 
636182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6362d986788bSMartin Pitt {
6363773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6364d986788bSMartin Pitt }
636582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
636682069379SAkinobu Mita 			       size_t count)
6367d986788bSMartin Pitt {
6368d986788bSMartin Pitt 	int n;
6369d986788bSMartin Pitt 
6370d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6371773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6372d986788bSMartin Pitt 		return count;
6373d986788bSMartin Pitt 	}
6374d986788bSMartin Pitt 	return -EINVAL;
6375d986788bSMartin Pitt }
637682069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6377d986788bSMartin Pitt 
6378cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6379cbf67842SDouglas Gilbert {
6380773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6381cbf67842SDouglas Gilbert }
6382185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
6383cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6384cbf67842SDouglas Gilbert 			       size_t count)
6385cbf67842SDouglas Gilbert {
6386185dd232SDouglas Gilbert 	int n;
6387cbf67842SDouglas Gilbert 
6388cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6389185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6390185dd232SDouglas Gilbert 		return count;
6391cbf67842SDouglas Gilbert 	}
6392cbf67842SDouglas Gilbert 	return -EINVAL;
6393cbf67842SDouglas Gilbert }
6394cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6395cbf67842SDouglas Gilbert 
6396c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6397c2248fc9SDouglas Gilbert {
6398773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6399c2248fc9SDouglas Gilbert }
6400c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6401c2248fc9SDouglas Gilbert 			    size_t count)
6402c2248fc9SDouglas Gilbert {
6403c2248fc9SDouglas Gilbert 	int n;
6404c2248fc9SDouglas Gilbert 
6405c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6406773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6407c2248fc9SDouglas Gilbert 		return count;
6408c2248fc9SDouglas Gilbert 	}
6409c2248fc9SDouglas Gilbert 	return -EINVAL;
6410c2248fc9SDouglas Gilbert }
6411c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6412c2248fc9SDouglas Gilbert 
641309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
641409ba24c1SDouglas Gilbert {
641509ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
641609ba24c1SDouglas Gilbert }
641709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
641809ba24c1SDouglas Gilbert 
64199b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
64209b760fd8SDouglas Gilbert {
64219b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
64229b760fd8SDouglas Gilbert }
64239b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
64249b760fd8SDouglas Gilbert 			     size_t count)
64259b760fd8SDouglas Gilbert {
64269b760fd8SDouglas Gilbert 	int ret, n;
64279b760fd8SDouglas Gilbert 
64289b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
64299b760fd8SDouglas Gilbert 	if (ret)
64309b760fd8SDouglas Gilbert 		return ret;
64319b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
64329b760fd8SDouglas Gilbert 	all_config_cdb_len();
64339b760fd8SDouglas Gilbert 	return count;
64349b760fd8SDouglas Gilbert }
64359b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
64369b760fd8SDouglas Gilbert 
64379267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
64389267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
64399267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
64409267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
64419267e0ebSDouglas Gilbert };
64429267e0ebSDouglas Gilbert 
64439267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
64449267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
64459267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
64469267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
64479267e0ebSDouglas Gilbert };
64489267e0ebSDouglas Gilbert 
64499267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
64509267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
64519267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
64529267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
64539267e0ebSDouglas Gilbert };
64549267e0ebSDouglas Gilbert 
64559267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
64569267e0ebSDouglas Gilbert {
64579267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
64589267e0ebSDouglas Gilbert 
64599267e0ebSDouglas Gilbert 	if (res < 0) {
64609267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
64619267e0ebSDouglas Gilbert 		if (res < 0) {
64629267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
646347742bdeSDan Carpenter 			if (res < 0)
64649267e0ebSDouglas Gilbert 				return -EINVAL;
64659267e0ebSDouglas Gilbert 		}
64669267e0ebSDouglas Gilbert 	}
64679267e0ebSDouglas Gilbert 	return res;
64689267e0ebSDouglas Gilbert }
64699267e0ebSDouglas Gilbert 
64709267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
64719267e0ebSDouglas Gilbert {
64729267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
64739267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
64749267e0ebSDouglas Gilbert }
64759267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6476cbf67842SDouglas Gilbert 
647782069379SAkinobu Mita /* Note: The following array creates attribute files in the
647823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
647923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
648023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
648187c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
648223183910SDouglas Gilbert  */
64836ecaff7fSRandy Dunlap 
648482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
648582069379SAkinobu Mita 	&driver_attr_delay.attr,
648682069379SAkinobu Mita 	&driver_attr_opts.attr,
648782069379SAkinobu Mita 	&driver_attr_ptype.attr,
648882069379SAkinobu Mita 	&driver_attr_dsense.attr,
648982069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
649082069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
649182069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
649282069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
649382069379SAkinobu Mita 	&driver_attr_num_parts.attr,
649482069379SAkinobu Mita 	&driver_attr_every_nth.attr,
649582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
649682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
649782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
649882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
649982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
650082069379SAkinobu Mita 	&driver_attr_add_host.attr,
650187c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
650282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
650382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6504c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6505c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
650682069379SAkinobu Mita 	&driver_attr_dix.attr,
650782069379SAkinobu Mita 	&driver_attr_dif.attr,
650882069379SAkinobu Mita 	&driver_attr_guard.attr,
650982069379SAkinobu Mita 	&driver_attr_ato.attr,
651082069379SAkinobu Mita 	&driver_attr_map.attr,
65110c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
651282069379SAkinobu Mita 	&driver_attr_removable.attr,
6513cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6514cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6515c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
651609ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
65179b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
65189267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
651982069379SAkinobu Mita 	NULL,
652082069379SAkinobu Mita };
652182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
65221da177e4SLinus Torvalds 
652311ddcecaSAkinobu Mita static struct device *pseudo_primary;
65248dea0d02SFUJITA Tomonori 
65251da177e4SLinus Torvalds static int __init scsi_debug_init(void)
65261da177e4SLinus Torvalds {
652787c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
65285f2578e5SFUJITA Tomonori 	unsigned long sz;
652987c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
653087c715dcSDouglas Gilbert 	int idx = -1;
65311da177e4SLinus Torvalds 
653287c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
653387c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
6534cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
6535cbf67842SDouglas Gilbert 
6536773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6537c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6538773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6539773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6540c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6541cbf67842SDouglas Gilbert 
6542773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6543597136abSMartin K. Petersen 	case  512:
6544597136abSMartin K. Petersen 	case 1024:
6545597136abSMartin K. Petersen 	case 2048:
6546597136abSMartin K. Petersen 	case 4096:
6547597136abSMartin K. Petersen 		break;
6548597136abSMartin K. Petersen 	default:
6549773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6550597136abSMartin K. Petersen 		return -EINVAL;
6551597136abSMartin K. Petersen 	}
6552597136abSMartin K. Petersen 
6553773642d9SDouglas Gilbert 	switch (sdebug_dif) {
65548475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6555f46eb0e9SDouglas Gilbert 		break;
65568475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
65578475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
65588475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6559f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6560c6a44287SMartin K. Petersen 		break;
6561c6a44287SMartin K. Petersen 
6562c6a44287SMartin K. Petersen 	default:
6563c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6564c6a44287SMartin K. Petersen 		return -EINVAL;
6565c6a44287SMartin K. Petersen 	}
6566c6a44287SMartin K. Petersen 
6567aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6568aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6569aa5334c4SMaurizio Lombardi 		return -EINVAL;
6570aa5334c4SMaurizio Lombardi 	}
6571aa5334c4SMaurizio Lombardi 
6572773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6573c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6574c6a44287SMartin K. Petersen 		return -EINVAL;
6575c6a44287SMartin K. Petersen 	}
6576c6a44287SMartin K. Petersen 
6577773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6578c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6579c6a44287SMartin K. Petersen 		return -EINVAL;
6580c6a44287SMartin K. Petersen 	}
6581c6a44287SMartin K. Petersen 
6582773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6583773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6584ea61fca5SMartin K. Petersen 		return -EINVAL;
6585ea61fca5SMartin K. Petersen 	}
65868d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
65878d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
65888d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
65898d039e22SDouglas Gilbert 	}
6590ea61fca5SMartin K. Petersen 
6591773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6592773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6593ea61fca5SMartin K. Petersen 		return -EINVAL;
6594ea61fca5SMartin K. Petersen 	}
6595ea61fca5SMartin K. Petersen 
6596c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6597c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6598c4837394SDouglas Gilbert 		return -EINVAL;
6599c4837394SDouglas Gilbert 	}
6600c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6601c4837394SDouglas Gilbert 			       GFP_KERNEL);
6602c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
6603c4837394SDouglas Gilbert 		return -ENOMEM;
6604c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
6605c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
6606c4837394SDouglas Gilbert 
6607f0d1cf93SDouglas Gilbert 	/*
66089267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
66099267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6610f0d1cf93SDouglas Gilbert 	 */
66119267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
66129267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
66139267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
66149267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
66159267e0ebSDouglas Gilbert 		if (k < 0) {
66169267e0ebSDouglas Gilbert 			ret = k;
66179267e0ebSDouglas Gilbert 			goto free_vm;
66189267e0ebSDouglas Gilbert 		}
66199267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
66209267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
66219267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
662264e14eceSDamien Le Moal 		case BLK_ZONED_HA:
66239267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
66249267e0ebSDouglas Gilbert 			break;
66259267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
66269267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
66279267e0ebSDouglas Gilbert 			break;
66289267e0ebSDouglas Gilbert 		default:
66299267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
66309267e0ebSDouglas Gilbert 			return -EINVAL;
66319267e0ebSDouglas Gilbert 		}
66329267e0ebSDouglas Gilbert 	}
66339267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6634f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
66359267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
66369267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
66379267e0ebSDouglas Gilbert 	}
6638f0d1cf93SDouglas Gilbert 
66399267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
66409267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6641773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6642773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6643773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6644773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
664528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
66461da177e4SLinus Torvalds 
66471da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
66481da177e4SLinus Torvalds 	sdebug_heads = 8;
66491da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6650773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
66511da177e4SLinus Torvalds 		sdebug_heads = 64;
6652773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6653fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
66541da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
66551da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
66561da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
66571da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
66581da177e4SLinus Torvalds 		sdebug_heads = 255;
66591da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
66601da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
66611da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
66621da177e4SLinus Torvalds 	}
66635b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6664773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6665773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
66666014759cSMartin K. Petersen 
6667773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6668773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
66696014759cSMartin K. Petersen 
6670773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6671773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
66726014759cSMartin K. Petersen 
6673773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6674773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6675773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6676c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6677c4837394SDouglas Gilbert 			ret = -EINVAL;
667887c715dcSDouglas Gilbert 			goto free_q_arr;
667944d92694SMartin K. Petersen 		}
668044d92694SMartin K. Petersen 	}
668187c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
668287c715dcSDouglas Gilbert 	if (want_store) {
668387c715dcSDouglas Gilbert 		idx = sdebug_add_store();
668487c715dcSDouglas Gilbert 		if (idx < 0) {
668587c715dcSDouglas Gilbert 			ret = idx;
668687c715dcSDouglas Gilbert 			goto free_q_arr;
668787c715dcSDouglas Gilbert 		}
668844d92694SMartin K. Petersen 	}
668944d92694SMartin K. Petersen 
66909b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
66919b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6692c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
66939b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
66946ecaff7fSRandy Dunlap 		goto free_vm;
66956ecaff7fSRandy Dunlap 	}
66966ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
66976ecaff7fSRandy Dunlap 	if (ret < 0) {
6698c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
66996ecaff7fSRandy Dunlap 		goto dev_unreg;
67006ecaff7fSRandy Dunlap 	}
67016ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
67026ecaff7fSRandy Dunlap 	if (ret < 0) {
6703c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
67046ecaff7fSRandy Dunlap 		goto bus_unreg;
67056ecaff7fSRandy Dunlap 	}
67061da177e4SLinus Torvalds 
670787c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
6708773642d9SDouglas Gilbert 	sdebug_add_host = 0;
67091da177e4SLinus Torvalds 
671087c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
671187c715dcSDouglas Gilbert 		if (want_store && k == 0) {
671287c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
671387c715dcSDouglas Gilbert 			if (ret < 0) {
671487c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
671587c715dcSDouglas Gilbert 				       k, -ret);
671687c715dcSDouglas Gilbert 				break;
671787c715dcSDouglas Gilbert 			}
671887c715dcSDouglas Gilbert 		} else {
671987c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
672087c715dcSDouglas Gilbert 						 sdebug_per_host_store);
672187c715dcSDouglas Gilbert 			if (ret < 0) {
672287c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
67231da177e4SLinus Torvalds 				break;
67241da177e4SLinus Torvalds 			}
67251da177e4SLinus Torvalds 		}
672687c715dcSDouglas Gilbert 	}
6727773642d9SDouglas Gilbert 	if (sdebug_verbose)
672887c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
6729c1287970STomas Winkler 
67301da177e4SLinus Torvalds 	return 0;
67316ecaff7fSRandy Dunlap 
67326ecaff7fSRandy Dunlap bus_unreg:
67336ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
67346ecaff7fSRandy Dunlap dev_unreg:
67359b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
67366ecaff7fSRandy Dunlap free_vm:
673787c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
6738c4837394SDouglas Gilbert free_q_arr:
6739c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
67406ecaff7fSRandy Dunlap 	return ret;
67411da177e4SLinus Torvalds }
67421da177e4SLinus Torvalds 
67431da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
67441da177e4SLinus Torvalds {
674587c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
67461da177e4SLinus Torvalds 
67471da177e4SLinus Torvalds 	stop_all_queued();
67481da177e4SLinus Torvalds 	for (; k; k--)
674987c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
675052ab9768SLuis Henriques 	free_all_queued();
67511da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
67521da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
67539b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
67541da177e4SLinus Torvalds 
675587c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
675687c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
67571da177e4SLinus Torvalds }
67581da177e4SLinus Torvalds 
67591da177e4SLinus Torvalds device_initcall(scsi_debug_init);
67601da177e4SLinus Torvalds module_exit(scsi_debug_exit);
67611da177e4SLinus Torvalds 
67621da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
67631da177e4SLinus Torvalds {
67641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
67651da177e4SLinus Torvalds 
67661da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
67671da177e4SLinus Torvalds 	kfree(sdbg_host);
67681da177e4SLinus Torvalds }
67691da177e4SLinus Torvalds 
677087c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
677187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
67721da177e4SLinus Torvalds {
677387c715dcSDouglas Gilbert 	if (idx < 0)
677487c715dcSDouglas Gilbert 		return;
677587c715dcSDouglas Gilbert 	if (!sip) {
677687c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
677787c715dcSDouglas Gilbert 			return;
677887c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
677987c715dcSDouglas Gilbert 		if (!sip)
678087c715dcSDouglas Gilbert 			return;
678187c715dcSDouglas Gilbert 	}
678287c715dcSDouglas Gilbert 	vfree(sip->map_storep);
678387c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
678487c715dcSDouglas Gilbert 	vfree(sip->storep);
678587c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
678687c715dcSDouglas Gilbert 	kfree(sip);
678787c715dcSDouglas Gilbert }
678887c715dcSDouglas Gilbert 
678987c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
679087c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
679187c715dcSDouglas Gilbert {
679287c715dcSDouglas Gilbert 	unsigned long idx;
679387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
679487c715dcSDouglas Gilbert 
679587c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
679687c715dcSDouglas Gilbert 		if (apart_from_first)
679787c715dcSDouglas Gilbert 			apart_from_first = false;
679887c715dcSDouglas Gilbert 		else
679987c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
680087c715dcSDouglas Gilbert 	}
680187c715dcSDouglas Gilbert 	if (apart_from_first)
680287c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
680387c715dcSDouglas Gilbert }
680487c715dcSDouglas Gilbert 
680587c715dcSDouglas Gilbert /*
680687c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
680787c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
680887c715dcSDouglas Gilbert  */
680987c715dcSDouglas Gilbert static int sdebug_add_store(void)
681087c715dcSDouglas Gilbert {
681187c715dcSDouglas Gilbert 	int res;
681287c715dcSDouglas Gilbert 	u32 n_idx;
681387c715dcSDouglas Gilbert 	unsigned long iflags;
681487c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
681587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
681687c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
681787c715dcSDouglas Gilbert 
681887c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
681987c715dcSDouglas Gilbert 	if (!sip)
682087c715dcSDouglas Gilbert 		return -ENOMEM;
682187c715dcSDouglas Gilbert 
682287c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
682387c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
682487c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
682587c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
682687c715dcSDouglas Gilbert 		kfree(sip);
682787c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
682887c715dcSDouglas Gilbert 		return res;
682987c715dcSDouglas Gilbert 	}
683087c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
683187c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
683287c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
683387c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
683487c715dcSDouglas Gilbert 
683587c715dcSDouglas Gilbert 	res = -ENOMEM;
683687c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
683787c715dcSDouglas Gilbert 	if (!sip->storep) {
683887c715dcSDouglas Gilbert 		pr_err("user data oom\n");
683987c715dcSDouglas Gilbert 		goto err;
684087c715dcSDouglas Gilbert 	}
684187c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
684287c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
684387c715dcSDouglas Gilbert 
684487c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
684587c715dcSDouglas Gilbert 	if (sdebug_dix) {
684687c715dcSDouglas Gilbert 		int dif_size;
684787c715dcSDouglas Gilbert 
684887c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
684987c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
685087c715dcSDouglas Gilbert 
685187c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
685287c715dcSDouglas Gilbert 			sip->dif_storep);
685387c715dcSDouglas Gilbert 
685487c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
685587c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
685687c715dcSDouglas Gilbert 			goto err;
685787c715dcSDouglas Gilbert 		}
685887c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
685987c715dcSDouglas Gilbert 	}
686087c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
686187c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
686287c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
686387c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
686487c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
686587c715dcSDouglas Gilbert 
686687c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
686787c715dcSDouglas Gilbert 
686887c715dcSDouglas Gilbert 		if (!sip->map_storep) {
686987c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
687087c715dcSDouglas Gilbert 			goto err;
687187c715dcSDouglas Gilbert 		}
687287c715dcSDouglas Gilbert 
687387c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
687487c715dcSDouglas Gilbert 
687587c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
687687c715dcSDouglas Gilbert 		if (sdebug_num_parts)
687787c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
687887c715dcSDouglas Gilbert 	}
687987c715dcSDouglas Gilbert 
688087c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
688187c715dcSDouglas Gilbert 	return (int)n_idx;
688287c715dcSDouglas Gilbert err:
688387c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
688487c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
688587c715dcSDouglas Gilbert 	return res;
688687c715dcSDouglas Gilbert }
688787c715dcSDouglas Gilbert 
688887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
688987c715dcSDouglas Gilbert {
689087c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
689187c715dcSDouglas Gilbert 	int error = -ENOMEM;
68921da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
68938b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
68941da177e4SLinus Torvalds 
689524669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
689687c715dcSDouglas Gilbert 	if (!sdbg_host)
68971da177e4SLinus Torvalds 		return -ENOMEM;
689887c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
689987c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
690087c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
690187c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
69021da177e4SLinus Torvalds 
69031da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
69041da177e4SLinus Torvalds 
6905773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
69061da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
69075cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
690887c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
69091da177e4SLinus Torvalds 			goto clean;
69101da177e4SLinus Torvalds 	}
69111da177e4SLinus Torvalds 
69121da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
69131da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
69141da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
69151da177e4SLinus Torvalds 
69161da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
69179b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
69181da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
691987c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
69201da177e4SLinus Torvalds 
69211da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
69221da177e4SLinus Torvalds 	if (error)
69231da177e4SLinus Torvalds 		goto clean;
69241da177e4SLinus Torvalds 
692587c715dcSDouglas Gilbert 	++sdebug_num_hosts;
692687c715dcSDouglas Gilbert 	return 0;
69271da177e4SLinus Torvalds 
69281da177e4SLinus Torvalds clean:
69298b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
69308b40228fSFUJITA Tomonori 				 dev_list) {
69311da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
6932f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
69331da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
69341da177e4SLinus Torvalds 	}
69351da177e4SLinus Torvalds 	kfree(sdbg_host);
693687c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
69371da177e4SLinus Torvalds 	return error;
69381da177e4SLinus Torvalds }
69391da177e4SLinus Torvalds 
694087c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
69411da177e4SLinus Torvalds {
694287c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
694387c715dcSDouglas Gilbert 
694487c715dcSDouglas Gilbert 	if (mk_new_store) {
694587c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
694687c715dcSDouglas Gilbert 		if (ph_idx < 0)
694787c715dcSDouglas Gilbert 			return ph_idx;
694887c715dcSDouglas Gilbert 	}
694987c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
695087c715dcSDouglas Gilbert }
695187c715dcSDouglas Gilbert 
695287c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
695387c715dcSDouglas Gilbert {
695487c715dcSDouglas Gilbert 	int idx = -1;
69551da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
695687c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
69571da177e4SLinus Torvalds 
69581da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
69591da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
69601da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
69611da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
696287c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
69631da177e4SLinus Torvalds 	}
696487c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
696587c715dcSDouglas Gilbert 		bool unique = true;
696687c715dcSDouglas Gilbert 
696787c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
696887c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
696987c715dcSDouglas Gilbert 				continue;
697087c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
697187c715dcSDouglas Gilbert 				unique = false;
697287c715dcSDouglas Gilbert 				break;
697387c715dcSDouglas Gilbert 			}
697487c715dcSDouglas Gilbert 		}
697587c715dcSDouglas Gilbert 		if (unique) {
697687c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
697787c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
697887c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
697987c715dcSDouglas Gilbert 		}
698087c715dcSDouglas Gilbert 	}
698187c715dcSDouglas Gilbert 	if (sdbg_host)
698287c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
69831da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
69841da177e4SLinus Torvalds 
69851da177e4SLinus Torvalds 	if (!sdbg_host)
69861da177e4SLinus Torvalds 		return;
69871da177e4SLinus Torvalds 
69881da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
698987c715dcSDouglas Gilbert 	--sdebug_num_hosts;
69901da177e4SLinus Torvalds }
69911da177e4SLinus Torvalds 
6992fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
6993cbf67842SDouglas Gilbert {
6994cbf67842SDouglas Gilbert 	int num_in_q = 0;
6995cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
6996cbf67842SDouglas Gilbert 
6997c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
6998cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
6999cbf67842SDouglas Gilbert 	if (NULL == devip) {
7000c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
7001cbf67842SDouglas Gilbert 		return	-ENODEV;
7002cbf67842SDouglas Gilbert 	}
7003cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
7004c40ecc12SChristoph Hellwig 
7005cbf67842SDouglas Gilbert 	if (qdepth < 1)
7006cbf67842SDouglas Gilbert 		qdepth = 1;
7007c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
7008c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
7009c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
7010db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
7011cbf67842SDouglas Gilbert 
7012773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
7013c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
7014c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
7015cbf67842SDouglas Gilbert 	}
7016c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
7017cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7018cbf67842SDouglas Gilbert }
7019cbf67842SDouglas Gilbert 
7020c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7021817fd66bSDouglas Gilbert {
7022c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7023773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7024773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7025773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7026c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7027773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7028817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7029c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7030817fd66bSDouglas Gilbert 	}
7031c4837394SDouglas Gilbert 	return false;
7032817fd66bSDouglas Gilbert }
7033817fd66bSDouglas Gilbert 
70347ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
70357ee6d1b4SBart Van Assche {
70367ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
70377ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
70387ee6d1b4SBart Van Assche }
70397ee6d1b4SBart Van Assche 
7040fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7041fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7042c2248fc9SDouglas Gilbert {
7043c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7044c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7045c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7046c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7047c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
704887c715dcSDouglas Gilbert 
7049c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7050c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7051f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7052c2248fc9SDouglas Gilbert 	int k, na;
7053c2248fc9SDouglas Gilbert 	int errsts = 0;
7054c2248fc9SDouglas Gilbert 	u32 flags;
7055c2248fc9SDouglas Gilbert 	u16 sa;
7056c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7057c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
7058c2248fc9SDouglas Gilbert 
7059c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
7060c4837394SDouglas Gilbert 	if (sdebug_statistics)
7061c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
7062f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7063f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7064c2248fc9SDouglas Gilbert 		char b[120];
7065c2248fc9SDouglas Gilbert 		int n, len, sb;
7066c2248fc9SDouglas Gilbert 
7067c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7068c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7069c2248fc9SDouglas Gilbert 		if (len > 32)
7070c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7071c2248fc9SDouglas Gilbert 		else {
7072c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7073c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7074c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7075c2248fc9SDouglas Gilbert 		}
7076458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7077458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
7078c2248fc9SDouglas Gilbert 	}
70797ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
70807ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
708134d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7082f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
7083f46eb0e9SDouglas Gilbert 		goto err_out;
7084c2248fc9SDouglas Gilbert 
7085c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7086c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7087c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7088f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7089f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7090c2248fc9SDouglas Gilbert 		if (NULL == devip)
7091f46eb0e9SDouglas Gilbert 			goto err_out;
7092c2248fc9SDouglas Gilbert 	}
7093c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7094c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7095c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7096c2248fc9SDouglas Gilbert 		r_oip = oip;
7097c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7098c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7099c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7100c2248fc9SDouglas Gilbert 			else
7101c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7102c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7103c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7104c2248fc9SDouglas Gilbert 					break;
7105c2248fc9SDouglas Gilbert 			}
7106c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7107c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7108c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7109c2248fc9SDouglas Gilbert 					break;
7110c2248fc9SDouglas Gilbert 			}
7111c2248fc9SDouglas Gilbert 		}
7112c2248fc9SDouglas Gilbert 		if (k > na) {
7113c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7114c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7115c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7116c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7117c2248fc9SDouglas Gilbert 			else
7118c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7119c2248fc9SDouglas Gilbert 			goto check_cond;
7120c2248fc9SDouglas Gilbert 		}
7121c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7122c2248fc9SDouglas Gilbert 	flags = oip->flags;
7123f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7124c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7125c2248fc9SDouglas Gilbert 		goto check_cond;
7126c2248fc9SDouglas Gilbert 	}
7127f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7128773642d9SDouglas Gilbert 		if (sdebug_verbose)
7129773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7130773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7131c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7132c2248fc9SDouglas Gilbert 		goto check_cond;
7133c2248fc9SDouglas Gilbert 	}
7134f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7135c2248fc9SDouglas Gilbert 		u8 rem;
7136c2248fc9SDouglas Gilbert 		int j;
7137c2248fc9SDouglas Gilbert 
7138c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7139c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7140c2248fc9SDouglas Gilbert 			if (rem) {
7141c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7142c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7143c2248fc9SDouglas Gilbert 						break;
7144c2248fc9SDouglas Gilbert 				}
7145c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7146c2248fc9SDouglas Gilbert 				goto check_cond;
7147c2248fc9SDouglas Gilbert 			}
7148c2248fc9SDouglas Gilbert 		}
7149c2248fc9SDouglas Gilbert 	}
7150f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7151b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7152b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7153f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7154c2248fc9SDouglas Gilbert 		if (errsts)
7155c2248fc9SDouglas Gilbert 			goto check_cond;
7156c2248fc9SDouglas Gilbert 	}
7157c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
7158c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7159773642d9SDouglas Gilbert 		if (sdebug_verbose)
7160c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
7161c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
7162c2248fc9SDouglas Gilbert 				    "required");
7163c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
7164c2248fc9SDouglas Gilbert 		goto fini;
7165c2248fc9SDouglas Gilbert 	}
7166773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7167c2248fc9SDouglas Gilbert 		goto fini;
7168f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7169c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7170c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7171c2248fc9SDouglas Gilbert 	}
7172f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7173f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7174f66b8517SMartin Wilck 	else
7175f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7176c2248fc9SDouglas Gilbert 
7177c2248fc9SDouglas Gilbert fini:
717867da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7179f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
718075aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
718175aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
718280c49563SDouglas Gilbert 		/*
718375aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
718475aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
718575aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
718675aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
718780c49563SDouglas Gilbert 		 */
718880c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
71894f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
719080c49563SDouglas Gilbert 
71914f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7192f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
719380c49563SDouglas Gilbert 	} else
7194f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
719510bde980SDouglas Gilbert 				     sdebug_ndelay);
7196c2248fc9SDouglas Gilbert check_cond:
7197f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7198f46eb0e9SDouglas Gilbert err_out:
7199f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7200c2248fc9SDouglas Gilbert }
7201c2248fc9SDouglas Gilbert 
72029e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7203c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7204c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
72059e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
72069e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
72079e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
72089e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
72099e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
72109e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
72119e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7212185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7213cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
72149e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
72159e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7216cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7217cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
72189e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7219c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
72209e603ca0SFUJITA Tomonori 	.this_id =		7,
722165e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7222cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
72236bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
722450c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
72259e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7226c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
72279e603ca0SFUJITA Tomonori };
72289e603ca0SFUJITA Tomonori 
72291da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
72301da177e4SLinus Torvalds {
72311da177e4SLinus Torvalds 	int error = 0;
72321da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
72331da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7234f46eb0e9SDouglas Gilbert 	int hprot;
72351da177e4SLinus Torvalds 
72361da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
72371da177e4SLinus Torvalds 
7238773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
72392a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
72404af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
72414af14d11SChristoph Hellwig 
72421da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
72431da177e4SLinus Torvalds 	if (NULL == hpnt) {
7244c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
72451da177e4SLinus Torvalds 		error = -ENODEV;
72461da177e4SLinus Torvalds 		return error;
72471da177e4SLinus Torvalds 	}
7248c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
72499b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7250c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7251c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7252c4837394SDouglas Gilbert 	}
7253c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
7254c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
7255c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
72561da177e4SLinus Torvalds 
72571da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
72581da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
7259773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7260773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
72611da177e4SLinus Torvalds 	else
7262773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7263773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7264f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
72651da177e4SLinus Torvalds 
7266f46eb0e9SDouglas Gilbert 	hprot = 0;
7267c6a44287SMartin K. Petersen 
7268773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7269c6a44287SMartin K. Petersen 
72708475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7271f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7272773642d9SDouglas Gilbert 		if (sdebug_dix)
7273f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7274c6a44287SMartin K. Petersen 		break;
7275c6a44287SMartin K. Petersen 
72768475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7277f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7278773642d9SDouglas Gilbert 		if (sdebug_dix)
7279f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7280c6a44287SMartin K. Petersen 		break;
7281c6a44287SMartin K. Petersen 
72828475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7283f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7284773642d9SDouglas Gilbert 		if (sdebug_dix)
7285f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7286c6a44287SMartin K. Petersen 		break;
7287c6a44287SMartin K. Petersen 
7288c6a44287SMartin K. Petersen 	default:
7289773642d9SDouglas Gilbert 		if (sdebug_dix)
7290f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7291c6a44287SMartin K. Petersen 		break;
7292c6a44287SMartin K. Petersen 	}
7293c6a44287SMartin K. Petersen 
7294f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7295c6a44287SMartin K. Petersen 
7296f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7297c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7298f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7299f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7300f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7301f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7302f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7303f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7304f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7305c6a44287SMartin K. Petersen 
7306773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7307c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7308c6a44287SMartin K. Petersen 	else
7309c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7310c6a44287SMartin K. Petersen 
7311773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7312773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7313c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7314c4837394SDouglas Gilbert 		sdebug_statistics = true;
73151da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
73161da177e4SLinus Torvalds 	if (error) {
7317c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
73181da177e4SLinus Torvalds 		error = -ENODEV;
73191da177e4SLinus Torvalds 		scsi_host_put(hpnt);
732087c715dcSDouglas Gilbert 	} else {
73211da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
732287c715dcSDouglas Gilbert 	}
73231da177e4SLinus Torvalds 
73241da177e4SLinus Torvalds 	return error;
73251da177e4SLinus Torvalds }
73261da177e4SLinus Torvalds 
73271da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
73281da177e4SLinus Torvalds {
73291da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
73308b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
73311da177e4SLinus Torvalds 
73321da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
73331da177e4SLinus Torvalds 
73341da177e4SLinus Torvalds 	if (!sdbg_host) {
7335c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
73361da177e4SLinus Torvalds 		return -ENODEV;
73371da177e4SLinus Torvalds 	}
73381da177e4SLinus Torvalds 
73391da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
73401da177e4SLinus Torvalds 
73418b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
73428b40228fSFUJITA Tomonori 				 dev_list) {
73431da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7344f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
73451da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
73461da177e4SLinus Torvalds 	}
73471da177e4SLinus Torvalds 
73481da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
73491da177e4SLinus Torvalds 	return 0;
73501da177e4SLinus Torvalds }
73511da177e4SLinus Torvalds 
73528dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
73538dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
73541da177e4SLinus Torvalds {
73558dea0d02SFUJITA Tomonori 	return 1;
73568dea0d02SFUJITA Tomonori }
73571da177e4SLinus Torvalds 
73588dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
73598dea0d02SFUJITA Tomonori 	.name = "pseudo",
73608dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
73618dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
73628dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
736382069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
73648dea0d02SFUJITA Tomonori };
7365