xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 23815df5)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
41da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
51da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
61da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
71da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
81da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
91da177e4SLinus Torvalds  *
10500d0d24SDouglas Gilbert  * Copyright (C) 2001 - 2021 Douglas Gilbert
111da177e4SLinus Torvalds  *
1230f67481SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
194a5fc1c6SDamien Le Moal #include <linux/align.h>
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/fs.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/proc_fs.h>
291da177e4SLinus Torvalds #include <linux/vmalloc.h>
301da177e4SLinus Torvalds #include <linux/moduleparam.h>
31852e034dSJens Axboe #include <linux/scatterlist.h>
321da177e4SLinus Torvalds #include <linux/blkdev.h>
33c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
34cbf67842SDouglas Gilbert #include <linux/spinlock.h>
35cbf67842SDouglas Gilbert #include <linux/interrupt.h>
36cbf67842SDouglas Gilbert #include <linux/atomic.h>
37cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3809ba24c1SDouglas Gilbert #include <linux/uuid.h>
396ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
401442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
410c4bc91dSDouglas Gilbert #include <linux/random.h>
4287c715dcSDouglas Gilbert #include <linux/xarray.h>
43ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
44c6a44287SMartin K. Petersen 
45c6a44287SMartin K. Petersen #include <net/checksum.h>
469ff26eefSFUJITA Tomonori 
4744d92694SMartin K. Petersen #include <asm/unaligned.h>
4844d92694SMartin K. Petersen 
499ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
521da177e4SLinus Torvalds #include <scsi/scsi_host.h>
531da177e4SLinus Torvalds #include <scsi/scsicam.h>
54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
62500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191"	/* format to fit INQUIRY revision field */
63500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520";
64cbf67842SDouglas Gilbert 
65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
661da177e4SLinus Torvalds 
676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
779447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
85500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4
98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5
99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6
100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7
1014a5fc1c6SDamien Le Moal #define ATTEMPT_ACCESS_GAP 0x9
102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe
1031da177e4SLinus Torvalds 
1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1066f3cbf55SDouglas Gilbert 
1071da177e4SLinus Torvalds /* Default values for driver parameters */
1081da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1091da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1101da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1121da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1131da177e4SLinus Torvalds  */
1145b94e232SMartin K. Petersen #define DEF_ATO 1
1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
116c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT   0
1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB   128
1205b94e232SMartin K. Petersen #define DEF_DIF 0
1215b94e232SMartin K. Petersen #define DEF_DIX 0
12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1235b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1241da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1255b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1265b94e232SMartin K. Petersen #define DEF_GUARD 0
127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1285b94e232SMartin K. Petersen #define DEF_LBPU 0
1295b94e232SMartin K. Petersen #define DEF_LBPWS 0
1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0
131be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
133cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1351da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1361da177e4SLinus Torvalds #define DEF_OPTS   0
13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
140b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false
142d986788bSMartin Pitt #define DEF_REMOVABLE false
143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
152c2248fc9SDouglas Gilbert #define DEF_STRICT 0
153c4837394SDouglas Gilbert #define DEF_STATISTICS false
154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0
15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1581da177e4SLinus Torvalds 
159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */
160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB	128
161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES	8
162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES	1
163f0d1cf93SDouglas Gilbert 
164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
165b01f6f83SDouglas Gilbert 
166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
1777d5a129bSDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400	/* ignore */
178773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
179773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
180773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
181773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1827ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1837382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
185773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
186773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
187773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
188773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1897ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1907382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1917382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1923a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1933a90a63dSDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1941da177e4SLinus Torvalds 
195cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
196cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
197cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
198cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
200500d0d24SDouglas Gilbert #define SDEBUG_UA_POOCCUR 1	/* Power on occurred */
201500d0d24SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 2
202500d0d24SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 3
203500d0d24SDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 4
204500d0d24SDouglas Gilbert #define SDEBUG_UA_LUNS_CHANGED 5
205500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED 6	/* simulate firmware change */
206500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7
207500d0d24SDouglas Gilbert #define SDEBUG_NUM_UAS 8
208cbf67842SDouglas Gilbert 
209773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2101da177e4SLinus Torvalds  * sector on read commands: */
2111da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2131da177e4SLinus Torvalds 
214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
216c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
220c4837394SDouglas Gilbert  */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
223fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN  SDEBUG_CANQUEUE
224cbf67842SDouglas Gilbert 
225b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
226b6ff8ca7SDouglas Gilbert #define F_D_IN			1	/* Data-in command (e.g. READ) */
227b6ff8ca7SDouglas Gilbert #define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
228fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
229fd32119bSDouglas Gilbert #define F_D_UNKN		8
230b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
231b6ff8ca7SDouglas Gilbert #define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
232b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
233b6ff8ca7SDouglas Gilbert #define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
234b6ff8ca7SDouglas Gilbert #define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
235b6ff8ca7SDouglas Gilbert #define F_INV_OP		0x200	/* invalid opcode (not supported) */
236b6ff8ca7SDouglas Gilbert #define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
237b6ff8ca7SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
238b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
239b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
240fd32119bSDouglas Gilbert 
241b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */
242fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24346f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
244fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2454f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
246fd32119bSDouglas Gilbert 
247fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
248fd32119bSDouglas Gilbert 
249b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
250fd32119bSDouglas Gilbert 
25187c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1
25287c715dcSDouglas Gilbert 
2531107c7b2SJohn Garry static struct kmem_cache *queued_cmd_cache;
2541107c7b2SJohn Garry 
2551107c7b2SJohn Garry #define TO_QUEUED_CMD(scmd)  ((void *)(scmd)->host_scribble)
2561107c7b2SJohn Garry #define ASSIGN_QUEUED_CMD(scmnd, qc) { (scmnd)->host_scribble = (void *) qc; }
2571107c7b2SJohn Garry 
25864e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */
25964e14eceSDamien Le Moal enum sdebug_z_type {
26035dbe2b9SDamien Le Moal 	ZBC_ZTYPE_CNV	= 0x1,
26135dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWR	= 0x2,
26235dbe2b9SDamien Le Moal 	ZBC_ZTYPE_SWP	= 0x3,
2634a5fc1c6SDamien Le Moal 	/* ZBC_ZTYPE_SOBR = 0x4, */
2644a5fc1c6SDamien Le Moal 	ZBC_ZTYPE_GAP	= 0x5,
26564e14eceSDamien Le Moal };
26664e14eceSDamien Le Moal 
267f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */
268f0d1cf93SDouglas Gilbert enum sdebug_z_cond {
269f0d1cf93SDouglas Gilbert 	ZBC_NOT_WRITE_POINTER	= 0x0,
270f0d1cf93SDouglas Gilbert 	ZC1_EMPTY		= 0x1,
271f0d1cf93SDouglas Gilbert 	ZC2_IMPLICIT_OPEN	= 0x2,
272f0d1cf93SDouglas Gilbert 	ZC3_EXPLICIT_OPEN	= 0x3,
273f0d1cf93SDouglas Gilbert 	ZC4_CLOSED		= 0x4,
274f0d1cf93SDouglas Gilbert 	ZC6_READ_ONLY		= 0xd,
275f0d1cf93SDouglas Gilbert 	ZC5_FULL		= 0xe,
276f0d1cf93SDouglas Gilbert 	ZC7_OFFLINE		= 0xf,
277f0d1cf93SDouglas Gilbert };
278f0d1cf93SDouglas Gilbert 
279f0d1cf93SDouglas Gilbert struct sdeb_zone_state {	/* ZBC: per zone state */
28064e14eceSDamien Le Moal 	enum sdebug_z_type z_type;
281f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond z_cond;
28264e14eceSDamien Le Moal 	bool z_non_seq_resource;
283f0d1cf93SDouglas Gilbert 	unsigned int z_size;
284f0d1cf93SDouglas Gilbert 	sector_t z_start;
285f0d1cf93SDouglas Gilbert 	sector_t z_wp;
286f0d1cf93SDouglas Gilbert };
287fd32119bSDouglas Gilbert 
288fd32119bSDouglas Gilbert struct sdebug_dev_info {
289fd32119bSDouglas Gilbert 	struct list_head dev_list;
290fd32119bSDouglas Gilbert 	unsigned int channel;
291fd32119bSDouglas Gilbert 	unsigned int target;
292fd32119bSDouglas Gilbert 	u64 lun;
293bf476433SChristoph Hellwig 	uuid_t lu_name;
294fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
295fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
296fc13638aSDouglas Gilbert 	atomic_t stopped;	/* 1: by SSU, 2: device start */
297fd32119bSDouglas Gilbert 	bool used;
298f0d1cf93SDouglas Gilbert 
299f0d1cf93SDouglas Gilbert 	/* For ZBC devices */
30064e14eceSDamien Le Moal 	enum blk_zoned_model zmodel;
3014a5fc1c6SDamien Le Moal 	unsigned int zcap;
302f0d1cf93SDouglas Gilbert 	unsigned int zsize;
303f0d1cf93SDouglas Gilbert 	unsigned int zsize_shift;
304f0d1cf93SDouglas Gilbert 	unsigned int nr_zones;
305aa8fecf9SDamien Le Moal 	unsigned int nr_conv_zones;
3064a5fc1c6SDamien Le Moal 	unsigned int nr_seq_zones;
307f0d1cf93SDouglas Gilbert 	unsigned int nr_imp_open;
308f0d1cf93SDouglas Gilbert 	unsigned int nr_exp_open;
309f0d1cf93SDouglas Gilbert 	unsigned int nr_closed;
310f0d1cf93SDouglas Gilbert 	unsigned int max_open;
311fc13638aSDouglas Gilbert 	ktime_t create_ts;	/* time since bootup that this device was created */
312f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zstate;
313fd32119bSDouglas Gilbert };
314fd32119bSDouglas Gilbert 
315fd32119bSDouglas Gilbert struct sdebug_host_info {
316fd32119bSDouglas Gilbert 	struct list_head host_list;
31787c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
318fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
319fd32119bSDouglas Gilbert 	struct device dev;
320fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
321fd32119bSDouglas Gilbert };
322fd32119bSDouglas Gilbert 
32387c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
32487c715dcSDouglas Gilbert struct sdeb_store_info {
32587c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
32687c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
32787c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
32887c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
32987c715dcSDouglas Gilbert };
33087c715dcSDouglas Gilbert 
331785d6b7cSJohn Garry #define dev_to_sdebug_host(d)	\
332fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
333fd32119bSDouglas Gilbert 
334785d6b7cSJohn Garry #define shost_to_sdebug_host(shost)	\
335785d6b7cSJohn Garry 	dev_to_sdebug_host(shost->dma_dev)
336785d6b7cSJohn Garry 
33710bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3384a0c6f43SDouglas Gilbert 		      SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
33910bde980SDouglas Gilbert 
340fd32119bSDouglas Gilbert struct sdebug_defer {
341fd32119bSDouglas Gilbert 	struct hrtimer hrt;
342fd32119bSDouglas Gilbert 	struct execute_work ew;
3434a0c6f43SDouglas Gilbert 	ktime_t cmpl_ts;/* time since boot to complete this cmd */
344c4837394SDouglas Gilbert 	int issuing_cpu;
3457382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
34610bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
347fd32119bSDouglas Gilbert };
348fd32119bSDouglas Gilbert 
349fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
350c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
351c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
352c4837394SDouglas Gilbert 	 */
3531107c7b2SJohn Garry 	struct sdebug_defer sd_dp;
3541107c7b2SJohn Garry 	struct scsi_cmnd *scmd;
355fd32119bSDouglas Gilbert };
356fd32119bSDouglas Gilbert 
3571107c7b2SJohn Garry struct sdebug_scsi_cmd {
3581107c7b2SJohn Garry 	spinlock_t   lock;
359fd32119bSDouglas Gilbert };
360fd32119bSDouglas Gilbert 
361c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
362c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
363c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
364c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3653a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending;
3664a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count;  /* bumped when mq_poll returns > 0 */
367c4837394SDouglas Gilbert 
368fd32119bSDouglas Gilbert struct opcode_info_t {
369b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
370b01f6f83SDouglas Gilbert 				/* for terminating element */
371fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
372fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
373fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
374fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
375fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3769a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3779a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
378fd32119bSDouglas Gilbert };
379fd32119bSDouglas Gilbert 
380fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
381c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
382c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
383c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
384c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
385c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
386c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
387c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
388c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
389c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
390c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
391c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
392c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
393c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
39446f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
39546f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
396c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
397c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
398c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
399481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
400c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
401c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
402c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
403c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
404c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
405c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
406c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
407c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
408c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
409c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
410c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
411ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
412f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
413f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
414f0d1cf93SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
415c2248fc9SDouglas Gilbert };
416c2248fc9SDouglas Gilbert 
417c4837394SDouglas Gilbert 
418c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
419c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
420c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
421c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
422c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
423c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
424c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
425c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
426c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
427c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
428c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
429c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
430ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
431c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
432c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
433c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
434c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
435c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
436c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
437c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
438fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
439c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
440c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
441c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
442c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
443c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
444c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
445c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
446f0d1cf93SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
447f0d1cf93SDouglas Gilbert 	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
44846f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
449c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
450c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
451c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
45246f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
45346f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
454c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
455c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
456c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
457c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
458c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
459c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
460c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
461c2248fc9SDouglas Gilbert };
462c2248fc9SDouglas Gilbert 
46380c49563SDouglas Gilbert /*
46480c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
46580c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
46680c49563SDouglas Gilbert  * command completion, they can mask their return value with
46780c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
46880c49563SDouglas Gilbert  */
46980c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
47080c49563SDouglas Gilbert 
471c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
472c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
473c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
474c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
475c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
476c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
477c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
478c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
479c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
480481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
481c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
482c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
483c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
484c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
485c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
48638d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
48738d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
488c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
489c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
490c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
49138d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
492acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
49380c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
494ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
495f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
496f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
497f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
498f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
499f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
500c2248fc9SDouglas Gilbert 
50187c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
50287c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
50387c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
50487c715dcSDouglas Gilbert static int sdebug_add_store(void);
50587c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
50687c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
50787c715dcSDouglas Gilbert 
5081107c7b2SJohn Garry static void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp);
5091107c7b2SJohn Garry 
51046f64e70SDouglas Gilbert /*
51146f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
51246f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
51346f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
51446f64e70SDouglas Gilbert  */
51546f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
516c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
517c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
518c2248fc9SDouglas Gilbert };
519c2248fc9SDouglas Gilbert 
52046f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
521c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
522c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
523c2248fc9SDouglas Gilbert };
524c2248fc9SDouglas Gilbert 
52546f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
52646f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
527b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
528c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
52946f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
530c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53146f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
532b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
533c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
534c2248fc9SDouglas Gilbert };
535c2248fc9SDouglas Gilbert 
53646f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
53746f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
53846f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
53946f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
54046f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
54146f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
54246f64e70SDouglas Gilbert 		   0, 0, 0} },
54346f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
54446f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54546f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
546c2248fc9SDouglas Gilbert };
547c2248fc9SDouglas Gilbert 
548c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
549c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
550c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
551c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
552c3e2fe92SDouglas Gilbert };
553c3e2fe92SDouglas Gilbert 
55446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
555c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
556c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55746f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
558c2248fc9SDouglas Gilbert };
559c2248fc9SDouglas Gilbert 
56046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
56146f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
562b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
563c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
564481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
565481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
566481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
567c2248fc9SDouglas Gilbert };
568c2248fc9SDouglas Gilbert 
56946f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
57038d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
571c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
57246f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
57338d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
574c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
57546f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
576c2248fc9SDouglas Gilbert };
577c2248fc9SDouglas Gilbert 
57846f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
57946f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
580c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58146f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
582c2248fc9SDouglas Gilbert };
583c2248fc9SDouglas Gilbert 
58446f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
585c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
586c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
587c2248fc9SDouglas Gilbert };
588c2248fc9SDouglas Gilbert 
58946f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
590c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
591c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
592c2248fc9SDouglas Gilbert };
593c2248fc9SDouglas Gilbert 
59480c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5954f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
59680c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59780c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
59880c49563SDouglas Gilbert };
59980c49563SDouglas Gilbert 
600ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
601b6ff8ca7SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
602ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
604ed9f3e25SDouglas Gilbert };
605ed9f3e25SDouglas Gilbert 
606f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
607b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
608f0d1cf93SDouglas Gilbert 	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
609f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
610b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
611f0d1cf93SDouglas Gilbert 	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
613b6ff8ca7SDouglas Gilbert 	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
614f0d1cf93SDouglas Gilbert 	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
615f0d1cf93SDouglas Gilbert 	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
616f0d1cf93SDouglas Gilbert };
617f0d1cf93SDouglas Gilbert 
618f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
619b6ff8ca7SDouglas Gilbert 	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
620f0d1cf93SDouglas Gilbert 	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
621f0d1cf93SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
622f0d1cf93SDouglas Gilbert };
623f0d1cf93SDouglas Gilbert 
624c2248fc9SDouglas Gilbert 
625c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
626c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
627c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
628ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
629c2248fc9SDouglas Gilbert /* 0 */
63046f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
631c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63246f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
633c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
634c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
635c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
63646f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
637c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
638c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
639c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
640c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
64146f64e70SDouglas Gilbert /* 5 */
64246f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
64346f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
64446f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64546f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
64646f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
64746f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
64846f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
649c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
650c2248fc9SDouglas Gilbert 	     0, 0, 0} },
65146f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
652c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
653c2248fc9SDouglas Gilbert 	     0, 0} },
65446f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
65546f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
65646f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
657c2248fc9SDouglas Gilbert /* 10 */
65846f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
65946f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
66046f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66180c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6624f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
663c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
66446f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
66546f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
66646f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66746f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
668481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
669481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
670481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
67146f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
67246f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
67346f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
67446f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
67546f64e70SDouglas Gilbert /* 15 */
676c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
677c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
678c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
679c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
680c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
681c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
68246f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
68346f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
68446f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
68546f64e70SDouglas Gilbert 	     0xff, 0xff} },
68646f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
68746f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
688c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
689c2248fc9SDouglas Gilbert 	     0} },
69046f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
69146f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
692c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
693c2248fc9SDouglas Gilbert 	     0} },
694c2248fc9SDouglas Gilbert /* 20 */
695f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
696f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
697c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
698c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
699c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
700c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
701c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
702c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
70346f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
704b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
70546f64e70SDouglas Gilbert /* 25 */
706acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
707acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
708acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
70946f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
71046f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
71146f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
71246f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
7134f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
71480c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
715b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
71680c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
71746f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
718c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
719b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
720b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
721ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
722ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
723ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
724c2248fc9SDouglas Gilbert 
725ed9f3e25SDouglas Gilbert /* 30 */
726b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
727f0d1cf93SDouglas Gilbert 	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
728f0d1cf93SDouglas Gilbert 		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
729f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
730b6ff8ca7SDouglas Gilbert 	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
731f0d1cf93SDouglas Gilbert 	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
732f0d1cf93SDouglas Gilbert 		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
733f0d1cf93SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
734f0d1cf93SDouglas Gilbert /* sentinel */
735c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
736c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
737c2248fc9SDouglas Gilbert };
738c2248fc9SDouglas Gilbert 
739f19fe8f3SBart Van Assche static int sdebug_num_hosts;
74087c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
741773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
7429b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
743c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7449267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
745773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
746773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
747773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
748773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
749773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
750773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
751c10fa55fSJohn Garry static int sdebug_host_max_queue;	/* per host */
752773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
753773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
754c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
755d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
756d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
757c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
758773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
759773642d9SDouglas Gilbert static int sdebug_no_uld;
760773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
761773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
762773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
763773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
764773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
76586e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
766b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
767773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
768773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
769fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
770773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
771773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
772773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
773773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
774773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
775773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
776773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
778773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
779773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
780773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
78109ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7820c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
78387c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
784773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
785773642d9SDouglas Gilbert static bool sdebug_clustering;
786773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
787773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
788817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
7897109f370SDouglas Gilbert static bool sdebug_no_rwlock;
790773642d9SDouglas Gilbert static bool sdebug_verbose;
791f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7924f2c8bf6SDouglas Gilbert static bool write_since_sync;
793c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7949447b6ceSMartin K. Petersen static bool sdebug_wp;
7959267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7969267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7979267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s;
7981da177e4SLinus Torvalds 
799ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
800ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_FLAT = 0x1,
801ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
802ad0c7775SDouglas Gilbert 			  SAM_LUN_AM_EXTENDED = 0x3};
803ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
804ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
805ad0c7775SDouglas Gilbert 
806c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
8071da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
8101da177e4SLinus Torvalds    may still need them */
8111da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
8121da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
8131da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
8160aaa3fadSJohn Garry static DEFINE_MUTEX(sdebug_host_list_mutex);
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 */
8364a5fc1c6SDamien Le Moal static int sdeb_zbc_zone_cap_mb;
83798e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb;
838380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
839aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
840f0d1cf93SDouglas Gilbert 
841c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
842c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/
843fd32119bSDouglas Gilbert 
844cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
845cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
8501da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
8511da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
8521da177e4SLinus Torvalds };
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds static const int check_condition_result =
855464a00c9SHannes Reinecke 	SAM_STAT_CHECK_CONDITION;
8561da177e4SLinus Torvalds 
857c6a44287SMartin K. Petersen static const int illegal_condition_result =
858464a00c9SHannes Reinecke 	(DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
859c6a44287SMartin K. Petersen 
860cbf67842SDouglas Gilbert static const int device_qfull_result =
8617d5a129bSDouglas Gilbert 	(DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
862cbf67842SDouglas Gilbert 
863ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
864ed9f3e25SDouglas Gilbert 
865fd32119bSDouglas Gilbert 
866760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
867760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
868760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
869760f3b03SDouglas Gilbert  */
scsi_debug_lbp(void)870760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
871fd32119bSDouglas Gilbert {
872fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
873fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
874fd32119bSDouglas Gilbert }
875c65b1445SDouglas Gilbert 
lba2fake_store(struct sdeb_store_info * sip,unsigned long long lba)87687c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
87787c715dcSDouglas Gilbert 			    unsigned long long lba)
87814faa944SAkinobu Mita {
87987c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
88014faa944SAkinobu Mita 
88187c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
88287c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
88387c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
88487c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
88587c715dcSDouglas Gilbert 	}
88687c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
88714faa944SAkinobu Mita }
88814faa944SAkinobu Mita 
dif_store(struct sdeb_store_info * sip,sector_t sector)88987c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
89087c715dcSDouglas Gilbert 				      sector_t sector)
89114faa944SAkinobu Mita {
89249413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
89314faa944SAkinobu Mita 
89487c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
89514faa944SAkinobu Mita }
89614faa944SAkinobu Mita 
sdebug_max_tgts_luns(void)8978dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8988dea0d02SFUJITA Tomonori {
8998dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
9008dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
9018dea0d02SFUJITA Tomonori 
9020aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
9038dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9048dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
9058dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
906773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
907773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
9088dea0d02SFUJITA Tomonori 		else
909773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
910773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
911f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9128dea0d02SFUJITA Tomonori 	}
9130aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
9148dea0d02SFUJITA Tomonori }
9158dea0d02SFUJITA Tomonori 
91622017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
91722017ed2SDouglas Gilbert 
91822017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
mk_sense_invalid_fld(struct scsi_cmnd * scp,enum sdeb_cmd_data c_d,int in_byte,int in_bit)919fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
920fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
92122017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
92222017ed2SDouglas Gilbert {
92322017ed2SDouglas Gilbert 	unsigned char *sbuff;
92422017ed2SDouglas Gilbert 	u8 sks[4];
92522017ed2SDouglas Gilbert 	int sl, asc;
92622017ed2SDouglas Gilbert 
92722017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
92822017ed2SDouglas Gilbert 	if (!sbuff) {
92922017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
93022017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
93122017ed2SDouglas Gilbert 		return;
93222017ed2SDouglas Gilbert 	}
93322017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
93422017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
935f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0);
93622017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
93722017ed2SDouglas Gilbert 	sks[0] = 0x80;
93822017ed2SDouglas Gilbert 	if (c_d)
93922017ed2SDouglas Gilbert 		sks[0] |= 0x40;
94022017ed2SDouglas Gilbert 	if (in_bit >= 0) {
94122017ed2SDouglas Gilbert 		sks[0] |= 0x8;
94222017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
94322017ed2SDouglas Gilbert 	}
94422017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
945773642d9SDouglas Gilbert 	if (sdebug_dsense) {
94622017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
94722017ed2SDouglas Gilbert 		sbuff[7] = sl;
94822017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
94922017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
95022017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
95122017ed2SDouglas Gilbert 	} else
95222017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
953773642d9SDouglas Gilbert 	if (sdebug_verbose)
95422017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
95522017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
95622017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
95722017ed2SDouglas Gilbert }
95822017ed2SDouglas Gilbert 
mk_sense_buffer(struct scsi_cmnd * scp,int key,int asc,int asq)959cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9608dea0d02SFUJITA Tomonori {
961f2b1e9c6SHannes Reinecke 	if (!scp->sense_buffer) {
962cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
963cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
964cbf67842SDouglas Gilbert 		return;
965cbf67842SDouglas Gilbert 	}
966f2b1e9c6SHannes Reinecke 	memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
9678dea0d02SFUJITA Tomonori 
968f2b1e9c6SHannes Reinecke 	scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
9698dea0d02SFUJITA Tomonori 
970773642d9SDouglas Gilbert 	if (sdebug_verbose)
971cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
972cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
973cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
9748dea0d02SFUJITA Tomonori }
9751da177e4SLinus Torvalds 
mk_sense_invalid_opcode(struct scsi_cmnd * scp)976fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
97722017ed2SDouglas Gilbert {
97822017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
97922017ed2SDouglas Gilbert }
98022017ed2SDouglas Gilbert 
scsi_debug_ioctl(struct scsi_device * dev,unsigned int cmd,void __user * arg)9816f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9826f4e626fSNathan Chancellor 			    void __user *arg)
9831da177e4SLinus Torvalds {
984773642d9SDouglas Gilbert 	if (sdebug_verbose) {
985cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
986cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
987cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
988cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
989cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
990cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
991cbf67842SDouglas Gilbert 				    __func__);
992cbf67842SDouglas Gilbert 		else
993cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
994cbf67842SDouglas Gilbert 				    __func__, cmd);
9951da177e4SLinus Torvalds 	}
9961da177e4SLinus Torvalds 	return -EINVAL;
9971da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds 
config_cdb_len(struct scsi_device * sdev)10009b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
10019b760fd8SDouglas Gilbert {
10029b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
10039b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10049b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10059b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10069b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10079b760fd8SDouglas Gilbert 		break;
10089b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10099b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10109b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10119b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10129b760fd8SDouglas Gilbert 		break;
10139b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10149b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10159b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10169b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10179b760fd8SDouglas Gilbert 		break;
10189b760fd8SDouglas Gilbert 	case 16:
10199b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10209b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10219b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10229b760fd8SDouglas Gilbert 		break;
10239b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
10249b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
10259b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
10269b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
10279b760fd8SDouglas Gilbert 		break;
10289b760fd8SDouglas Gilbert 	default:
10299b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
10309b760fd8SDouglas Gilbert 			sdebug_cdb_len);
10319b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
10329b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
10339b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
10349b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
10359b760fd8SDouglas Gilbert 		break;
10369b760fd8SDouglas Gilbert 	}
10379b760fd8SDouglas Gilbert }
10389b760fd8SDouglas Gilbert 
all_config_cdb_len(void)10399b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
10409b760fd8SDouglas Gilbert {
10419b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
10429b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
10439b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
10449b760fd8SDouglas Gilbert 
10450aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
10469b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10479b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
10489b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
10499b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
10509b760fd8SDouglas Gilbert 		}
10519b760fd8SDouglas Gilbert 	}
10520aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
10539b760fd8SDouglas Gilbert }
10549b760fd8SDouglas Gilbert 
clear_luns_changed_on_target(struct sdebug_dev_info * devip)105519c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
105619c8ead7SEwan D. Milne {
105700f9d622SJohn Garry 	struct sdebug_host_info *sdhp = devip->sdbg_host;
105819c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
105919c8ead7SEwan D. Milne 
106019c8ead7SEwan D. Milne 	list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
106119c8ead7SEwan D. Milne 		if ((devip->sdbg_host == dp->sdbg_host) &&
106200f9d622SJohn Garry 		    (devip->target == dp->target)) {
106319c8ead7SEwan D. Milne 			clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
106419c8ead7SEwan D. Milne 		}
106519c8ead7SEwan D. Milne 	}
106619c8ead7SEwan D. Milne }
106719c8ead7SEwan D. Milne 
make_ua(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)1068f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10691da177e4SLinus Torvalds {
1070cbf67842SDouglas Gilbert 	int k;
1071cbf67842SDouglas Gilbert 
1072cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1073cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
1074cbf67842SDouglas Gilbert 		const char *cp = NULL;
1075cbf67842SDouglas Gilbert 
1076cbf67842SDouglas Gilbert 		switch (k) {
1077cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
1078f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1079f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
1080773642d9SDouglas Gilbert 			if (sdebug_verbose)
1081cbf67842SDouglas Gilbert 				cp = "power on reset";
1082cbf67842SDouglas Gilbert 			break;
1083500d0d24SDouglas Gilbert 		case SDEBUG_UA_POOCCUR:
1084500d0d24SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1085500d0d24SDouglas Gilbert 					POWER_ON_OCCURRED_ASCQ);
1086500d0d24SDouglas Gilbert 			if (sdebug_verbose)
1087500d0d24SDouglas Gilbert 				cp = "power on occurred";
1088500d0d24SDouglas Gilbert 			break;
1089cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
1090f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1091f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1092773642d9SDouglas Gilbert 			if (sdebug_verbose)
1093cbf67842SDouglas Gilbert 				cp = "bus reset";
1094cbf67842SDouglas Gilbert 			break;
1095cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1096f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1097f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1098773642d9SDouglas Gilbert 			if (sdebug_verbose)
1099cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1100cbf67842SDouglas Gilbert 			break;
11010d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1102f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1103f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1104773642d9SDouglas Gilbert 			if (sdebug_verbose)
11050d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1106f49accf1SEwan D. Milne 			break;
1107acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1108f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1109b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1110b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1111773642d9SDouglas Gilbert 			if (sdebug_verbose)
1112acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1113acafd0b9SEwan D. Milne 			break;
1114acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1115f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1116acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1117acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1118773642d9SDouglas Gilbert 			if (sdebug_verbose)
1119acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1120acafd0b9SEwan D. Milne 			break;
112119c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
112219c8ead7SEwan D. Milne 			/*
112319c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
112419c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
112519c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
112619c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1127773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
112819c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
112919c8ead7SEwan D. Milne 			 */
1130773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
113119c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1132f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
113319c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
113419c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1135773642d9SDouglas Gilbert 			if (sdebug_verbose)
113619c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
113719c8ead7SEwan D. Milne 			break;
1138cbf67842SDouglas Gilbert 		default:
1139773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1140773642d9SDouglas Gilbert 			if (sdebug_verbose)
1141cbf67842SDouglas Gilbert 				cp = "unknown";
1142cbf67842SDouglas Gilbert 			break;
1143cbf67842SDouglas Gilbert 		}
1144cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1145773642d9SDouglas Gilbert 		if (sdebug_verbose)
1146f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1147cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1148cbf67842SDouglas Gilbert 				   my_name, cp);
11491da177e4SLinus Torvalds 		return check_condition_result;
11501da177e4SLinus Torvalds 	}
11511da177e4SLinus Torvalds 	return 0;
11521da177e4SLinus Torvalds }
11531da177e4SLinus Torvalds 
1154fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
fill_from_dev_buffer(struct scsi_cmnd * scp,unsigned char * arr,int arr_len)11551da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11561da177e4SLinus Torvalds 				int arr_len)
11571da177e4SLinus Torvalds {
115821a61829SFUJITA Tomonori 	int act_len;
1159ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
11601da177e4SLinus Torvalds 
1161072d0bb3SFUJITA Tomonori 	if (!sdb->length)
11621da177e4SLinus Torvalds 		return 0;
1163ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1164773642d9SDouglas Gilbert 		return DID_ERROR << 16;
116521a61829SFUJITA Tomonori 
116621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
116721a61829SFUJITA Tomonori 				      arr, arr_len);
116842d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
116921a61829SFUJITA Tomonori 
11701da177e4SLinus Torvalds 	return 0;
11711da177e4SLinus Torvalds }
11721da177e4SLinus Torvalds 
1173fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1174fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1175fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1176fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1177fb0cc8d1SDouglas Gilbert  */
p_fill_from_dev_buffer(struct scsi_cmnd * scp,const void * arr,int arr_len,unsigned int off_dst)1178fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1179fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1180fb0cc8d1SDouglas Gilbert {
11819237f04eSDamien Le Moal 	unsigned int act_len, n;
1182ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1183fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1184fb0cc8d1SDouglas Gilbert 
1185fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1186fb0cc8d1SDouglas Gilbert 		return 0;
1187ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1188fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1189fb0cc8d1SDouglas Gilbert 
1190fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1191fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1192fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
119342d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
119442d387beSBart Van Assche 		 scsi_get_resid(scp));
11959237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
119636e07d7eSGeorge Kennedy 	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
1197fb0cc8d1SDouglas Gilbert 	return 0;
1198fb0cc8d1SDouglas Gilbert }
1199fb0cc8d1SDouglas Gilbert 
1200fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1201fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1202fb0cc8d1SDouglas Gilbert  */
fetch_to_dev_buffer(struct scsi_cmnd * scp,unsigned char * arr,int arr_len)12031da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
120421a61829SFUJITA Tomonori 			       int arr_len)
12051da177e4SLinus Torvalds {
120621a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
12071da177e4SLinus Torvalds 		return 0;
1208ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
12091da177e4SLinus Torvalds 		return -1;
121021a61829SFUJITA Tomonori 
121121a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds 
1215e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1216e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
12179b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12181b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
12191b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
12201b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
12211b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
12221da177e4SLinus Torvalds 
1223cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
inquiry_vpd_83(unsigned char * arr,int port_group_id,int target_dev_id,int dev_id_num,const char * dev_id_str,int dev_id_str_len,const uuid_t * lu_name)1224760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12255a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
122609ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1227bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
12281da177e4SLinus Torvalds {
1229c65b1445SDouglas Gilbert 	int num, port_a;
1230c65b1445SDouglas Gilbert 	char b[32];
12311da177e4SLinus Torvalds 
1232c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
12331da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
12341da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
12351da177e4SLinus Torvalds 	arr[1] = 0x1;
12361da177e4SLinus Torvalds 	arr[2] = 0x0;
1237e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1238e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
12391da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12401da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
12411da177e4SLinus Torvalds 	arr[3] = num;
12421da177e4SLinus Torvalds 	num += 4;
1243c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
124409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
124509ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
124609ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
124709ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
124809ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
124909ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
125009ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
125109ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
125209ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
125309ba24c1SDouglas Gilbert 			num += 16;
125409ba24c1SDouglas Gilbert 		} else {
12551b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1256c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1257c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1258c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1259c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
12601b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1261773642d9SDouglas Gilbert 			num += 8;
126209ba24c1SDouglas Gilbert 		}
1263c65b1445SDouglas Gilbert 		/* Target relative port number */
1264c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1265c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1266c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1267c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1268c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1269c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1270c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1271c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1272c65b1445SDouglas Gilbert 	}
12731b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1274c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1275c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1276c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1277c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12781b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1279773642d9SDouglas Gilbert 	num += 8;
12801b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
12815a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
12825a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
12835a09e398SHannes Reinecke 	arr[num++] = 0x0;
12845a09e398SHannes Reinecke 	arr[num++] = 0x4;
12855a09e398SHannes Reinecke 	arr[num++] = 0;
12865a09e398SHannes Reinecke 	arr[num++] = 0;
1287773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1288773642d9SDouglas Gilbert 	num += 2;
12891b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1290c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1291c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1292c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1293c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12941b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1295773642d9SDouglas Gilbert 	num += 8;
1296c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1297c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1298c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1299c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1300c65b1445SDouglas Gilbert 	arr[num++] = 24;
13011b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1302c65b1445SDouglas Gilbert 	num += 12;
1303c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1304c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1305c65b1445SDouglas Gilbert 	num += 8;
1306c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1307c65b1445SDouglas Gilbert 	num += 4;
1308c65b1445SDouglas Gilbert 	return num;
1309c65b1445SDouglas Gilbert }
1310c65b1445SDouglas Gilbert 
1311c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1312c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1313c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1314c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1315c65b1445SDouglas Gilbert };
1316c65b1445SDouglas Gilbert 
1317cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
inquiry_vpd_84(unsigned char * arr)1318760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1319c65b1445SDouglas Gilbert {
1320c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1321c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1322c65b1445SDouglas Gilbert }
1323c65b1445SDouglas Gilbert 
1324cbf67842SDouglas Gilbert /* Management network addresses VPD page */
inquiry_vpd_85(unsigned char * arr)1325760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1326c65b1445SDouglas Gilbert {
1327c65b1445SDouglas Gilbert 	int num = 0;
1328c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1329c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1330c65b1445SDouglas Gilbert 	int plen, olen;
1331c65b1445SDouglas Gilbert 
1332c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1333c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1334c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1335c65b1445SDouglas Gilbert 	olen = strlen(na1);
1336c65b1445SDouglas Gilbert 	plen = olen + 1;
1337c65b1445SDouglas Gilbert 	if (plen % 4)
1338c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1339c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1340c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1341c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1342c65b1445SDouglas Gilbert 	num += plen;
1343c65b1445SDouglas Gilbert 
1344c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1345c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1346c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1347c65b1445SDouglas Gilbert 	olen = strlen(na2);
1348c65b1445SDouglas Gilbert 	plen = olen + 1;
1349c65b1445SDouglas Gilbert 	if (plen % 4)
1350c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1351c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1352c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1353c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1354c65b1445SDouglas Gilbert 	num += plen;
1355c65b1445SDouglas Gilbert 
1356c65b1445SDouglas Gilbert 	return num;
1357c65b1445SDouglas Gilbert }
1358c65b1445SDouglas Gilbert 
1359c65b1445SDouglas Gilbert /* SCSI ports VPD page */
inquiry_vpd_88(unsigned char * arr,int target_dev_id)1360760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1361c65b1445SDouglas Gilbert {
1362c65b1445SDouglas Gilbert 	int num = 0;
1363c65b1445SDouglas Gilbert 	int port_a, port_b;
1364c65b1445SDouglas Gilbert 
1365c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1366c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1367c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1368c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1369c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1370c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1371c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1372c65b1445SDouglas Gilbert 	num += 6;
1373c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1374c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1375c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1376c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1377c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1378c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1379c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13801b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1381773642d9SDouglas Gilbert 	num += 8;
1382c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1383c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1384c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1385c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1386c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1387c65b1445SDouglas Gilbert 	num += 6;
1388c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1389c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1390c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1391c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1392c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1393c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1394c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13951b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1396773642d9SDouglas Gilbert 	num += 8;
1397c65b1445SDouglas Gilbert 
1398c65b1445SDouglas Gilbert 	return num;
1399c65b1445SDouglas Gilbert }
1400c65b1445SDouglas Gilbert 
1401c65b1445SDouglas Gilbert 
1402c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1403c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1404c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1405c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1406c65b1445SDouglas Gilbert '1','2','3','4',
1407c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1408c65b1445SDouglas Gilbert 0xec,0,0,0,
1409c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1410c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1411c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1412c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1413c65b1445SDouglas Gilbert 0x53,0x41,
1414c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1415c65b1445SDouglas Gilbert 0x20,0x20,
1416c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1417c65b1445SDouglas Gilbert 0x10,0x80,
1418c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1419c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1420c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1421c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1422c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1423c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1424c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1425c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1426c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1428c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1429c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1430c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1431c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1444c65b1445SDouglas Gilbert };
1445c65b1445SDouglas Gilbert 
1446cbf67842SDouglas Gilbert /* ATA Information VPD page */
inquiry_vpd_89(unsigned char * arr)1447760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1448c65b1445SDouglas Gilbert {
1449c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1450c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1451c65b1445SDouglas Gilbert }
1452c65b1445SDouglas Gilbert 
1453c65b1445SDouglas Gilbert 
1454c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
14551e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14561e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14571e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14581e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1459c65b1445SDouglas Gilbert };
1460c65b1445SDouglas Gilbert 
1461cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
inquiry_vpd_b0(unsigned char * arr)1462760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1463c65b1445SDouglas Gilbert {
1464ea61fca5SMartin K. Petersen 	unsigned int gran;
1465ea61fca5SMartin K. Petersen 
1466c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1467e308b3d1SMartin K. Petersen 
1468e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
146986e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
147086e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
147186e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
147286e6828aSLukas Herbolt 	else
1473773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1474773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1475e308b3d1SMartin K. Petersen 
1476e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1477773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1478773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
147944d92694SMartin K. Petersen 
1480e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1481773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1482e308b3d1SMartin K. Petersen 
1483773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1484e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1485773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1486e308b3d1SMartin K. Petersen 
1487e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1488773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
148944d92694SMartin K. Petersen 	}
149044d92694SMartin K. Petersen 
1491e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1492773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1493773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
149444d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
149544d92694SMartin K. Petersen 	}
149644d92694SMartin K. Petersen 
1497e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1498773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14996014759cSMartin K. Petersen 
15005b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1501773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
15025b94e232SMartin K. Petersen 
15035b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
15041da177e4SLinus Torvalds }
15051da177e4SLinus Torvalds 
15061e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
inquiry_vpd_b1(struct sdebug_dev_info * devip,unsigned char * arr)150764e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
1508eac6e8e4SMatthew Wilcox {
1509eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1510eac6e8e4SMatthew Wilcox 	arr[0] = 0;
15111e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15121e49f785SDouglas Gilbert 	arr[2] = 0;
15131e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
151464e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HA)
151564e14eceSDamien Le Moal 		arr[4] = 1 << 4;	/* zoned field = 01b */
1516eac6e8e4SMatthew Wilcox 
1517eac6e8e4SMatthew Wilcox 	return 0x3c;
1518eac6e8e4SMatthew Wilcox }
15191da177e4SLinus Torvalds 
1520760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
inquiry_vpd_b2(unsigned char * arr)1521760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
15226014759cSMartin K. Petersen {
15233f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
15246014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1525773642d9SDouglas Gilbert 	if (sdebug_lbpu)
15266014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1527773642d9SDouglas Gilbert 	if (sdebug_lbpws)
15286014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1529773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
15305b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1531760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1532760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1533760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1534760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1535760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
15363f0bc3b3SMartin K. Petersen 	return 0x4;
15376014759cSMartin K. Petersen }
15386014759cSMartin K. Petersen 
1539d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */
inquiry_vpd_b6(struct sdebug_dev_info * devip,unsigned char * arr)1540f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
1541d36da305SDouglas Gilbert {
1542d36da305SDouglas Gilbert 	memset(arr, 0, 0x3c);
1543d36da305SDouglas Gilbert 	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1544d36da305SDouglas Gilbert 	/*
1545d36da305SDouglas Gilbert 	 * Set Optimal number of open sequential write preferred zones and
1546d36da305SDouglas Gilbert 	 * Optimal number of non-sequentially written sequential write
1547f0d1cf93SDouglas Gilbert 	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1548f0d1cf93SDouglas Gilbert 	 * fields set to zero, apart from Max. number of open swrz_s field.
1549d36da305SDouglas Gilbert 	 */
1550d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[4]);
1551d36da305SDouglas Gilbert 	put_unaligned_be32(0xffffffff, &arr[8]);
155264e14eceSDamien Le Moal 	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
1553f0d1cf93SDouglas Gilbert 		put_unaligned_be32(devip->max_open, &arr[12]);
1554f0d1cf93SDouglas Gilbert 	else
1555d36da305SDouglas Gilbert 		put_unaligned_be32(0xffffffff, &arr[12]);
15564a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize) {
15574a5fc1c6SDamien Le Moal 		arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET;
15584a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, &arr[20]);
15594a5fc1c6SDamien Le Moal 	} else {
15604a5fc1c6SDamien Le Moal 		arr[19] = 0;
15614a5fc1c6SDamien Le Moal 	}
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 
resp_inquiry(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)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;
157336e07d7eSGeorge Kennedy 	u32 alloc_len, n;
157436e07d7eSGeorge Kennedy 	int ret;
1575d36da305SDouglas Gilbert 	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15761da177e4SLinus Torvalds 
1577773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
15786f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15796f3cbf55SDouglas Gilbert 	if (! arr)
15806f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1581760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
158264e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
1583d36da305SDouglas Gilbert 	is_disk_zbc = (is_disk || is_zbc);
1584b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1585c2248fc9SDouglas Gilbert 	if (have_wlun)
1586b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1587b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1588b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1589c65b1445SDouglas Gilbert 	else
1590773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
15911da177e4SLinus Torvalds 	arr[0] = pq_pdt;
15921da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
159322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15945a09e398SHannes Reinecke 		kfree(arr);
15951da177e4SLinus Torvalds 		return check_condition_result;
15961da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
159736e07d7eSGeorge Kennedy 		int lu_id_num, port_group_id, target_dev_id;
159836e07d7eSGeorge Kennedy 		u32 len;
1599c65b1445SDouglas Gilbert 		char lu_id_str[6];
1600c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
16011da177e4SLinus Torvalds 
16025a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
16035a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1604b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
160523183910SDouglas Gilbert 			host_no = 0;
1606c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1607c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1608c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1609c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1610c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16111da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1612c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1613c65b1445SDouglas Gilbert 			n = 4;
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1615c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1616c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1617c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1618c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1619c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1620c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1621c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1622d36da305SDouglas Gilbert 			if (is_disk_zbc) {	  /* SBC or ZBC */
1623c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1624760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1625760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1626d36da305SDouglas Gilbert 				if (is_disk)
1627d36da305SDouglas Gilbert 					arr[n++] = 0xb2;  /* LB Provisioning */
162864e14eceSDamien Le Moal 				if (is_zbc)
1629d36da305SDouglas Gilbert 					arr[n++] = 0xb6;  /* ZB dev. char. */
1630760f3b03SDouglas Gilbert 			}
1631c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
16321da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1633c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
16341da177e4SLinus Torvalds 			arr[3] = len;
1635c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
16361da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1637c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1638760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16395a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
164009ba24c1SDouglas Gilbert 						lu_id_str, len,
164109ba24c1SDouglas Gilbert 						&devip->lu_name);
1642c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1643c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1644760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1645c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1646c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1647760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1648c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1649c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1650c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
16518475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1652c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1653760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1654c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1655c6a44287SMartin K. Petersen 			else
1656c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1657c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1658c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1659c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1660c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1661c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1662c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1663c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1664c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1665c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1666c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1667760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1668d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
1669c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1670760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1671773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1672d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
1673c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1674760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1675d36da305SDouglas Gilbert 		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
1676eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
167764e14eceSDamien Le Moal 			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
1678760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16796014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1680760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
1681d36da305SDouglas Gilbert 		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1682d36da305SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1683f0d1cf93SDouglas Gilbert 			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16841da177e4SLinus Torvalds 		} else {
168522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16865a09e398SHannes Reinecke 			kfree(arr);
16871da177e4SLinus Torvalds 			return check_condition_result;
16881da177e4SLinus Torvalds 		}
168936e07d7eSGeorge Kennedy 		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
16905a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
169136e07d7eSGeorge Kennedy 			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
16925a09e398SHannes Reinecke 		kfree(arr);
16935a09e398SHannes Reinecke 		return ret;
16941da177e4SLinus Torvalds 	}
16951da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1696773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1697773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
16981da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
16991da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1700f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1701b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
170270bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1703c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
17041da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1705c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1706e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1707e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1708e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17099b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
17109b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
17111da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1712760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1713760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1714c65b1445SDouglas Gilbert 	n = 62;
1715760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1716760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1717760f3b03SDouglas Gilbert 		n += 2;
1718760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1719760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1720760f3b03SDouglas Gilbert 		n += 2;
1721d36da305SDouglas Gilbert 	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
1722d36da305SDouglas Gilbert 		put_unaligned_be16(0x624, arr + n);
1723d36da305SDouglas Gilbert 		n += 2;
17241da177e4SLinus Torvalds 	}
1725760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17265a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
172736e07d7eSGeorge Kennedy 			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17285a09e398SHannes Reinecke 	kfree(arr);
17295a09e398SHannes Reinecke 	return ret;
17301da177e4SLinus Torvalds }
17311da177e4SLinus Torvalds 
173284905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */
1733fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1734fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1735fd32119bSDouglas Gilbert 
resp_requests(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)17361da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
17371da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
17381da177e4SLinus Torvalds {
173901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
174084905d34SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
174184905d34SDouglas Gilbert 	bool dsense = !!(cmd[1] & 1);
174236e07d7eSGeorge Kennedy 	u32 alloc_len = cmd[4];
174336e07d7eSGeorge Kennedy 	u32 len = 18;
174484905d34SDouglas Gilbert 	int stopped_state = atomic_read(&devip->stopped);
17451da177e4SLinus Torvalds 
1746c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
174784905d34SDouglas Gilbert 	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
174884905d34SDouglas Gilbert 		if (dsense) {
174984905d34SDouglas Gilbert 			arr[0] = 0x72;
175084905d34SDouglas Gilbert 			arr[1] = NOT_READY;
175184905d34SDouglas Gilbert 			arr[2] = LOGICAL_UNIT_NOT_READY;
175284905d34SDouglas Gilbert 			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
175384905d34SDouglas Gilbert 			len = 8;
175484905d34SDouglas Gilbert 		} else {
175584905d34SDouglas Gilbert 			arr[0] = 0x70;
175684905d34SDouglas Gilbert 			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
175784905d34SDouglas Gilbert 			arr[7] = 0xa;			/* 18 byte sense buffer */
175884905d34SDouglas Gilbert 			arr[12] = LOGICAL_UNIT_NOT_READY;
175984905d34SDouglas Gilbert 			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
176084905d34SDouglas Gilbert 		}
176184905d34SDouglas Gilbert 	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
176284905d34SDouglas Gilbert 		/* Information exceptions control mode page: TEST=1, MRIE=6 */
1763c2248fc9SDouglas Gilbert 		if (dsense) {
1764c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1765c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1766c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
176784905d34SDouglas Gilbert 			arr[3] = 0xff;		/* Failure prediction(false) */
1768c2248fc9SDouglas Gilbert 			len = 8;
1769c65b1445SDouglas Gilbert 		} else {
1770c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1771c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1772c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1773c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
177484905d34SDouglas Gilbert 			arr[13] = 0xff;		/* Failure prediction(false) */
1775c65b1445SDouglas Gilbert 		}
177684905d34SDouglas Gilbert 	} else {	/* nothing to report */
1777c2248fc9SDouglas Gilbert 		if (dsense) {
1778c2248fc9SDouglas Gilbert 			len = 8;
177984905d34SDouglas Gilbert 			memset(arr, 0, len);
178084905d34SDouglas Gilbert 			arr[0] = 0x72;
1781c2248fc9SDouglas Gilbert 		} else {
178284905d34SDouglas Gilbert 			memset(arr, 0, len);
1783c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1784c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1785c2248fc9SDouglas Gilbert 		}
1786c65b1445SDouglas Gilbert 	}
178736e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
17881da177e4SLinus Torvalds }
17891da177e4SLinus Torvalds 
resp_start_stop(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)1790fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1791c65b1445SDouglas Gilbert {
179201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1793fc13638aSDouglas Gilbert 	int power_cond, want_stop, stopped_state;
17944f2c8bf6SDouglas Gilbert 	bool changing;
1795c65b1445SDouglas Gilbert 
1796c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1797c65b1445SDouglas Gilbert 	if (power_cond) {
179822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1799c65b1445SDouglas Gilbert 		return check_condition_result;
1800c65b1445SDouglas Gilbert 	}
1801fc13638aSDouglas Gilbert 	want_stop = !(cmd[4] & 1);
1802fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
1803fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
1804fc13638aSDouglas Gilbert 		ktime_t now_ts = ktime_get_boottime();
1805fc13638aSDouglas Gilbert 
1806fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1807fc13638aSDouglas Gilbert 			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1808fc13638aSDouglas Gilbert 
1809fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1810fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
1811fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
1812fc13638aSDouglas Gilbert 				stopped_state = 0;
1813fc13638aSDouglas Gilbert 			}
1814fc13638aSDouglas Gilbert 		}
1815fc13638aSDouglas Gilbert 		if (stopped_state == 2) {
1816fc13638aSDouglas Gilbert 			if (want_stop) {
1817fc13638aSDouglas Gilbert 				stopped_state = 1;	/* dummy up success */
1818fc13638aSDouglas Gilbert 			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
1819fc13638aSDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1820fc13638aSDouglas Gilbert 				return check_condition_result;
1821fc13638aSDouglas Gilbert 			}
1822fc13638aSDouglas Gilbert 		}
1823fc13638aSDouglas Gilbert 	}
1824fc13638aSDouglas Gilbert 	changing = (stopped_state != want_stop);
1825fc13638aSDouglas Gilbert 	if (changing)
1826fc13638aSDouglas Gilbert 		atomic_xchg(&devip->stopped, want_stop);
1827fc13638aSDouglas Gilbert 	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18284f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
18294f2c8bf6SDouglas Gilbert 	else
18304f2c8bf6SDouglas Gilbert 		return 0;
1831c65b1445SDouglas Gilbert }
1832c65b1445SDouglas Gilbert 
get_sdebug_capacity(void)183328898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
183428898873SFUJITA Tomonori {
1835773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1836773642d9SDouglas Gilbert 
1837773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1838773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1839773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
184028898873SFUJITA Tomonori 	else
184128898873SFUJITA Tomonori 		return sdebug_store_sectors;
184228898873SFUJITA Tomonori }
184328898873SFUJITA Tomonori 
18441da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
resp_readcap(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)18451da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
18461da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
18471da177e4SLinus Torvalds {
18481da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1849c65b1445SDouglas Gilbert 	unsigned int capac;
18501da177e4SLinus Torvalds 
1851c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
185228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
18531da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1854c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1855c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1856773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1857773642d9SDouglas Gilbert 	} else
1858773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1859773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
18601da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18611da177e4SLinus Torvalds }
18621da177e4SLinus Torvalds 
1863c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
resp_readcap16(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)1864c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1865c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1866c65b1445SDouglas Gilbert {
186701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1868c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18694e3ace00SYe Bin 	u32 alloc_len;
1870c65b1445SDouglas Gilbert 
1871773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1872c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
187328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1874c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1875773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1876773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1877773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1878773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
187944d92694SMartin K. Petersen 
1880be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
18815b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1882760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1883760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1884760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1885760f3b03SDouglas Gilbert 		 */
1886760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1887760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1888be1dd78dSEric Sandeen 	}
188944d92694SMartin K. Petersen 
1890ecb8c258SBart Van Assche 	/*
1891ecb8c258SBart Van Assche 	 * Since the scsi_debug READ CAPACITY implementation always reports the
1892ecb8c258SBart Van Assche 	 * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices.
1893ecb8c258SBart Van Assche 	 */
1894ecb8c258SBart Van Assche 	if (devip->zmodel == BLK_ZONED_HM)
1895ecb8c258SBart Van Assche 		arr[12] |= 1 << 4;
1896ecb8c258SBart Van Assche 
1897773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1898c6a44287SMartin K. Petersen 
1899760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1900773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1901c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1902c6a44287SMartin K. Petersen 	}
1903c6a44287SMartin K. Petersen 
1904c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
19054e3ace00SYe Bin 			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1906c65b1445SDouglas Gilbert }
1907c65b1445SDouglas Gilbert 
19085a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19095a09e398SHannes Reinecke 
resp_report_tgtpgs(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)19105a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
19115a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
19125a09e398SHannes Reinecke {
191301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19145a09e398SHannes Reinecke 	unsigned char *arr;
19155a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
19165a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
1917f347c268SYe Bin 	u32 alen, n, rlen;
1918f347c268SYe Bin 	int ret;
19195a09e398SHannes Reinecke 
1920773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
19216f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19226f3cbf55SDouglas Gilbert 	if (! arr)
19236f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
19245a09e398SHannes Reinecke 	/*
19255a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
19265a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
19275a09e398SHannes Reinecke 	 * So we create two port groups with one port each
19285a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
19295a09e398SHannes Reinecke 	 */
19305a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
19315a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
19325a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19335a09e398SHannes Reinecke 			(devip->channel & 0x7f);
19345a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19355a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
19365a09e398SHannes Reinecke 
19375a09e398SHannes Reinecke 	/*
19385a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
19395a09e398SHannes Reinecke 	 */
19405a09e398SHannes Reinecke 	n = 4;
1941b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
19425a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
19435a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
19445a09e398SHannes Reinecke 	} else {
19455a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1946773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
19475a09e398SHannes Reinecke 	}
1948773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1949773642d9SDouglas Gilbert 	n += 2;
19505a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19535a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19545a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19555a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1956773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1957773642d9SDouglas Gilbert 	n += 2;
19585a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
19595a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1960773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1961773642d9SDouglas Gilbert 	n += 2;
19625a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
19645a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
19655a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
19665a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
19675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1968773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1969773642d9SDouglas Gilbert 	n += 2;
19705a09e398SHannes Reinecke 
19715a09e398SHannes Reinecke 	rlen = n - 4;
1972773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
19735a09e398SHannes Reinecke 
19745a09e398SHannes Reinecke 	/*
19755a09e398SHannes Reinecke 	 * Return the smallest value of either
19765a09e398SHannes Reinecke 	 * - The allocated length
19775a09e398SHannes Reinecke 	 * - The constructed command length
19785a09e398SHannes Reinecke 	 * - The maximum array size
19795a09e398SHannes Reinecke 	 */
1980f347c268SYe Bin 	rlen = min(alen, n);
19815a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
1982f347c268SYe Bin 			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19835a09e398SHannes Reinecke 	kfree(arr);
19845a09e398SHannes Reinecke 	return ret;
19855a09e398SHannes Reinecke }
19865a09e398SHannes Reinecke 
resp_rsup_opcodes(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)1987fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1988fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
198938d5c833SDouglas Gilbert {
199038d5c833SDouglas Gilbert 	bool rctd;
199138d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
199238d5c833SDouglas Gilbert 	u16 req_sa, u;
199338d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
199438d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
199538d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
199638d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
199738d5c833SDouglas Gilbert 	u8 *arr;
199838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
199938d5c833SDouglas Gilbert 
200038d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
200138d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
200238d5c833SDouglas Gilbert 	req_opcode = cmd[3];
200338d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
200438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
20056d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
200638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
200738d5c833SDouglas Gilbert 		return check_condition_result;
200838d5c833SDouglas Gilbert 	}
200938d5c833SDouglas Gilbert 	if (alloc_len > 8192)
201038d5c833SDouglas Gilbert 		a_len = 8192;
201138d5c833SDouglas Gilbert 	else
201238d5c833SDouglas Gilbert 		a_len = alloc_len;
201399531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
201438d5c833SDouglas Gilbert 	if (NULL == arr) {
201538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
201638d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
201738d5c833SDouglas Gilbert 		return check_condition_result;
201838d5c833SDouglas Gilbert 	}
201938d5c833SDouglas Gilbert 	switch (reporting_opts) {
202038d5c833SDouglas Gilbert 	case 0:	/* all commands */
202138d5c833SDouglas Gilbert 		/* count number of commands */
202238d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
202338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
202438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
202538d5c833SDouglas Gilbert 				continue;
202638d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
202738d5c833SDouglas Gilbert 		}
202838d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
202938d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
203038d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
203138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
203238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
203338d5c833SDouglas Gilbert 				continue;
203438d5c833SDouglas Gilbert 			na = oip->num_attached;
203538d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
203638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
203738d5c833SDouglas Gilbert 			if (rctd)
203838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
203938d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
204038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
204138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
204238d5c833SDouglas Gilbert 			if (rctd)
204338d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
204438d5c833SDouglas Gilbert 			r_oip = oip;
204538d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
204638d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
204738d5c833SDouglas Gilbert 					continue;
204838d5c833SDouglas Gilbert 				offset += bump;
204938d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
205038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
205138d5c833SDouglas Gilbert 				if (rctd)
205238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
205338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
205438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
205538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
205638d5c833SDouglas Gilbert 						   arr + offset + 6);
205738d5c833SDouglas Gilbert 				if (rctd)
205838d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
205938d5c833SDouglas Gilbert 							   arr + offset + 8);
206038d5c833SDouglas Gilbert 			}
206138d5c833SDouglas Gilbert 			oip = r_oip;
206238d5c833SDouglas Gilbert 			offset += bump;
206338d5c833SDouglas Gilbert 		}
206438d5c833SDouglas Gilbert 		break;
206538d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
206638d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
206738d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
206838d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
206938d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
207038d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
207138d5c833SDouglas Gilbert 			supp = 1;
207238d5c833SDouglas Gilbert 			offset = 4;
207338d5c833SDouglas Gilbert 		} else {
207438d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
207538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
207638d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
207738d5c833SDouglas Gilbert 							     2, 2);
207838d5c833SDouglas Gilbert 					kfree(arr);
207938d5c833SDouglas Gilbert 					return check_condition_result;
208038d5c833SDouglas Gilbert 				}
208138d5c833SDouglas Gilbert 				req_sa = 0;
208238d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
208338d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
208438d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
208538d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
208638d5c833SDouglas Gilbert 				return check_condition_result;
208738d5c833SDouglas Gilbert 			}
208838d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
208938d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
209038d5c833SDouglas Gilbert 				supp = 3;
209138d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
209238d5c833SDouglas Gilbert 				na = oip->num_attached;
209338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
209438d5c833SDouglas Gilbert 				     ++k, ++oip) {
209538d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
209638d5c833SDouglas Gilbert 						break;
209738d5c833SDouglas Gilbert 				}
209838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
209938d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
210038d5c833SDouglas Gilbert 				na = oip->num_attached;
210138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
210238d5c833SDouglas Gilbert 				     ++k, ++oip) {
210338d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
210438d5c833SDouglas Gilbert 						break;
210538d5c833SDouglas Gilbert 				}
210638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
210738d5c833SDouglas Gilbert 			} else
210838d5c833SDouglas Gilbert 				supp = 3;
210938d5c833SDouglas Gilbert 			if (3 == supp) {
211038d5c833SDouglas Gilbert 				u = oip->len_mask[0];
211138d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
211238d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
211338d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
211438d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
211538d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
211638d5c833SDouglas Gilbert 				offset = 4 + u;
211738d5c833SDouglas Gilbert 			} else
211838d5c833SDouglas Gilbert 				offset = 4;
211938d5c833SDouglas Gilbert 		}
212038d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
212138d5c833SDouglas Gilbert 		if (rctd) {
212238d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
212338d5c833SDouglas Gilbert 			offset += 12;
212438d5c833SDouglas Gilbert 		}
212538d5c833SDouglas Gilbert 		break;
212638d5c833SDouglas Gilbert 	default:
212738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
212838d5c833SDouglas Gilbert 		kfree(arr);
212938d5c833SDouglas Gilbert 		return check_condition_result;
213038d5c833SDouglas Gilbert 	}
213138d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
213238d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
213338d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
213438d5c833SDouglas Gilbert 	kfree(arr);
213538d5c833SDouglas Gilbert 	return errsts;
213638d5c833SDouglas Gilbert }
213738d5c833SDouglas Gilbert 
resp_rsup_tmfs(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)2138fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2139fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
214038d5c833SDouglas Gilbert {
214138d5c833SDouglas Gilbert 	bool repd;
214238d5c833SDouglas Gilbert 	u32 alloc_len, len;
214338d5c833SDouglas Gilbert 	u8 arr[16];
214438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
214538d5c833SDouglas Gilbert 
214638d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
214738d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
214838d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
214938d5c833SDouglas Gilbert 	if (alloc_len < 4) {
215038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
215138d5c833SDouglas Gilbert 		return check_condition_result;
215238d5c833SDouglas Gilbert 	}
215338d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
215438d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
215538d5c833SDouglas Gilbert 	if (repd) {
215638d5c833SDouglas Gilbert 		arr[3] = 0xc;
215738d5c833SDouglas Gilbert 		len = 16;
215838d5c833SDouglas Gilbert 	} else
215938d5c833SDouglas Gilbert 		len = 4;
216038d5c833SDouglas Gilbert 
216138d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
216238d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
216338d5c833SDouglas Gilbert }
216438d5c833SDouglas Gilbert 
21651da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
21661da177e4SLinus Torvalds 
resp_err_recov_pg(unsigned char * p,int pcontrol,int target)21671da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21681da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
21691da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21701da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
21711da177e4SLinus Torvalds 
21721da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21731da177e4SLinus Torvalds 	if (1 == pcontrol)
21741da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21751da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
21761da177e4SLinus Torvalds }
21771da177e4SLinus Torvalds 
resp_disconnect_pg(unsigned char * p,int pcontrol,int target)21781da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21791da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
21801da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21811da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
21821da177e4SLinus Torvalds 
21831da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21841da177e4SLinus Torvalds 	if (1 == pcontrol)
21851da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21861da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
21871da177e4SLinus Torvalds }
21881da177e4SLinus Torvalds 
resp_format_pg(unsigned char * p,int pcontrol,int target)21891da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
21901da177e4SLinus Torvalds {       /* Format device page for mode_sense */
21911da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21921da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
21931da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
21941da177e4SLinus Torvalds 
21951da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2196773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2197773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2198773642d9SDouglas Gilbert 	if (sdebug_removable)
21991da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
22001da177e4SLinus Torvalds 	if (1 == pcontrol)
22011da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
22021da177e4SLinus Torvalds 	return sizeof(format_pg);
22031da177e4SLinus Torvalds }
22041da177e4SLinus Torvalds 
2205fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2206fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2207fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2208fd32119bSDouglas Gilbert 
resp_caching_pg(unsigned char * p,int pcontrol,int target)22091da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22101da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2211cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2212cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2213cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22141da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22151da177e4SLinus Torvalds 
2216773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2217cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22181da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
22191da177e4SLinus Torvalds 	if (1 == pcontrol)
2220cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2221cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2222cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22231da177e4SLinus Torvalds 	return sizeof(caching_pg);
22241da177e4SLinus Torvalds }
22251da177e4SLinus Torvalds 
2226fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2227fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2228fd32119bSDouglas Gilbert 
resp_ctrl_m_pg(unsigned char * p,int pcontrol,int target)22291da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22301da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2231c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2232c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2233c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22341da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
22351da177e4SLinus Torvalds 
2236773642d9SDouglas Gilbert 	if (sdebug_dsense)
22371da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2238c65b1445SDouglas Gilbert 	else
2239c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2240c6a44287SMartin K. Petersen 
2241773642d9SDouglas Gilbert 	if (sdebug_ato)
2242c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2243c6a44287SMartin K. Petersen 
22441da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22451da177e4SLinus Torvalds 	if (1 == pcontrol)
2246c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2247c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2248c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22491da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
22501da177e4SLinus Torvalds }
22511da177e4SLinus Torvalds 
2252c65b1445SDouglas Gilbert 
resp_iec_m_pg(unsigned char * p,int pcontrol,int target)22531da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22541da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2255c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22561da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2257c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2258c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2259c65b1445SDouglas Gilbert 
22601da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22611da177e4SLinus Torvalds 	if (1 == pcontrol)
2262c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2263c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2264c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22651da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
22661da177e4SLinus Torvalds }
22671da177e4SLinus Torvalds 
resp_sas_sf_m_pg(unsigned char * p,int pcontrol,int target)2268c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2269c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2270c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2271c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2272c65b1445SDouglas Gilbert 
2273c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2274c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2275c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2276c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2277c65b1445SDouglas Gilbert }
2278c65b1445SDouglas Gilbert 
2279c65b1445SDouglas Gilbert 
resp_sas_pcd_m_spg(unsigned char * p,int pcontrol,int target,int target_dev_id)2280c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2281c65b1445SDouglas Gilbert 			      int target_dev_id)
2282c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2283c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2284c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2285773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2286773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2287c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2288c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2289c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2290c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2291773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2292773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2293c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2294c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2295c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2296c65b1445SDouglas Gilbert 		};
2297c65b1445SDouglas Gilbert 	int port_a, port_b;
2298c65b1445SDouglas Gilbert 
22991b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
23001b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
23011b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
23021b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2303c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2304c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2305c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2306773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2307773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2308c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2309c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2310c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2311c65b1445SDouglas Gilbert }
2312c65b1445SDouglas Gilbert 
resp_sas_sha_m_spg(unsigned char * p,int pcontrol)2313c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2314c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2315c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2316c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2317c65b1445SDouglas Gilbert 		};
2318c65b1445SDouglas Gilbert 
2319c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2320c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2321c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2322c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2323c65b1445SDouglas Gilbert }
2324c65b1445SDouglas Gilbert 
23251da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
23261da177e4SLinus Torvalds 
resp_mode_sense(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)2327fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2328fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
23291da177e4SLinus Torvalds {
233023183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
23311da177e4SLinus Torvalds 	unsigned char dev_spec;
233236e07d7eSGeorge Kennedy 	u32 alloc_len, offset, len;
233336e07d7eSGeorge Kennedy 	int target_dev_id;
2334c2248fc9SDouglas Gilbert 	int target = scp->device->id;
23351da177e4SLinus Torvalds 	unsigned char *ap;
23361da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
233701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2338d36da305SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23391da177e4SLinus Torvalds 
2340760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23411da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
23421da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
23431da177e4SLinus Torvalds 	subpcode = cmd[3];
23441da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2345760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2346760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
234764e14eceSDamien Le Moal 	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
2348d36da305SDouglas Gilbert 	if ((is_disk || is_zbc) && !dbd)
234923183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
235023183910SDouglas Gilbert 	else
235123183910SDouglas Gilbert 		bd_len = 0;
2352773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23531da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23541da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2355cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23561da177e4SLinus Torvalds 		return check_condition_result;
23571da177e4SLinus Torvalds 	}
2358c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2359c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2360d36da305SDouglas Gilbert 	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2361d36da305SDouglas Gilbert 	if (is_disk || is_zbc) {
2362b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23639447b6ceSMartin K. Petersen 		if (sdebug_wp)
23649447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
23659447b6ceSMartin K. Petersen 	} else
236623183910SDouglas Gilbert 		dev_spec = 0x0;
23671da177e4SLinus Torvalds 	if (msense_6) {
23681da177e4SLinus Torvalds 		arr[2] = dev_spec;
236923183910SDouglas Gilbert 		arr[3] = bd_len;
23701da177e4SLinus Torvalds 		offset = 4;
23711da177e4SLinus Torvalds 	} else {
23721da177e4SLinus Torvalds 		arr[3] = dev_spec;
237323183910SDouglas Gilbert 		if (16 == bd_len)
237423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
237523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
23761da177e4SLinus Torvalds 		offset = 8;
23771da177e4SLinus Torvalds 	}
23781da177e4SLinus Torvalds 	ap = arr + offset;
237928898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
238028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
238128898873SFUJITA Tomonori 
238223183910SDouglas Gilbert 	if (8 == bd_len) {
2383773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2384773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2385773642d9SDouglas Gilbert 		else
2386773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2387773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
238823183910SDouglas Gilbert 		offset += bd_len;
238923183910SDouglas Gilbert 		ap = arr + offset;
239023183910SDouglas Gilbert 	} else if (16 == bd_len) {
2391773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2392773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
239323183910SDouglas Gilbert 		offset += bd_len;
239423183910SDouglas Gilbert 		ap = arr + offset;
239523183910SDouglas Gilbert 	}
23961da177e4SLinus Torvalds 
2397c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2398c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
239922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24001da177e4SLinus Torvalds 		return check_condition_result;
24011da177e4SLinus Torvalds 	}
2402760f3b03SDouglas Gilbert 	bad_pcode = false;
2403760f3b03SDouglas Gilbert 
24041da177e4SLinus Torvalds 	switch (pcode) {
24051da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
24061da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
24071da177e4SLinus Torvalds 		offset += len;
24081da177e4SLinus Torvalds 		break;
24091da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
24101da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
24111da177e4SLinus Torvalds 		offset += len;
24121da177e4SLinus Torvalds 		break;
24131da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2414760f3b03SDouglas Gilbert 		if (is_disk) {
24151da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
24161da177e4SLinus Torvalds 			offset += len;
2417760f3b03SDouglas Gilbert 		} else
2418760f3b03SDouglas Gilbert 			bad_pcode = true;
24191da177e4SLinus Torvalds 		break;
24201da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2421d36da305SDouglas Gilbert 		if (is_disk || is_zbc) {
24221da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
24231da177e4SLinus Torvalds 			offset += len;
2424760f3b03SDouglas Gilbert 		} else
2425760f3b03SDouglas Gilbert 			bad_pcode = true;
24261da177e4SLinus Torvalds 		break;
24271da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
24281da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
24291da177e4SLinus Torvalds 		offset += len;
24301da177e4SLinus Torvalds 		break;
2431c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2432c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
243322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2434c65b1445SDouglas Gilbert 			return check_condition_result;
2435c65b1445SDouglas Gilbert 		}
2436c65b1445SDouglas Gilbert 		len = 0;
2437c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2438c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2439c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2440c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2441c65b1445SDouglas Gilbert 						  target_dev_id);
2442c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2443c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2444c65b1445SDouglas Gilbert 		offset += len;
2445c65b1445SDouglas Gilbert 		break;
24461da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24471da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
24481da177e4SLinus Torvalds 		offset += len;
24491da177e4SLinus Torvalds 		break;
24501da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2451c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
24521da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
24531da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2454760f3b03SDouglas Gilbert 			if (is_disk) {
2455760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2456760f3b03SDouglas Gilbert 						      target);
2457760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2458760f3b03SDouglas Gilbert 						       target);
2459d36da305SDouglas Gilbert 			} else if (is_zbc) {
2460d36da305SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2461d36da305SDouglas Gilbert 						       target);
2462760f3b03SDouglas Gilbert 			}
24631da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2464c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2465c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2466c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2467c65b1445SDouglas Gilbert 						  target, target_dev_id);
2468c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2469c65b1445SDouglas Gilbert 			}
24701da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2471760f3b03SDouglas Gilbert 			offset += len;
2472c65b1445SDouglas Gilbert 		} else {
247322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2474c65b1445SDouglas Gilbert 			return check_condition_result;
2475c65b1445SDouglas Gilbert 		}
24761da177e4SLinus Torvalds 		break;
24771da177e4SLinus Torvalds 	default:
2478760f3b03SDouglas Gilbert 		bad_pcode = true;
2479760f3b03SDouglas Gilbert 		break;
2480760f3b03SDouglas Gilbert 	}
2481760f3b03SDouglas Gilbert 	if (bad_pcode) {
248222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24831da177e4SLinus Torvalds 		return check_condition_result;
24841da177e4SLinus Torvalds 	}
24851da177e4SLinus Torvalds 	if (msense_6)
24861da177e4SLinus Torvalds 		arr[0] = offset - 1;
2487773642d9SDouglas Gilbert 	else
2488773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
248936e07d7eSGeorge Kennedy 	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
24901da177e4SLinus Torvalds }
24911da177e4SLinus Torvalds 
2492c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2493c65b1445SDouglas Gilbert 
resp_mode_select(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)2494fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2495fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2496c65b1445SDouglas Gilbert {
2497c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2498c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2499c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
250001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2501c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2502c65b1445SDouglas Gilbert 
2503c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2504c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2505c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2506773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2507c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
250822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2509c65b1445SDouglas Gilbert 		return check_condition_result;
2510c65b1445SDouglas Gilbert 	}
2511c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2512c65b1445SDouglas Gilbert 	if (-1 == res)
2513773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2514773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2515cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2516cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2517cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2518773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2519773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
2520e0a2c28dSGeorge Kennedy 	off = bd_len + (mselect6 ? 4 : 8);
2521e0a2c28dSGeorge Kennedy 	if (md_len > 2 || off >= res) {
252222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2523c65b1445SDouglas Gilbert 		return check_condition_result;
2524c65b1445SDouglas Gilbert 	}
2525c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2526c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2527c65b1445SDouglas Gilbert 	if (ps) {
252822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2529c65b1445SDouglas Gilbert 		return check_condition_result;
2530c65b1445SDouglas Gilbert 	}
2531c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2532773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2533c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2534c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2535cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2536c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2537c65b1445SDouglas Gilbert 		return check_condition_result;
2538c65b1445SDouglas Gilbert 	}
2539c65b1445SDouglas Gilbert 	switch (mpage) {
2540cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2541cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2542cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2543cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2544cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2545cbf67842SDouglas Gilbert 		}
2546cbf67842SDouglas Gilbert 		break;
2547c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2548c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2549c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2550c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
25519447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
25529447b6ceSMartin K. Petersen 				sdebug_wp = true;
25539447b6ceSMartin K. Petersen 			else
25549447b6ceSMartin K. Petersen 				sdebug_wp = false;
2555773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2556cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2557c65b1445SDouglas Gilbert 		}
2558c65b1445SDouglas Gilbert 		break;
2559c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2560c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2561c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2562c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2563cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2564c65b1445SDouglas Gilbert 		}
2565c65b1445SDouglas Gilbert 		break;
2566c65b1445SDouglas Gilbert 	default:
2567c65b1445SDouglas Gilbert 		break;
2568c65b1445SDouglas Gilbert 	}
256922017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2570c65b1445SDouglas Gilbert 	return check_condition_result;
2571cbf67842SDouglas Gilbert set_mode_changed_ua:
2572cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2573cbf67842SDouglas Gilbert 	return 0;
2574c65b1445SDouglas Gilbert }
2575c65b1445SDouglas Gilbert 
resp_temp_l_pg(unsigned char * arr)2576c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2577c65b1445SDouglas Gilbert {
2578c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2579c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2580c65b1445SDouglas Gilbert 		};
2581c65b1445SDouglas Gilbert 
2582c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2583c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2584c65b1445SDouglas Gilbert }
2585c65b1445SDouglas Gilbert 
resp_ie_l_pg(unsigned char * arr)2586c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2587c65b1445SDouglas Gilbert {
2588c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2589c65b1445SDouglas Gilbert 		};
2590c65b1445SDouglas Gilbert 
2591c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2592c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2593c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2594c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2595c65b1445SDouglas Gilbert 	}
2596c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2597c65b1445SDouglas Gilbert }
2598c65b1445SDouglas Gilbert 
resp_env_rep_l_spg(unsigned char * arr)25990790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr)
26000790797aSDouglas Gilbert {
26010790797aSDouglas Gilbert 	unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
26020790797aSDouglas Gilbert 					 0x0, 40, 72, 0xff, 45, 18, 0, 0,
26030790797aSDouglas Gilbert 					 0x1, 0x0, 0x23, 0x8,
26040790797aSDouglas Gilbert 					 0x0, 55, 72, 35, 55, 45, 0, 0,
26050790797aSDouglas Gilbert 		};
26060790797aSDouglas Gilbert 
26070790797aSDouglas Gilbert 	memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
26080790797aSDouglas Gilbert 	return sizeof(env_rep_l_spg);
26090790797aSDouglas Gilbert }
26100790797aSDouglas Gilbert 
2611c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2612c65b1445SDouglas Gilbert 
resp_log_sense(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)2613c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2614c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2615c65b1445SDouglas Gilbert {
261636e07d7eSGeorge Kennedy 	int ppc, sp, pcode, subpcode;
261736e07d7eSGeorge Kennedy 	u32 alloc_len, len, n;
2618c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
261901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2620c65b1445SDouglas Gilbert 
2621c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2622c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2623c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2624c65b1445SDouglas Gilbert 	if (ppc || sp) {
262522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2626c65b1445SDouglas Gilbert 		return check_condition_result;
2627c65b1445SDouglas Gilbert 	}
2628c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
262923183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2630773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2631c65b1445SDouglas Gilbert 	arr[0] = pcode;
263223183910SDouglas Gilbert 	if (0 == subpcode) {
2633c65b1445SDouglas Gilbert 		switch (pcode) {
2634c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2635c65b1445SDouglas Gilbert 			n = 4;
2636c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2637c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2638c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2639c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2640c65b1445SDouglas Gilbert 			break;
2641c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2642c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2643c65b1445SDouglas Gilbert 			break;
2644c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2645c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2646c65b1445SDouglas Gilbert 			break;
2647c65b1445SDouglas Gilbert 		default:
264822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2649c65b1445SDouglas Gilbert 			return check_condition_result;
2650c65b1445SDouglas Gilbert 		}
265123183910SDouglas Gilbert 	} else if (0xff == subpcode) {
265223183910SDouglas Gilbert 		arr[0] |= 0x40;
265323183910SDouglas Gilbert 		arr[1] = subpcode;
265423183910SDouglas Gilbert 		switch (pcode) {
265523183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
265623183910SDouglas Gilbert 			n = 4;
265723183910SDouglas Gilbert 			arr[n++] = 0x0;
265823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
265923183910SDouglas Gilbert 			arr[n++] = 0x0;
266023183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
266123183910SDouglas Gilbert 			arr[n++] = 0xd;
266223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26630790797aSDouglas Gilbert 			arr[n++] = 0xd;
26640790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26650790797aSDouglas Gilbert 			arr[n++] = 0xd;
26660790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0xd subpages */
266723183910SDouglas Gilbert 			arr[n++] = 0x2f;
266823183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
26690790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26700790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* all 0x2f subpages */
267123183910SDouglas Gilbert 			arr[3] = n - 4;
267223183910SDouglas Gilbert 			break;
267323183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
267423183910SDouglas Gilbert 			n = 4;
267523183910SDouglas Gilbert 			arr[n++] = 0xd;
267623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
26770790797aSDouglas Gilbert 			arr[n++] = 0xd;
26780790797aSDouglas Gilbert 			arr[n++] = 0x1;		/* Environment reporting */
26790790797aSDouglas Gilbert 			arr[n++] = 0xd;
26800790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
268123183910SDouglas Gilbert 			arr[3] = n - 4;
268223183910SDouglas Gilbert 			break;
268323183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
268423183910SDouglas Gilbert 			n = 4;
268523183910SDouglas Gilbert 			arr[n++] = 0x2f;
268623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
26870790797aSDouglas Gilbert 			arr[n++] = 0x2f;
26880790797aSDouglas Gilbert 			arr[n++] = 0xff;	/* these subpages */
268923183910SDouglas Gilbert 			arr[3] = n - 4;
269023183910SDouglas Gilbert 			break;
269123183910SDouglas Gilbert 		default:
269222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
269323183910SDouglas Gilbert 			return check_condition_result;
269423183910SDouglas Gilbert 		}
26950790797aSDouglas Gilbert 	} else if (subpcode > 0) {
26960790797aSDouglas Gilbert 		arr[0] |= 0x40;
26970790797aSDouglas Gilbert 		arr[1] = subpcode;
26980790797aSDouglas Gilbert 		if (pcode == 0xd && subpcode == 1)
26990790797aSDouglas Gilbert 			arr[3] = resp_env_rep_l_spg(arr + 4);
27000790797aSDouglas Gilbert 		else {
27010790797aSDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
27020790797aSDouglas Gilbert 			return check_condition_result;
27030790797aSDouglas Gilbert 		}
270423183910SDouglas Gilbert 	} else {
270522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
270623183910SDouglas Gilbert 		return check_condition_result;
270723183910SDouglas Gilbert 	}
270836e07d7eSGeorge Kennedy 	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
2709c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
271036e07d7eSGeorge Kennedy 		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
2711c65b1445SDouglas Gilbert }
2712c65b1445SDouglas Gilbert 
sdebug_dev_is_zoned(struct sdebug_dev_info * devip)2713f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
2714f0d1cf93SDouglas Gilbert {
2715f0d1cf93SDouglas Gilbert 	return devip->nr_zones != 0;
2716f0d1cf93SDouglas Gilbert }
2717f0d1cf93SDouglas Gilbert 
zbc_zone(struct sdebug_dev_info * devip,unsigned long long lba)2718f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2719f0d1cf93SDouglas Gilbert 					unsigned long long lba)
2720f0d1cf93SDouglas Gilbert {
27214a5fc1c6SDamien Le Moal 	u32 zno = lba >> devip->zsize_shift;
27224a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp;
27234a5fc1c6SDamien Le Moal 
27244a5fc1c6SDamien Le Moal 	if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones)
27254a5fc1c6SDamien Le Moal 		return &devip->zstate[zno];
27264a5fc1c6SDamien Le Moal 
27274a5fc1c6SDamien Le Moal 	/*
27284a5fc1c6SDamien Le Moal 	 * If the zone capacity is less than the zone size, adjust for gap
27294a5fc1c6SDamien Le Moal 	 * zones.
27304a5fc1c6SDamien Le Moal 	 */
27314a5fc1c6SDamien Le Moal 	zno = 2 * zno - devip->nr_conv_zones;
27324a5fc1c6SDamien Le Moal 	WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones);
27334a5fc1c6SDamien Le Moal 	zsp = &devip->zstate[zno];
27344a5fc1c6SDamien Le Moal 	if (lba >= zsp->z_start + zsp->z_size)
27354a5fc1c6SDamien Le Moal 		zsp++;
27364a5fc1c6SDamien Le Moal 	WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size);
27374a5fc1c6SDamien Le Moal 	return zsp;
2738f0d1cf93SDouglas Gilbert }
2739f0d1cf93SDouglas Gilbert 
zbc_zone_is_conv(struct sdeb_zone_state * zsp)2740f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2741f0d1cf93SDouglas Gilbert {
274235dbe2b9SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_CNV;
2743f0d1cf93SDouglas Gilbert }
2744f0d1cf93SDouglas Gilbert 
zbc_zone_is_gap(struct sdeb_zone_state * zsp)27454a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp)
27464a5fc1c6SDamien Le Moal {
27474a5fc1c6SDamien Le Moal 	return zsp->z_type == ZBC_ZTYPE_GAP;
27484a5fc1c6SDamien Le Moal }
27494a5fc1c6SDamien Le Moal 
zbc_zone_is_seq(struct sdeb_zone_state * zsp)27504a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp)
27514a5fc1c6SDamien Le Moal {
27524a5fc1c6SDamien Le Moal 	return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp);
27534a5fc1c6SDamien Le Moal }
27544a5fc1c6SDamien Le Moal 
zbc_close_zone(struct sdebug_dev_info * devip,struct sdeb_zone_state * zsp)2755f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip,
2756f0d1cf93SDouglas Gilbert 			   struct sdeb_zone_state *zsp)
2757f0d1cf93SDouglas Gilbert {
2758f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2759f0d1cf93SDouglas Gilbert 
27604a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2761f0d1cf93SDouglas Gilbert 		return;
2762f0d1cf93SDouglas Gilbert 
2763f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2764f0d1cf93SDouglas Gilbert 	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2765f0d1cf93SDouglas Gilbert 		return;
2766f0d1cf93SDouglas Gilbert 
2767f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN)
2768f0d1cf93SDouglas Gilbert 		devip->nr_imp_open--;
2769f0d1cf93SDouglas Gilbert 	else
2770f0d1cf93SDouglas Gilbert 		devip->nr_exp_open--;
2771f0d1cf93SDouglas Gilbert 
2772f0d1cf93SDouglas Gilbert 	if (zsp->z_wp == zsp->z_start) {
2773f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC1_EMPTY;
2774f0d1cf93SDouglas Gilbert 	} else {
2775f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC4_CLOSED;
2776f0d1cf93SDouglas Gilbert 		devip->nr_closed++;
2777f0d1cf93SDouglas Gilbert 	}
2778f0d1cf93SDouglas Gilbert }
2779f0d1cf93SDouglas Gilbert 
zbc_close_imp_open_zone(struct sdebug_dev_info * devip)2780f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2781f0d1cf93SDouglas Gilbert {
2782f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
2783f0d1cf93SDouglas Gilbert 	unsigned int i;
2784f0d1cf93SDouglas Gilbert 
2785f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
2786f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2787f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
2788f0d1cf93SDouglas Gilbert 			return;
2789f0d1cf93SDouglas Gilbert 		}
2790f0d1cf93SDouglas Gilbert 	}
2791f0d1cf93SDouglas Gilbert }
2792f0d1cf93SDouglas Gilbert 
zbc_open_zone(struct sdebug_dev_info * devip,struct sdeb_zone_state * zsp,bool explicit)2793f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip,
2794f0d1cf93SDouglas Gilbert 			  struct sdeb_zone_state *zsp, bool explicit)
2795f0d1cf93SDouglas Gilbert {
2796f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
2797f0d1cf93SDouglas Gilbert 
27984a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2799f0d1cf93SDouglas Gilbert 		return;
2800f0d1cf93SDouglas Gilbert 
2801f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
2802f0d1cf93SDouglas Gilbert 	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2803f0d1cf93SDouglas Gilbert 	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
2804f0d1cf93SDouglas Gilbert 		return;
2805f0d1cf93SDouglas Gilbert 
2806f0d1cf93SDouglas Gilbert 	/* Close an implicit open zone if necessary */
2807f0d1cf93SDouglas Gilbert 	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2808f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
2809f0d1cf93SDouglas Gilbert 	else if (devip->max_open &&
2810f0d1cf93SDouglas Gilbert 		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2811f0d1cf93SDouglas Gilbert 		zbc_close_imp_open_zone(devip);
2812f0d1cf93SDouglas Gilbert 
2813f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
2814f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
2815f0d1cf93SDouglas Gilbert 	if (explicit) {
2816f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC3_EXPLICIT_OPEN;
2817f0d1cf93SDouglas Gilbert 		devip->nr_exp_open++;
2818f0d1cf93SDouglas Gilbert 	} else {
2819f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC2_IMPLICIT_OPEN;
2820f0d1cf93SDouglas Gilbert 		devip->nr_imp_open++;
2821f0d1cf93SDouglas Gilbert 	}
2822f0d1cf93SDouglas Gilbert }
2823f0d1cf93SDouglas Gilbert 
zbc_set_zone_full(struct sdebug_dev_info * devip,struct sdeb_zone_state * zsp)2824566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip,
2825566d3c57SDamien Le Moal 				     struct sdeb_zone_state *zsp)
2826566d3c57SDamien Le Moal {
2827566d3c57SDamien Le Moal 	switch (zsp->z_cond) {
2828566d3c57SDamien Le Moal 	case ZC2_IMPLICIT_OPEN:
2829566d3c57SDamien Le Moal 		devip->nr_imp_open--;
2830566d3c57SDamien Le Moal 		break;
2831566d3c57SDamien Le Moal 	case ZC3_EXPLICIT_OPEN:
2832566d3c57SDamien Le Moal 		devip->nr_exp_open--;
2833566d3c57SDamien Le Moal 		break;
2834566d3c57SDamien Le Moal 	default:
2835566d3c57SDamien Le Moal 		WARN_ONCE(true, "Invalid zone %llu condition %x\n",
2836566d3c57SDamien Le Moal 			  zsp->z_start, zsp->z_cond);
2837566d3c57SDamien Le Moal 		break;
2838566d3c57SDamien Le Moal 	}
2839566d3c57SDamien Le Moal 	zsp->z_cond = ZC5_FULL;
2840566d3c57SDamien Le Moal }
2841566d3c57SDamien Le Moal 
zbc_inc_wp(struct sdebug_dev_info * devip,unsigned long long lba,unsigned int num)2842f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip,
2843f0d1cf93SDouglas Gilbert 		       unsigned long long lba, unsigned int num)
2844f0d1cf93SDouglas Gilbert {
2845f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
284664e14eceSDamien Le Moal 	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
2847f0d1cf93SDouglas Gilbert 
28484a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
2849f0d1cf93SDouglas Gilbert 		return;
2850f0d1cf93SDouglas Gilbert 
285135dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2852f0d1cf93SDouglas Gilbert 		zsp->z_wp += num;
285364e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2854566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
285564e14eceSDamien Le Moal 		return;
285664e14eceSDamien Le Moal 	}
285764e14eceSDamien Le Moal 
285864e14eceSDamien Le Moal 	while (num) {
285964e14eceSDamien Le Moal 		if (lba != zsp->z_wp)
286064e14eceSDamien Le Moal 			zsp->z_non_seq_resource = true;
286164e14eceSDamien Le Moal 
286264e14eceSDamien Le Moal 		end = lba + num;
286364e14eceSDamien Le Moal 		if (end >= zend) {
286464e14eceSDamien Le Moal 			n = zend - lba;
286564e14eceSDamien Le Moal 			zsp->z_wp = zend;
286664e14eceSDamien Le Moal 		} else if (end > zsp->z_wp) {
286764e14eceSDamien Le Moal 			n = num;
286864e14eceSDamien Le Moal 			zsp->z_wp = end;
286964e14eceSDamien Le Moal 		} else {
287064e14eceSDamien Le Moal 			n = num;
287164e14eceSDamien Le Moal 		}
287264e14eceSDamien Le Moal 		if (zsp->z_wp >= zend)
2873566d3c57SDamien Le Moal 			zbc_set_zone_full(devip, zsp);
287464e14eceSDamien Le Moal 
287564e14eceSDamien Le Moal 		num -= n;
287664e14eceSDamien Le Moal 		lba += n;
287764e14eceSDamien Le Moal 		if (num) {
287864e14eceSDamien Le Moal 			zsp++;
287964e14eceSDamien Le Moal 			zend = zsp->z_start + zsp->z_size;
288064e14eceSDamien Le Moal 		}
288164e14eceSDamien Le Moal 	}
2882f0d1cf93SDouglas Gilbert }
2883f0d1cf93SDouglas Gilbert 
check_zbc_access_params(struct scsi_cmnd * scp,unsigned long long lba,unsigned int num,bool write)2884f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp,
28859447b6ceSMartin K. Petersen 			unsigned long long lba, unsigned int num, bool write)
28861da177e4SLinus Torvalds {
2887f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2888f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2889f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2890f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2891f0d1cf93SDouglas Gilbert 
2892f0d1cf93SDouglas Gilbert 	if (!write) {
289364e14eceSDamien Le Moal 		if (devip->zmodel == BLK_ZONED_HA)
289464e14eceSDamien Le Moal 			return 0;
289564e14eceSDamien Le Moal 		/* For host-managed, reads cannot cross zone types boundaries */
28964a5fc1c6SDamien Le Moal 		if (zsp->z_type != zsp_end->z_type) {
2897f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2898f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2899f0d1cf93SDouglas Gilbert 					READ_INVDATA_ASCQ);
2900f0d1cf93SDouglas Gilbert 			return check_condition_result;
2901f0d1cf93SDouglas Gilbert 		}
2902f0d1cf93SDouglas Gilbert 		return 0;
2903f0d1cf93SDouglas Gilbert 	}
2904f0d1cf93SDouglas Gilbert 
29054a5fc1c6SDamien Le Moal 	/* Writing into a gap zone is not allowed */
29064a5fc1c6SDamien Le Moal 	if (zbc_zone_is_gap(zsp)) {
29074a5fc1c6SDamien Le Moal 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE,
29084a5fc1c6SDamien Le Moal 				ATTEMPT_ACCESS_GAP);
29094a5fc1c6SDamien Le Moal 		return check_condition_result;
29104a5fc1c6SDamien Le Moal 	}
29114a5fc1c6SDamien Le Moal 
2912f0d1cf93SDouglas Gilbert 	/* No restrictions for writes within conventional zones */
2913f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
2914f0d1cf93SDouglas Gilbert 		if (!zbc_zone_is_conv(zsp_end)) {
2915f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2916f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2917f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2918f0d1cf93SDouglas Gilbert 			return check_condition_result;
2919f0d1cf93SDouglas Gilbert 		}
2920f0d1cf93SDouglas Gilbert 		return 0;
2921f0d1cf93SDouglas Gilbert 	}
2922f0d1cf93SDouglas Gilbert 
292335dbe2b9SDamien Le Moal 	if (zsp->z_type == ZBC_ZTYPE_SWR) {
2924f0d1cf93SDouglas Gilbert 		/* Writes cannot cross sequential zone boundaries */
2925f0d1cf93SDouglas Gilbert 		if (zsp_end != zsp) {
2926f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2927f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2928f0d1cf93SDouglas Gilbert 					WRITE_BOUNDARY_ASCQ);
2929f0d1cf93SDouglas Gilbert 			return check_condition_result;
2930f0d1cf93SDouglas Gilbert 		}
2931f0d1cf93SDouglas Gilbert 		/* Cannot write full zones */
2932f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC5_FULL) {
2933f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2934f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
2935f0d1cf93SDouglas Gilbert 			return check_condition_result;
2936f0d1cf93SDouglas Gilbert 		}
2937f0d1cf93SDouglas Gilbert 		/* Writes must be aligned to the zone WP */
2938f0d1cf93SDouglas Gilbert 		if (lba != zsp->z_wp) {
2939f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
2940f0d1cf93SDouglas Gilbert 					LBA_OUT_OF_RANGE,
2941f0d1cf93SDouglas Gilbert 					UNALIGNED_WRITE_ASCQ);
2942f0d1cf93SDouglas Gilbert 			return check_condition_result;
2943f0d1cf93SDouglas Gilbert 		}
294464e14eceSDamien Le Moal 	}
2945f0d1cf93SDouglas Gilbert 
2946f0d1cf93SDouglas Gilbert 	/* Handle implicit open of closed and empty zones */
2947f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2948f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
2949f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open >= devip->max_open) {
2950f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT,
2951f0d1cf93SDouglas Gilbert 					INSUFF_RES_ASC,
2952f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
2953f0d1cf93SDouglas Gilbert 			return check_condition_result;
2954f0d1cf93SDouglas Gilbert 		}
2955f0d1cf93SDouglas Gilbert 		zbc_open_zone(devip, zsp, false);
2956f0d1cf93SDouglas Gilbert 	}
2957f0d1cf93SDouglas Gilbert 
2958f0d1cf93SDouglas Gilbert 	return 0;
2959f0d1cf93SDouglas Gilbert }
2960f0d1cf93SDouglas Gilbert 
check_device_access_params(struct scsi_cmnd * scp,unsigned long long lba,unsigned int num,bool write)2961f0d1cf93SDouglas Gilbert static inline int check_device_access_params
2962f0d1cf93SDouglas Gilbert 			(struct scsi_cmnd *scp, unsigned long long lba,
2963f0d1cf93SDouglas Gilbert 			 unsigned int num, bool write)
2964f0d1cf93SDouglas Gilbert {
2965f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
2966f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2967f0d1cf93SDouglas Gilbert 
2968c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
296922017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
29701da177e4SLinus Torvalds 		return check_condition_result;
29711da177e4SLinus Torvalds 	}
2972c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2973c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
297422017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2975cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2976c65b1445SDouglas Gilbert 		return check_condition_result;
2977c65b1445SDouglas Gilbert 	}
29789447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
29799447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29809447b6ceSMartin K. Petersen 		return check_condition_result;
29819447b6ceSMartin K. Petersen 	}
2982f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
2983f0d1cf93SDouglas Gilbert 		return check_zbc_access_params(scp, lba, num, write);
2984f0d1cf93SDouglas Gilbert 
298519789100SFUJITA Tomonori 	return 0;
298619789100SFUJITA Tomonori }
298719789100SFUJITA Tomonori 
2988b6ff8ca7SDouglas Gilbert /*
2989b6ff8ca7SDouglas Gilbert  * Note: if BUG_ON() fires it usually indicates a problem with the parser
2990b6ff8ca7SDouglas Gilbert  * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2991b6ff8ca7SDouglas Gilbert  * that access any of the "stores" in struct sdeb_store_info should call this
2992b6ff8ca7SDouglas Gilbert  * function with bug_if_fake_rw set to true.
2993b6ff8ca7SDouglas Gilbert  */
devip2sip(struct sdebug_dev_info * devip,bool bug_if_fake_rw)2994b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2995b6ff8ca7SDouglas Gilbert 						bool bug_if_fake_rw)
299687c715dcSDouglas Gilbert {
2997b6ff8ca7SDouglas Gilbert 	if (sdebug_fake_rw) {
2998b6ff8ca7SDouglas Gilbert 		BUG_ON(bug_if_fake_rw);	/* See note above */
2999b6ff8ca7SDouglas Gilbert 		return NULL;
3000b6ff8ca7SDouglas Gilbert 	}
3001b6ff8ca7SDouglas Gilbert 	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
300287c715dcSDouglas Gilbert }
300387c715dcSDouglas Gilbert 
3004a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
do_device_access(struct sdeb_store_info * sip,struct scsi_cmnd * scp,u32 sg_skip,u64 lba,u32 num,bool do_write)300587c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
300687c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
300719789100SFUJITA Tomonori {
300819789100SFUJITA Tomonori 	int ret;
3009c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
3010a4517511SAkinobu Mita 	enum dma_data_direction dir;
301187c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
301287c715dcSDouglas Gilbert 	u8 *fsp;
301319789100SFUJITA Tomonori 
3014c2248fc9SDouglas Gilbert 	if (do_write) {
3015a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
30164f2c8bf6SDouglas Gilbert 		write_since_sync = true;
3017a4517511SAkinobu Mita 	} else {
3018a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
3019a4517511SAkinobu Mita 	}
3020a4517511SAkinobu Mita 
302187c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
3022a4517511SAkinobu Mita 		return 0;
302387c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
3024a4517511SAkinobu Mita 		return -1;
302587c715dcSDouglas Gilbert 	fsp = sip->storep;
302619789100SFUJITA Tomonori 
302719789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
302819789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
302919789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
303019789100SFUJITA Tomonori 
3031386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
303287c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
30330a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
3034773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
3035a4517511SAkinobu Mita 		return ret;
3036a4517511SAkinobu Mita 
3037a4517511SAkinobu Mita 	if (rest) {
3038386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
303987c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
30400a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
30410a7e69c7SDouglas Gilbert 			    do_write);
3042a4517511SAkinobu Mita 	}
304319789100SFUJITA Tomonori 
304419789100SFUJITA Tomonori 	return ret;
304519789100SFUJITA Tomonori }
304619789100SFUJITA Tomonori 
304787c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
do_dout_fetch(struct scsi_cmnd * scp,u32 num,u8 * doutp)304887c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
304987c715dcSDouglas Gilbert {
305087c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
305187c715dcSDouglas Gilbert 
305287c715dcSDouglas Gilbert 	if (!sdb->length)
305387c715dcSDouglas Gilbert 		return 0;
305487c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
305587c715dcSDouglas Gilbert 		return -1;
305687c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
305787c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
305887c715dcSDouglas Gilbert }
305987c715dcSDouglas Gilbert 
306087c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
306187c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
306238d5c833SDouglas Gilbert  * return false. */
comp_write_worker(struct sdeb_store_info * sip,u64 lba,u32 num,const u8 * arr,bool compare_only)306387c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
3064c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
306538d5c833SDouglas Gilbert {
306638d5c833SDouglas Gilbert 	bool res;
306738d5c833SDouglas Gilbert 	u64 block, rest = 0;
306838d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
3069773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
307087c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
307138d5c833SDouglas Gilbert 
307238d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
307338d5c833SDouglas Gilbert 	if (block + num > store_blks)
307438d5c833SDouglas Gilbert 		rest = block + num - store_blks;
307538d5c833SDouglas Gilbert 
307687c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
307738d5c833SDouglas Gilbert 	if (!res)
307838d5c833SDouglas Gilbert 		return res;
307938d5c833SDouglas Gilbert 	if (rest)
308087c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
308138d5c833SDouglas Gilbert 			     rest * lb_size);
308238d5c833SDouglas Gilbert 	if (!res)
308338d5c833SDouglas Gilbert 		return res;
3084c3e2fe92SDouglas Gilbert 	if (compare_only)
3085c3e2fe92SDouglas Gilbert 		return true;
308638d5c833SDouglas Gilbert 	arr += num * lb_size;
308787c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
308838d5c833SDouglas Gilbert 	if (rest)
308987c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
309038d5c833SDouglas Gilbert 	return res;
309138d5c833SDouglas Gilbert }
309238d5c833SDouglas Gilbert 
dif_compute_csum(const void * buf,int len)309351d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
3094beb40ea4SAkinobu Mita {
309551d648afSAkinobu Mita 	__be16 csum;
3096beb40ea4SAkinobu Mita 
3097773642d9SDouglas Gilbert 	if (sdebug_guard)
309851d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
309951d648afSAkinobu Mita 	else
3100beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
310151d648afSAkinobu Mita 
3102beb40ea4SAkinobu Mita 	return csum;
3103beb40ea4SAkinobu Mita }
3104beb40ea4SAkinobu Mita 
dif_verify(struct t10_pi_tuple * sdt,const void * data,sector_t sector,u32 ei_lba)31056ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
3106beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
3107beb40ea4SAkinobu Mita {
3108773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
3109beb40ea4SAkinobu Mita 
3110beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
3111c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
3112beb40ea4SAkinobu Mita 			(unsigned long)sector,
3113beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
3114beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
3115beb40ea4SAkinobu Mita 		return 0x01;
3116beb40ea4SAkinobu Mita 	}
31178475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
3118beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
3119c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3120c1287970STomas Winkler 			(unsigned long)sector);
3121beb40ea4SAkinobu Mita 		return 0x03;
3122beb40ea4SAkinobu Mita 	}
31238475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3124beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
3125c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
3126c1287970STomas Winkler 			(unsigned long)sector);
3127beb40ea4SAkinobu Mita 		return 0x03;
3128beb40ea4SAkinobu Mita 	}
3129beb40ea4SAkinobu Mita 	return 0;
3130beb40ea4SAkinobu Mita }
3131beb40ea4SAkinobu Mita 
dif_copy_prot(struct scsi_cmnd * scp,sector_t sector,unsigned int sectors,bool read)313287c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
313365f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
3134c6a44287SMartin K. Petersen {
3135be4e11beSAkinobu Mita 	size_t resid;
3136c6a44287SMartin K. Petersen 	void *paddr;
313787c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3138b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
313987c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
314014faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
3141be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3142c6a44287SMartin K. Petersen 
3143e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
3144e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
3145c6a44287SMartin K. Petersen 
314687c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
314787c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3148be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
3149be4e11beSAkinobu Mita 
3150be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
315187c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
315287c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
3153be4e11beSAkinobu Mita 		size_t rest = 0;
315414faa944SAkinobu Mita 
315514faa944SAkinobu Mita 		if (dif_store_end < start + len)
315614faa944SAkinobu Mita 			rest = start + len - dif_store_end;
3157c6a44287SMartin K. Petersen 
3158be4e11beSAkinobu Mita 		paddr = miter.addr;
315914faa944SAkinobu Mita 
316065f72f2aSAkinobu Mita 		if (read)
316165f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
316265f72f2aSAkinobu Mita 		else
316365f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
316465f72f2aSAkinobu Mita 
316565f72f2aSAkinobu Mita 		if (rest) {
316665f72f2aSAkinobu Mita 			if (read)
316714faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
316865f72f2aSAkinobu Mita 			else
316965f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
317065f72f2aSAkinobu Mita 		}
3171c6a44287SMartin K. Petersen 
3172e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
3173c6a44287SMartin K. Petersen 		resid -= len;
3174c6a44287SMartin K. Petersen 	}
3175be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3176bb8c063cSAkinobu Mita }
3177c6a44287SMartin K. Petersen 
prot_verify_read(struct scsi_cmnd * scp,sector_t start_sec,unsigned int sectors,u32 ei_lba)317887c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
3179bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
3180bb8c063cSAkinobu Mita {
3181f7be6772SMartin K. Petersen 	int ret = 0;
3182bb8c063cSAkinobu Mita 	unsigned int i;
3183bb8c063cSAkinobu Mita 	sector_t sector;
318487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3185b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
318687c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
3187bb8c063cSAkinobu Mita 
3188c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
3189bb8c063cSAkinobu Mita 		sector = start_sec + i;
319087c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
3191bb8c063cSAkinobu Mita 
319251d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
3193bb8c063cSAkinobu Mita 			continue;
3194bb8c063cSAkinobu Mita 
3195f7be6772SMartin K. Petersen 		/*
3196f7be6772SMartin K. Petersen 		 * Because scsi_debug acts as both initiator and
3197f7be6772SMartin K. Petersen 		 * target we proceed to verify the PI even if
3198f7be6772SMartin K. Petersen 		 * RDPROTECT=3. This is done so the "initiator" knows
3199f7be6772SMartin K. Petersen 		 * which type of error to return. Otherwise we would
3200f7be6772SMartin K. Petersen 		 * have to iterate over the PI twice.
3201f7be6772SMartin K. Petersen 		 */
3202f7be6772SMartin K. Petersen 		if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3203f7be6772SMartin K. Petersen 			ret = dif_verify(sdt, lba2fake_store(sip, sector),
3204f7be6772SMartin K. Petersen 					 sector, ei_lba);
3205bb8c063cSAkinobu Mita 			if (ret) {
3206bb8c063cSAkinobu Mita 				dif_errors++;
3207f7be6772SMartin K. Petersen 				break;
3208f7be6772SMartin K. Petersen 			}
3209bb8c063cSAkinobu Mita 		}
3210bb8c063cSAkinobu Mita 	}
3211bb8c063cSAkinobu Mita 
321287c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
3213c6a44287SMartin K. Petersen 	dix_reads++;
3214c6a44287SMartin K. Petersen 
3215f7be6772SMartin K. Petersen 	return ret;
3216c6a44287SMartin K. Petersen }
3217c6a44287SMartin K. Petersen 
32187109f370SDouglas Gilbert static inline void
sdeb_read_lock(struct sdeb_store_info * sip)32197109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip)
32207109f370SDouglas Gilbert {
3221e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3222e9c47801SDamien Le Moal 		if (sip)
3223e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3224e9c47801SDamien Le Moal 		else
3225e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3226e9c47801SDamien Le Moal 	} else {
32277109f370SDouglas Gilbert 		if (sip)
32287109f370SDouglas Gilbert 			read_lock(&sip->macc_lck);
32297109f370SDouglas Gilbert 		else
32307109f370SDouglas Gilbert 			read_lock(&sdeb_fake_rw_lck);
32317109f370SDouglas Gilbert 	}
3232e9c47801SDamien Le Moal }
32337109f370SDouglas Gilbert 
32347109f370SDouglas Gilbert static inline void
sdeb_read_unlock(struct sdeb_store_info * sip)32357109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip)
32367109f370SDouglas Gilbert {
3237e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3238e9c47801SDamien Le Moal 		if (sip)
3239e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3240e9c47801SDamien Le Moal 		else
3241e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3242e9c47801SDamien Le Moal 	} else {
32437109f370SDouglas Gilbert 		if (sip)
32447109f370SDouglas Gilbert 			read_unlock(&sip->macc_lck);
32457109f370SDouglas Gilbert 		else
32467109f370SDouglas Gilbert 			read_unlock(&sdeb_fake_rw_lck);
32477109f370SDouglas Gilbert 	}
3248e9c47801SDamien Le Moal }
32497109f370SDouglas Gilbert 
32507109f370SDouglas Gilbert static inline void
sdeb_write_lock(struct sdeb_store_info * sip)32517109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip)
32527109f370SDouglas Gilbert {
3253e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3254e9c47801SDamien Le Moal 		if (sip)
3255e9c47801SDamien Le Moal 			__acquire(&sip->macc_lck);
3256e9c47801SDamien Le Moal 		else
3257e9c47801SDamien Le Moal 			__acquire(&sdeb_fake_rw_lck);
3258e9c47801SDamien Le Moal 	} else {
32597109f370SDouglas Gilbert 		if (sip)
32607109f370SDouglas Gilbert 			write_lock(&sip->macc_lck);
32617109f370SDouglas Gilbert 		else
32627109f370SDouglas Gilbert 			write_lock(&sdeb_fake_rw_lck);
32637109f370SDouglas Gilbert 	}
3264e9c47801SDamien Le Moal }
32657109f370SDouglas Gilbert 
32667109f370SDouglas Gilbert static inline void
sdeb_write_unlock(struct sdeb_store_info * sip)32677109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip)
32687109f370SDouglas Gilbert {
3269e9c47801SDamien Le Moal 	if (sdebug_no_rwlock) {
3270e9c47801SDamien Le Moal 		if (sip)
3271e9c47801SDamien Le Moal 			__release(&sip->macc_lck);
3272e9c47801SDamien Le Moal 		else
3273e9c47801SDamien Le Moal 			__release(&sdeb_fake_rw_lck);
3274e9c47801SDamien Le Moal 	} else {
32757109f370SDouglas Gilbert 		if (sip)
32767109f370SDouglas Gilbert 			write_unlock(&sip->macc_lck);
32777109f370SDouglas Gilbert 		else
32787109f370SDouglas Gilbert 			write_unlock(&sdeb_fake_rw_lck);
32797109f370SDouglas Gilbert 	}
3280e9c47801SDamien Le Moal }
32817109f370SDouglas Gilbert 
resp_read_dt0(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)3282fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
328319789100SFUJITA Tomonori {
328487c715dcSDouglas Gilbert 	bool check_prot;
3285c2248fc9SDouglas Gilbert 	u32 num;
3286c2248fc9SDouglas Gilbert 	u32 ei_lba;
328719789100SFUJITA Tomonori 	int ret;
328887c715dcSDouglas Gilbert 	u64 lba;
3289b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
329087c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
329119789100SFUJITA Tomonori 
3292c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3293c2248fc9SDouglas Gilbert 	case READ_16:
3294c2248fc9SDouglas Gilbert 		ei_lba = 0;
3295c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3296c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3297c2248fc9SDouglas Gilbert 		check_prot = true;
3298c2248fc9SDouglas Gilbert 		break;
3299c2248fc9SDouglas Gilbert 	case READ_10:
3300c2248fc9SDouglas Gilbert 		ei_lba = 0;
3301c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3302c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3303c2248fc9SDouglas Gilbert 		check_prot = true;
3304c2248fc9SDouglas Gilbert 		break;
3305c2248fc9SDouglas Gilbert 	case READ_6:
3306c2248fc9SDouglas Gilbert 		ei_lba = 0;
3307c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3308c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3309c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3310c2248fc9SDouglas Gilbert 		check_prot = true;
3311c2248fc9SDouglas Gilbert 		break;
3312c2248fc9SDouglas Gilbert 	case READ_12:
3313c2248fc9SDouglas Gilbert 		ei_lba = 0;
3314c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3315c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3316c2248fc9SDouglas Gilbert 		check_prot = true;
3317c2248fc9SDouglas Gilbert 		break;
3318c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
3319c2248fc9SDouglas Gilbert 		ei_lba = 0;
3320c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3321c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3322c2248fc9SDouglas Gilbert 		check_prot = false;
3323c2248fc9SDouglas Gilbert 		break;
3324c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
3325c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3326c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3327c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3328c2248fc9SDouglas Gilbert 		check_prot = false;
3329c2248fc9SDouglas Gilbert 		break;
3330c2248fc9SDouglas Gilbert 	}
3331f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
33328475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3333c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3334c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3335c2248fc9SDouglas Gilbert 			return check_condition_result;
3336c2248fc9SDouglas Gilbert 		}
33378475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
33388475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3339c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3340c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3341c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3342c2248fc9SDouglas Gilbert 	}
33433a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
33443a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
3345c2248fc9SDouglas Gilbert 		num /= 2;
33463a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 0);
3347c2248fc9SDouglas Gilbert 	}
3348c2248fc9SDouglas Gilbert 
33499447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
33509447b6ceSMartin K. Petersen 	if (ret)
33519447b6ceSMartin K. Petersen 		return ret;
3352f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
3353d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3354d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
3355c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
3356c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
3357c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
3358c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3359c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
336032f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
336132f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
3362c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
3363c65b1445SDouglas Gilbert 		}
3364c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
33651da177e4SLinus Torvalds 		return check_condition_result;
33661da177e4SLinus Torvalds 	}
3367c6a44287SMartin K. Petersen 
33687109f370SDouglas Gilbert 	sdeb_read_lock(sip);
33696c78cc06SAkinobu Mita 
3370c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3371f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3372f7be6772SMartin K. Petersen 		switch (prot_verify_read(scp, lba, num, ei_lba)) {
3373f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3374f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33757109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3376f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3377f7be6772SMartin K. Petersen 				return check_condition_result;
3378f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
33797109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3380f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3381c6a44287SMartin K. Petersen 				return illegal_condition_result;
3382c6a44287SMartin K. Petersen 			}
3383f7be6772SMartin K. Petersen 			break;
3384f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3385f7be6772SMartin K. Petersen 			if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
33867109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3387f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3388f7be6772SMartin K. Petersen 				return check_condition_result;
3389f7be6772SMartin K. Petersen 			} else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
33907109f370SDouglas Gilbert 				sdeb_read_unlock(sip);
3391f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3392f7be6772SMartin K. Petersen 				return illegal_condition_result;
3393f7be6772SMartin K. Petersen 			}
3394f7be6772SMartin K. Petersen 			break;
3395f7be6772SMartin K. Petersen 		}
3396c6a44287SMartin K. Petersen 	}
3397c6a44287SMartin K. Petersen 
339887c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
33997109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
3400f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
3401a4517511SAkinobu Mita 		return DID_ERROR << 16;
3402a4517511SAkinobu Mita 
340342d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
3404a4517511SAkinobu Mita 
34053a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
34063a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
34073a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
34083a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
34093a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3410c2248fc9SDouglas Gilbert 			return check_condition_result;
34113a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3412c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3413c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
34143a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3415c2248fc9SDouglas Gilbert 			return illegal_condition_result;
34163a90a63dSDouglas Gilbert 		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
3417c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
34183a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3419c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3420c2248fc9SDouglas Gilbert 		}
3421c2248fc9SDouglas Gilbert 	}
3422a4517511SAkinobu Mita 	return 0;
34231da177e4SLinus Torvalds }
34241da177e4SLinus Torvalds 
prot_verify_write(struct scsi_cmnd * SCpnt,sector_t start_sec,unsigned int sectors,u32 ei_lba)3425c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
3426395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
3427c6a44287SMartin K. Petersen {
3428be4e11beSAkinobu Mita 	int ret;
34296ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
3430be4e11beSAkinobu Mita 	void *daddr;
343165f72f2aSAkinobu Mita 	sector_t sector = start_sec;
3432c6a44287SMartin K. Petersen 	int ppage_offset;
3433be4e11beSAkinobu Mita 	int dpage_offset;
3434be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
3435be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
3436c6a44287SMartin K. Petersen 
3437c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
3438c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3439c6a44287SMartin K. Petersen 
3440be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3441be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
3442be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3443be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3444be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3445c6a44287SMartin K. Petersen 
3446be4e11beSAkinobu Mita 	/* For each protection page */
3447be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
3448be4e11beSAkinobu Mita 		dpage_offset = 0;
3449be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
3450be4e11beSAkinobu Mita 			ret = 0x01;
3451be4e11beSAkinobu Mita 			goto out;
3452c6a44287SMartin K. Petersen 		}
3453c6a44287SMartin K. Petersen 
3454be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
34556ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
3456be4e11beSAkinobu Mita 			/* If we're at the end of the current
3457be4e11beSAkinobu Mita 			 * data page advance to the next one
3458be4e11beSAkinobu Mita 			 */
3459be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
3460be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
3461be4e11beSAkinobu Mita 					ret = 0x01;
3462be4e11beSAkinobu Mita 					goto out;
3463be4e11beSAkinobu Mita 				}
3464be4e11beSAkinobu Mita 				dpage_offset = 0;
3465be4e11beSAkinobu Mita 			}
3466c6a44287SMartin K. Petersen 
3467be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
3468be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
3469be4e11beSAkinobu Mita 
3470f7be6772SMartin K. Petersen 			if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3471be4e11beSAkinobu Mita 				ret = dif_verify(sdt, daddr, sector, ei_lba);
3472c78be80dSMartin K. Petersen 				if (ret)
3473395cef03SMartin K. Petersen 					goto out;
3474395cef03SMartin K. Petersen 			}
3475395cef03SMartin K. Petersen 
3476c6a44287SMartin K. Petersen 			sector++;
3477395cef03SMartin K. Petersen 			ei_lba++;
3478773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
3479c6a44287SMartin K. Petersen 		}
3480be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
3481be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
3482c6a44287SMartin K. Petersen 	}
3483be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3484c6a44287SMartin K. Petersen 
348565f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
3486c6a44287SMartin K. Petersen 	dix_writes++;
3487c6a44287SMartin K. Petersen 
3488c6a44287SMartin K. Petersen 	return 0;
3489c6a44287SMartin K. Petersen 
3490c6a44287SMartin K. Petersen out:
3491c6a44287SMartin K. Petersen 	dif_errors++;
3492be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
3493be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
3494c6a44287SMartin K. Petersen 	return ret;
3495c6a44287SMartin K. Petersen }
3496c6a44287SMartin K. Petersen 
lba_to_map_index(sector_t lba)3497b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
3498b90ebc3dSAkinobu Mita {
3499773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3500773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3501773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
3502b90ebc3dSAkinobu Mita 	return lba;
3503b90ebc3dSAkinobu Mita }
3504b90ebc3dSAkinobu Mita 
map_index_to_lba(unsigned long index)3505b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
3506b90ebc3dSAkinobu Mita {
3507773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
3508a027b5b9SAkinobu Mita 
3509773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
3510773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
3511a027b5b9SAkinobu Mita 	return lba;
3512a027b5b9SAkinobu Mita }
3513a027b5b9SAkinobu Mita 
map_state(struct sdeb_store_info * sip,sector_t lba,unsigned int * num)351487c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
351587c715dcSDouglas Gilbert 			      unsigned int *num)
351644d92694SMartin K. Petersen {
3517b90ebc3dSAkinobu Mita 	sector_t end;
3518b90ebc3dSAkinobu Mita 	unsigned int mapped;
3519b90ebc3dSAkinobu Mita 	unsigned long index;
3520b90ebc3dSAkinobu Mita 	unsigned long next;
352144d92694SMartin K. Petersen 
3522b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
352387c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
352444d92694SMartin K. Petersen 
352544d92694SMartin K. Petersen 	if (mapped)
352687c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
352744d92694SMartin K. Petersen 	else
352887c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
352944d92694SMartin K. Petersen 
3530b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
353144d92694SMartin K. Petersen 	*num = end - lba;
353244d92694SMartin K. Petersen 	return mapped;
353344d92694SMartin K. Petersen }
353444d92694SMartin K. Petersen 
map_region(struct sdeb_store_info * sip,sector_t lba,unsigned int len)353587c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
353687c715dcSDouglas Gilbert 		       unsigned int len)
353744d92694SMartin K. Petersen {
353844d92694SMartin K. Petersen 	sector_t end = lba + len;
353944d92694SMartin K. Petersen 
354044d92694SMartin K. Petersen 	while (lba < end) {
3541b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
354244d92694SMartin K. Petersen 
3543b90ebc3dSAkinobu Mita 		if (index < map_size)
354487c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
354544d92694SMartin K. Petersen 
3546b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
354744d92694SMartin K. Petersen 	}
354844d92694SMartin K. Petersen }
354944d92694SMartin K. Petersen 
unmap_region(struct sdeb_store_info * sip,sector_t lba,unsigned int len)355087c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
355187c715dcSDouglas Gilbert 			 unsigned int len)
355244d92694SMartin K. Petersen {
355344d92694SMartin K. Petersen 	sector_t end = lba + len;
355487c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
355544d92694SMartin K. Petersen 
355644d92694SMartin K. Petersen 	while (lba < end) {
3557b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
355844d92694SMartin K. Petersen 
3559b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3560773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3561b90ebc3dSAkinobu Mita 		    index < map_size) {
356287c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3563760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
356487c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3565760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3566773642d9SDouglas Gilbert 				       sdebug_sector_size *
3567773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3568be1dd78dSEric Sandeen 			}
356987c715dcSDouglas Gilbert 			if (sip->dif_storep) {
357087c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
357187c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3572773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3573e9926b43SAkinobu Mita 			}
3574b90ebc3dSAkinobu Mita 		}
3575b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
357644d92694SMartin K. Petersen 	}
357744d92694SMartin K. Petersen }
357844d92694SMartin K. Petersen 
resp_write_dt0(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)3579fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
35801da177e4SLinus Torvalds {
358187c715dcSDouglas Gilbert 	bool check_prot;
3582c2248fc9SDouglas Gilbert 	u32 num;
3583c2248fc9SDouglas Gilbert 	u32 ei_lba;
358419789100SFUJITA Tomonori 	int ret;
358587c715dcSDouglas Gilbert 	u64 lba;
3586b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
358787c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
35881da177e4SLinus Torvalds 
3589c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3590c2248fc9SDouglas Gilbert 	case WRITE_16:
3591c2248fc9SDouglas Gilbert 		ei_lba = 0;
3592c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3593c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3594c2248fc9SDouglas Gilbert 		check_prot = true;
3595c2248fc9SDouglas Gilbert 		break;
3596c2248fc9SDouglas Gilbert 	case WRITE_10:
3597c2248fc9SDouglas Gilbert 		ei_lba = 0;
3598c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3599c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3600c2248fc9SDouglas Gilbert 		check_prot = true;
3601c2248fc9SDouglas Gilbert 		break;
3602c2248fc9SDouglas Gilbert 	case WRITE_6:
3603c2248fc9SDouglas Gilbert 		ei_lba = 0;
3604c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3605c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3606c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3607c2248fc9SDouglas Gilbert 		check_prot = true;
3608c2248fc9SDouglas Gilbert 		break;
3609c2248fc9SDouglas Gilbert 	case WRITE_12:
3610c2248fc9SDouglas Gilbert 		ei_lba = 0;
3611c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3612c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3613c2248fc9SDouglas Gilbert 		check_prot = true;
3614c2248fc9SDouglas Gilbert 		break;
3615c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3616c2248fc9SDouglas Gilbert 		ei_lba = 0;
3617c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3618c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3619c2248fc9SDouglas Gilbert 		check_prot = false;
3620c2248fc9SDouglas Gilbert 		break;
3621c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3622c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3623c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3624c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3625c2248fc9SDouglas Gilbert 		check_prot = false;
3626c2248fc9SDouglas Gilbert 		break;
3627c2248fc9SDouglas Gilbert 	}
3628f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
36298475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3630c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3631c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3632c2248fc9SDouglas Gilbert 			return check_condition_result;
3633c2248fc9SDouglas Gilbert 		}
36348475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
36358475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3636c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3637c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3638c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3639c2248fc9SDouglas Gilbert 	}
3640f0d1cf93SDouglas Gilbert 
36417109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3642f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3643f0d1cf93SDouglas Gilbert 	if (ret) {
36447109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3645f0d1cf93SDouglas Gilbert 		return ret;
3646f0d1cf93SDouglas Gilbert 	}
36476c78cc06SAkinobu Mita 
3648c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3649f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3650f7be6772SMartin K. Petersen 		switch (prot_verify_write(scp, lba, num, ei_lba)) {
3651f7be6772SMartin K. Petersen 		case 1: /* Guard tag error */
3652f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
36537109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3654f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3655c6a44287SMartin K. Petersen 				return illegal_condition_result;
3656f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36577109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3658f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3659f7be6772SMartin K. Petersen 				return check_condition_result;
3660f7be6772SMartin K. Petersen 			}
3661f7be6772SMartin K. Petersen 			break;
3662f7be6772SMartin K. Petersen 		case 3: /* Reference tag error */
3663f7be6772SMartin K. Petersen 			if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
36647109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3665f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3666f7be6772SMartin K. Petersen 				return illegal_condition_result;
3667f7be6772SMartin K. Petersen 			} else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
36687109f370SDouglas Gilbert 				sdeb_write_unlock(sip);
3669f7be6772SMartin K. Petersen 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3670f7be6772SMartin K. Petersen 				return check_condition_result;
3671f7be6772SMartin K. Petersen 			}
3672f7be6772SMartin K. Petersen 			break;
3673c6a44287SMartin K. Petersen 		}
3674c6a44287SMartin K. Petersen 	}
3675c6a44287SMartin K. Petersen 
367687c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3677f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
367887c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3679f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3680f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3681f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
36827109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3683f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3684773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3685c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3686c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3687c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3688cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3689773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
369044d92694SMartin K. Petersen 
36913a90a63dSDouglas Gilbert 	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36923a90a63dSDouglas Gilbert 		     atomic_read(&sdeb_inject_pending))) {
36933a90a63dSDouglas Gilbert 		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36943a90a63dSDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36953a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3696c2248fc9SDouglas Gilbert 			return check_condition_result;
36973a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3698c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
3699c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37003a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3701c2248fc9SDouglas Gilbert 			return illegal_condition_result;
37023a90a63dSDouglas Gilbert 		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3703c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37043a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
3705c2248fc9SDouglas Gilbert 			return illegal_condition_result;
3706c2248fc9SDouglas Gilbert 		}
3707c2248fc9SDouglas Gilbert 	}
37081da177e4SLinus Torvalds 	return 0;
37091da177e4SLinus Torvalds }
37101da177e4SLinus Torvalds 
3711481b5e5cSDouglas Gilbert /*
3712481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3713481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3714481b5e5cSDouglas Gilbert  */
resp_write_scat(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)3715481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3716481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3717481b5e5cSDouglas Gilbert {
3718481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3719481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3720481b5e5cSDouglas Gilbert 	u8 *up;
3721b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
3722481b5e5cSDouglas Gilbert 	u8 wrprotect;
3723481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3724481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3725481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3726481b5e5cSDouglas Gilbert 	u32 ei_lba;
3727481b5e5cSDouglas Gilbert 	u64 lba;
3728481b5e5cSDouglas Gilbert 	int ret, res;
3729481b5e5cSDouglas Gilbert 	bool is_16;
3730481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3731481b5e5cSDouglas Gilbert 
3732481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3733481b5e5cSDouglas Gilbert 		is_16 = false;
3734481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3735481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3736481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3737481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3738481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3739481b5e5cSDouglas Gilbert 		is_16 = true;
3740481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3741481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3742481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3743481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3744481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3745481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3746481b5e5cSDouglas Gilbert 			    wrprotect) {
3747481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3748481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3749481b5e5cSDouglas Gilbert 			}
3750481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3751481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3752481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3753481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3754481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3755481b5e5cSDouglas Gilbert 		}
3756481b5e5cSDouglas Gilbert 	}
3757481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3758481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3759481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3760481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3761481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3762481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3763481b5e5cSDouglas Gilbert 				my_name, __func__);
3764481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3765481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3766481b5e5cSDouglas Gilbert 	}
3767481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3768481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3769481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3770481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3771481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3772481b5e5cSDouglas Gilbert 				my_name, __func__);
3773481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3774481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3775481b5e5cSDouglas Gilbert 	}
3776216e1797SHarshit Mogalapalli 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN);
3777481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3778481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3779481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3780481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3781481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3782481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3783481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3784481b5e5cSDouglas Gilbert 	if (res == -1) {
3785481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3786481b5e5cSDouglas Gilbert 		goto err_out;
3787481b5e5cSDouglas Gilbert 	}
3788481b5e5cSDouglas Gilbert 
37897109f370SDouglas Gilbert 	sdeb_write_lock(sip);
3790481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3791481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3792481b5e5cSDouglas Gilbert 	cum_lb = 0;
3793481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3794481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3795481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3796481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3797481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3798481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3799481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3800481b5e5cSDouglas Gilbert 		if (num == 0)
3801481b5e5cSDouglas Gilbert 			continue;
38029447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3803481b5e5cSDouglas Gilbert 		if (ret)
3804481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3805481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3806481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3807481b5e5cSDouglas Gilbert 
3808481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3809481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3810481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3811481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3812481b5e5cSDouglas Gilbert 				    my_name, __func__);
3813481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3814481b5e5cSDouglas Gilbert 					0);
3815481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3816481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3817481b5e5cSDouglas Gilbert 		}
3818481b5e5cSDouglas Gilbert 
3819481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3820481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3821481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3822481b5e5cSDouglas Gilbert 							 ei_lba);
3823481b5e5cSDouglas Gilbert 
3824481b5e5cSDouglas Gilbert 			if (prot_ret) {
3825481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3826481b5e5cSDouglas Gilbert 						prot_ret);
3827481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3828481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3829481b5e5cSDouglas Gilbert 			}
3830481b5e5cSDouglas Gilbert 		}
3831481b5e5cSDouglas Gilbert 
383287c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3833f0d1cf93SDouglas Gilbert 		/* If ZBC zone then bump its write pointer */
3834f0d1cf93SDouglas Gilbert 		if (sdebug_dev_is_zoned(devip))
3835f0d1cf93SDouglas Gilbert 			zbc_inc_wp(devip, lba, num);
3836481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
383787c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3838481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3839481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3840481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3841481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3842481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3843481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3844481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3845481b5e5cSDouglas Gilbert 
38463a90a63dSDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
38473a90a63dSDouglas Gilbert 			     atomic_read(&sdeb_inject_pending))) {
38483a90a63dSDouglas Gilbert 			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
38493a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
38503a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
38513a90a63dSDouglas Gilbert 				ret = check_condition_result;
3852481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38533a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3854481b5e5cSDouglas Gilbert 				/* Logical block guard check failed */
38553a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
38563a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3857481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3858481b5e5cSDouglas Gilbert 				goto err_out_unlock;
38593a90a63dSDouglas Gilbert 			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
38603a90a63dSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
38613a90a63dSDouglas Gilbert 				atomic_set(&sdeb_inject_pending, 0);
3862481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3863481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3864481b5e5cSDouglas Gilbert 			}
3865481b5e5cSDouglas Gilbert 		}
3866481b5e5cSDouglas Gilbert 		sg_off += num_by;
3867481b5e5cSDouglas Gilbert 		cum_lb += num;
3868481b5e5cSDouglas Gilbert 	}
3869481b5e5cSDouglas Gilbert 	ret = 0;
3870481b5e5cSDouglas Gilbert err_out_unlock:
38717109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
3872481b5e5cSDouglas Gilbert err_out:
3873481b5e5cSDouglas Gilbert 	kfree(lrdp);
3874481b5e5cSDouglas Gilbert 	return ret;
3875481b5e5cSDouglas Gilbert }
3876481b5e5cSDouglas Gilbert 
resp_write_same(struct scsi_cmnd * scp,u64 lba,u32 num,u32 ei_lba,bool unmap,bool ndob)3877fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3878fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
387944d92694SMartin K. Petersen {
3880f0d1cf93SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
3881f0d1cf93SDouglas Gilbert 	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
388244d92694SMartin K. Petersen 	unsigned long long i;
388340d07b52SDouglas Gilbert 	u64 block, lbaa;
388487c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
388587c715dcSDouglas Gilbert 	int ret;
388687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
3887b6ff8ca7SDouglas Gilbert 						scp->device->hostdata, true);
388840d07b52SDouglas Gilbert 	u8 *fs1p;
388987c715dcSDouglas Gilbert 	u8 *fsp;
389044d92694SMartin K. Petersen 
38917109f370SDouglas Gilbert 	sdeb_write_lock(sip);
389244d92694SMartin K. Petersen 
3893f0d1cf93SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num, true);
3894f0d1cf93SDouglas Gilbert 	if (ret) {
38957109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3896f0d1cf93SDouglas Gilbert 		return ret;
3897f0d1cf93SDouglas Gilbert 	}
3898f0d1cf93SDouglas Gilbert 
38999ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
390087c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
390144d92694SMartin K. Petersen 		goto out;
390244d92694SMartin K. Petersen 	}
390340d07b52SDouglas Gilbert 	lbaa = lba;
390440d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3905c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
390687c715dcSDouglas Gilbert 	fsp = sip->storep;
390787c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3908c2248fc9SDouglas Gilbert 	if (ndob) {
390940d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3910c2248fc9SDouglas Gilbert 		ret = 0;
3911c2248fc9SDouglas Gilbert 	} else
391240d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
391344d92694SMartin K. Petersen 
391444d92694SMartin K. Petersen 	if (-1 == ret) {
39157109f370SDouglas Gilbert 		sdeb_write_unlock(sip);
3916773642d9SDouglas Gilbert 		return DID_ERROR << 16;
391740d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3918c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3919e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
392040d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
392144d92694SMartin K. Petersen 
392244d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
392340d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
392440d07b52SDouglas Gilbert 		lbaa = lba + i;
392540d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
392687c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
392740d07b52SDouglas Gilbert 	}
39289ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
392987c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3930f0d1cf93SDouglas Gilbert 	/* If ZBC zone then bump its write pointer */
3931f0d1cf93SDouglas Gilbert 	if (sdebug_dev_is_zoned(devip))
3932f0d1cf93SDouglas Gilbert 		zbc_inc_wp(devip, lba, num);
393344d92694SMartin K. Petersen out:
39347109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
393544d92694SMartin K. Petersen 
393644d92694SMartin K. Petersen 	return 0;
393744d92694SMartin K. Petersen }
393844d92694SMartin K. Petersen 
resp_write_same_10(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)3939fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3940fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3941c2248fc9SDouglas Gilbert {
3942c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3943c2248fc9SDouglas Gilbert 	u32 lba;
3944c2248fc9SDouglas Gilbert 	u16 num;
3945c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3946c2248fc9SDouglas Gilbert 	bool unmap = false;
3947c2248fc9SDouglas Gilbert 
3948c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3949773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3950c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3951c2248fc9SDouglas Gilbert 			return check_condition_result;
3952c2248fc9SDouglas Gilbert 		} else
3953c2248fc9SDouglas Gilbert 			unmap = true;
3954c2248fc9SDouglas Gilbert 	}
3955c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3956c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3957773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3958c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3959c2248fc9SDouglas Gilbert 		return check_condition_result;
3960c2248fc9SDouglas Gilbert 	}
3961c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3962c2248fc9SDouglas Gilbert }
3963c2248fc9SDouglas Gilbert 
resp_write_same_16(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)3964fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3965fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3966c2248fc9SDouglas Gilbert {
3967c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3968c2248fc9SDouglas Gilbert 	u64 lba;
3969c2248fc9SDouglas Gilbert 	u32 num;
3970c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3971c2248fc9SDouglas Gilbert 	bool unmap = false;
3972c2248fc9SDouglas Gilbert 	bool ndob = false;
3973c2248fc9SDouglas Gilbert 
3974c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3975773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3976c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3977c2248fc9SDouglas Gilbert 			return check_condition_result;
3978c2248fc9SDouglas Gilbert 		} else
3979c2248fc9SDouglas Gilbert 			unmap = true;
3980c2248fc9SDouglas Gilbert 	}
3981c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3982c2248fc9SDouglas Gilbert 		ndob = true;
3983c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3984c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3985773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3986c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3987c2248fc9SDouglas Gilbert 		return check_condition_result;
3988c2248fc9SDouglas Gilbert 	}
3989c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3990c2248fc9SDouglas Gilbert }
3991c2248fc9SDouglas Gilbert 
3992acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3993acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3994acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
resp_write_buffer(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)3995fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3996fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3997acafd0b9SEwan D. Milne {
3998acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3999acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
4000acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
4001acafd0b9SEwan D. Milne 	u8 mode;
4002acafd0b9SEwan D. Milne 
4003acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
4004acafd0b9SEwan D. Milne 	switch (mode) {
4005acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
4006acafd0b9SEwan D. Milne 		/* set UAs on this device only */
4007acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4008acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
4009acafd0b9SEwan D. Milne 		break;
4010acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
4011acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
4012acafd0b9SEwan D. Milne 		break;
4013acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
4014acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
4015acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4016acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4017acafd0b9SEwan D. Milne 				    dev_list)
4018acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
4019acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
4020acafd0b9SEwan D. Milne 				if (devip != dp)
4021acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
4022acafd0b9SEwan D. Milne 						dp->uas_bm);
4023acafd0b9SEwan D. Milne 			}
4024acafd0b9SEwan D. Milne 		break;
4025acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
4026acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
4027acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
4028acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
4029acafd0b9SEwan D. Milne 				    dev_list)
4030acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
4031acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
4032acafd0b9SEwan D. Milne 					dp->uas_bm);
4033acafd0b9SEwan D. Milne 		break;
4034acafd0b9SEwan D. Milne 	default:
4035acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
4036acafd0b9SEwan D. Milne 		break;
4037acafd0b9SEwan D. Milne 	}
4038acafd0b9SEwan D. Milne 	return 0;
4039acafd0b9SEwan D. Milne }
4040acafd0b9SEwan D. Milne 
resp_comp_write(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4041fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
4042fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
404338d5c833SDouglas Gilbert {
404438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
404538d5c833SDouglas Gilbert 	u8 *arr;
4046b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
404738d5c833SDouglas Gilbert 	u64 lba;
404838d5c833SDouglas Gilbert 	u32 dnum;
4049773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
405038d5c833SDouglas Gilbert 	u8 num;
405138d5c833SDouglas Gilbert 	int ret;
4052d467d31fSDouglas Gilbert 	int retval = 0;
405338d5c833SDouglas Gilbert 
4054d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
405538d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
405638d5c833SDouglas Gilbert 	if (0 == num)
405738d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
40588475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
405938d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
406038d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
406138d5c833SDouglas Gilbert 		return check_condition_result;
406238d5c833SDouglas Gilbert 	}
40638475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
40648475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
406538d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
406638d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
406738d5c833SDouglas Gilbert 			    "to DIF device\n");
40689447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
40699447b6ceSMartin K. Petersen 	if (ret)
40709447b6ceSMartin K. Petersen 		return ret;
4071d467d31fSDouglas Gilbert 	dnum = 2 * num;
40726396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
4073d467d31fSDouglas Gilbert 	if (NULL == arr) {
4074d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4075d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
4076d467d31fSDouglas Gilbert 		return check_condition_result;
4077d467d31fSDouglas Gilbert 	}
407838d5c833SDouglas Gilbert 
40797109f370SDouglas Gilbert 	sdeb_write_lock(sip);
408038d5c833SDouglas Gilbert 
408187c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
408238d5c833SDouglas Gilbert 	if (ret == -1) {
4083d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
4084d467d31fSDouglas Gilbert 		goto cleanup;
4085773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
408638d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
408738d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
408838d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
4089c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
409038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4091d467d31fSDouglas Gilbert 		retval = check_condition_result;
4092d467d31fSDouglas Gilbert 		goto cleanup;
409338d5c833SDouglas Gilbert 	}
409438d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
409587c715dcSDouglas Gilbert 		map_region(sip, lba, num);
4096d467d31fSDouglas Gilbert cleanup:
40977109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4098d467d31fSDouglas Gilbert 	kfree(arr);
4099d467d31fSDouglas Gilbert 	return retval;
410038d5c833SDouglas Gilbert }
410138d5c833SDouglas Gilbert 
410244d92694SMartin K. Petersen struct unmap_block_desc {
410344d92694SMartin K. Petersen 	__be64	lba;
410444d92694SMartin K. Petersen 	__be32	blocks;
410544d92694SMartin K. Petersen 	__be32	__reserved;
410644d92694SMartin K. Petersen };
410744d92694SMartin K. Petersen 
resp_unmap(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4108fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
410944d92694SMartin K. Petersen {
411044d92694SMartin K. Petersen 	unsigned char *buf;
411144d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
4112b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
411344d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
411444d92694SMartin K. Petersen 	int ret;
411544d92694SMartin K. Petersen 
4116c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
4117c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
4118c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
4119c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
412044d92694SMartin K. Petersen 
412144d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
4122773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
4123c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
412444d92694SMartin K. Petersen 		return check_condition_result;
4125c2248fc9SDouglas Gilbert 	}
412644d92694SMartin K. Petersen 
4127b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
4128c2248fc9SDouglas Gilbert 	if (!buf) {
4129c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4130c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
4131c2248fc9SDouglas Gilbert 		return check_condition_result;
4132c2248fc9SDouglas Gilbert 	}
4133c2248fc9SDouglas Gilbert 
4134c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
413544d92694SMartin K. Petersen 
413644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
413744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
413844d92694SMartin K. Petersen 
413944d92694SMartin K. Petersen 	desc = (void *)&buf[8];
414044d92694SMartin K. Petersen 
41417109f370SDouglas Gilbert 	sdeb_write_lock(sip);
41426c78cc06SAkinobu Mita 
414344d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
414444d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
414544d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
414644d92694SMartin K. Petersen 
41479447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
414844d92694SMartin K. Petersen 		if (ret)
414944d92694SMartin K. Petersen 			goto out;
415044d92694SMartin K. Petersen 
415187c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
415244d92694SMartin K. Petersen 	}
415344d92694SMartin K. Petersen 
415444d92694SMartin K. Petersen 	ret = 0;
415544d92694SMartin K. Petersen 
415644d92694SMartin K. Petersen out:
41577109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
415844d92694SMartin K. Petersen 	kfree(buf);
415944d92694SMartin K. Petersen 
416044d92694SMartin K. Petersen 	return ret;
416144d92694SMartin K. Petersen }
416244d92694SMartin K. Petersen 
416344d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
416444d92694SMartin K. Petersen 
resp_get_lba_status(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4165fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
4166fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
416744d92694SMartin K. Petersen {
4168c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4169c2248fc9SDouglas Gilbert 	u64 lba;
4170c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
417144d92694SMartin K. Petersen 	int ret;
417287c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
417344d92694SMartin K. Petersen 
4174c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
4175c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
417644d92694SMartin K. Petersen 
417744d92694SMartin K. Petersen 	if (alloc_len < 24)
417844d92694SMartin K. Petersen 		return 0;
417944d92694SMartin K. Petersen 
41809447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
418144d92694SMartin K. Petersen 	if (ret)
418244d92694SMartin K. Petersen 		return ret;
418344d92694SMartin K. Petersen 
4184b6ff8ca7SDouglas Gilbert 	if (scsi_debug_lbp()) {
4185b6ff8ca7SDouglas Gilbert 		struct sdeb_store_info *sip = devip2sip(devip, true);
4186b6ff8ca7SDouglas Gilbert 
418787c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
4188b6ff8ca7SDouglas Gilbert 	} else {
4189c2248fc9SDouglas Gilbert 		mapped = 1;
4190c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
4191c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
4192c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
4193c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
4194c2248fc9SDouglas Gilbert 		else
4195c2248fc9SDouglas Gilbert 			num = 0xffffffff;
4196c2248fc9SDouglas Gilbert 	}
419744d92694SMartin K. Petersen 
419844d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
4199c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
4200c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
4201c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
4202c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
420344d92694SMartin K. Petersen 
4204c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
420544d92694SMartin K. Petersen }
420644d92694SMartin K. Petersen 
resp_sync_cache(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)420780c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
420880c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
420980c49563SDouglas Gilbert {
42104f2c8bf6SDouglas Gilbert 	int res = 0;
421180c49563SDouglas Gilbert 	u64 lba;
421280c49563SDouglas Gilbert 	u32 num_blocks;
421380c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
421480c49563SDouglas Gilbert 
421580c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
421680c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
421780c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
421880c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
421980c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
422080c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
422180c49563SDouglas Gilbert 	}
422280c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
422380c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
422480c49563SDouglas Gilbert 		return check_condition_result;
422580c49563SDouglas Gilbert 	}
4226fc13638aSDouglas Gilbert 	if (!write_since_sync || (cmd[1] & 0x2))
42274f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
42284f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
42294f2c8bf6SDouglas Gilbert 		write_since_sync = false;
42304f2c8bf6SDouglas Gilbert 	return res;
423180c49563SDouglas Gilbert }
423280c49563SDouglas Gilbert 
4233ed9f3e25SDouglas Gilbert /*
4234ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
4235ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
4236ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
4237ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
4238ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
4239ed9f3e25SDouglas Gilbert  */
resp_pre_fetch(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4240ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
4241ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
4242ed9f3e25SDouglas Gilbert {
4243ed9f3e25SDouglas Gilbert 	int res = 0;
4244ed9f3e25SDouglas Gilbert 	u64 lba;
4245ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
4246ed9f3e25SDouglas Gilbert 	u32 nblks;
4247ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4248b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4249b6ff8ca7SDouglas Gilbert 	u8 *fsp = sip->storep;
4250ed9f3e25SDouglas Gilbert 
4251ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
4252ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4253ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
4254ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
4255ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4256ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
4257ed9f3e25SDouglas Gilbert 	}
4258ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
4259ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4260ed9f3e25SDouglas Gilbert 		return check_condition_result;
4261ed9f3e25SDouglas Gilbert 	}
4262ed9f3e25SDouglas Gilbert 	if (!fsp)
4263ed9f3e25SDouglas Gilbert 		goto fini;
4264ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
4265ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
4266ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
4267ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
4268ed9f3e25SDouglas Gilbert 
4269ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
42707109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4271ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
4272ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
4273ed9f3e25SDouglas Gilbert 	if (rest)
4274ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
42757109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4276ed9f3e25SDouglas Gilbert fini:
4277ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
4278ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
4279ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
4280ed9f3e25SDouglas Gilbert }
4281ed9f3e25SDouglas Gilbert 
4282fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
4283fb0cc8d1SDouglas Gilbert 
42848d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
42858d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
42868d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
42878d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
42888d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
42898d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
42908d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
42918d039e22SDouglas Gilbert  */
resp_report_luns(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)42921da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
42931da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
42941da177e4SLinus Torvalds {
429501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
42968d039e22SDouglas Gilbert 	unsigned int alloc_len;
42978d039e22SDouglas Gilbert 	unsigned char select_report;
42988d039e22SDouglas Gilbert 	u64 lun;
42998d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
4300fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
43018d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
43028d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
43038d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
43048d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
4305fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
4306fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
4307fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
43081da177e4SLinus Torvalds 
430919c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
43108d039e22SDouglas Gilbert 
43118d039e22SDouglas Gilbert 	select_report = cmd[2];
43128d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
43138d039e22SDouglas Gilbert 
43148d039e22SDouglas Gilbert 	if (alloc_len < 4) {
43158d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
43168d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
43171da177e4SLinus Torvalds 		return check_condition_result;
43181da177e4SLinus Torvalds 	}
43198d039e22SDouglas Gilbert 
43208d039e22SDouglas Gilbert 	switch (select_report) {
43218d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
4322773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43238d039e22SDouglas Gilbert 		wlun_cnt = 0;
43248d039e22SDouglas Gilbert 		break;
43258d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
4326c65b1445SDouglas Gilbert 		lun_cnt = 0;
43278d039e22SDouglas Gilbert 		wlun_cnt = 1;
43288d039e22SDouglas Gilbert 		break;
43298d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
43308d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
43318d039e22SDouglas Gilbert 		wlun_cnt = 1;
43328d039e22SDouglas Gilbert 		break;
43338d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
43348d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
43358d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
43368d039e22SDouglas Gilbert 	default:
43378d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
43388d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
43398d039e22SDouglas Gilbert 		return check_condition_result;
43408d039e22SDouglas Gilbert 	}
43418d039e22SDouglas Gilbert 
43428d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
4343c65b1445SDouglas Gilbert 		--lun_cnt;
43448d039e22SDouglas Gilbert 
43458d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
4346fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
4347fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
43488d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
43498d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
43508d039e22SDouglas Gilbert 
4351fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
43528d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
4353fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4354fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
4355fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
4356fb0cc8d1SDouglas Gilbert 		if (k == 0) {
4357fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
4358fb0cc8d1SDouglas Gilbert 			++lun_p;
4359fb0cc8d1SDouglas Gilbert 			j = 1;
4360fb0cc8d1SDouglas Gilbert 		}
4361fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4362fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4363fb0cc8d1SDouglas Gilbert 				break;
4364fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
4365ad0c7775SDouglas Gilbert 			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4366ad0c7775SDouglas Gilbert 				lun_p->scsi_lun[0] |= 0x40;
4367fb0cc8d1SDouglas Gilbert 		}
4368fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
4369fb0cc8d1SDouglas Gilbert 			break;
4370fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
4371fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4372fb0cc8d1SDouglas Gilbert 		if (res)
4373fb0cc8d1SDouglas Gilbert 			return res;
4374fb0cc8d1SDouglas Gilbert 		off_rsp += n;
4375fb0cc8d1SDouglas Gilbert 	}
4376fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
4377fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4378fb0cc8d1SDouglas Gilbert 		++j;
4379fb0cc8d1SDouglas Gilbert 	}
4380fb0cc8d1SDouglas Gilbert 	if (j > 0)
4381fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
43828d039e22SDouglas Gilbert 	return res;
43831da177e4SLinus Torvalds }
43841da177e4SLinus Torvalds 
resp_verify(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4385c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4386c3e2fe92SDouglas Gilbert {
4387c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
4388c3e2fe92SDouglas Gilbert 	u8 bytchk;
4389c3e2fe92SDouglas Gilbert 	int ret, j;
4390c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
4391c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
4392c3e2fe92SDouglas Gilbert 	u64 lba;
4393c3e2fe92SDouglas Gilbert 	u8 *arr;
4394c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4395b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, true);
4396c3e2fe92SDouglas Gilbert 
4397c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
4398c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
4399c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
4400c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
4401c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4402c3e2fe92SDouglas Gilbert 		return check_condition_result;
4403c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
4404c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
4405c3e2fe92SDouglas Gilbert 	}
4406c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
4407c3e2fe92SDouglas Gilbert 	case VERIFY_16:
4408c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
4409c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
4410c3e2fe92SDouglas Gilbert 		break;
4411c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
4412c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
4413c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
4414c3e2fe92SDouglas Gilbert 		break;
4415c3e2fe92SDouglas Gilbert 	default:
4416c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4417c3e2fe92SDouglas Gilbert 		return check_condition_result;
4418c3e2fe92SDouglas Gilbert 	}
44193344b58bSGeorge Kennedy 	if (vnum == 0)
44203344b58bSGeorge Kennedy 		return 0;	/* not an error */
4421c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
4422c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
4423c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
4424c3e2fe92SDouglas Gilbert 	if (ret)
4425c3e2fe92SDouglas Gilbert 		return ret;
4426c3e2fe92SDouglas Gilbert 
4427ed0f17b7SHarshit Mogalapalli 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN);
4428c3e2fe92SDouglas Gilbert 	if (!arr) {
4429c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4430c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
4431c3e2fe92SDouglas Gilbert 		return check_condition_result;
4432c3e2fe92SDouglas Gilbert 	}
4433c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
44347109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4435c3e2fe92SDouglas Gilbert 
4436c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
4437c3e2fe92SDouglas Gilbert 	if (ret == -1) {
4438c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
4439c3e2fe92SDouglas Gilbert 		goto cleanup;
4440c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4441c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
4442c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4443c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
4444c3e2fe92SDouglas Gilbert 	}
4445c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
4446c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4447c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
4448c3e2fe92SDouglas Gilbert 	}
4449c3e2fe92SDouglas Gilbert 	ret = 0;
4450c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4451c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4452c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
4453c3e2fe92SDouglas Gilbert 		goto cleanup;
4454c3e2fe92SDouglas Gilbert 	}
4455c3e2fe92SDouglas Gilbert cleanup:
44567109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4457c3e2fe92SDouglas Gilbert 	kfree(arr);
4458c3e2fe92SDouglas Gilbert 	return ret;
4459c3e2fe92SDouglas Gilbert }
4460c3e2fe92SDouglas Gilbert 
4461f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64
4462f0d1cf93SDouglas Gilbert 
4463897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */
resp_report_zones(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4464f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp,
4465f0d1cf93SDouglas Gilbert 			     struct sdebug_dev_info *devip)
4466f0d1cf93SDouglas Gilbert {
44674a5fc1c6SDamien Le Moal 	unsigned int rep_max_zones, nrz = 0;
4468f0d1cf93SDouglas Gilbert 	int ret = 0;
4469f0d1cf93SDouglas Gilbert 	u32 alloc_len, rep_opts, rep_len;
4470f0d1cf93SDouglas Gilbert 	bool partial;
4471f0d1cf93SDouglas Gilbert 	u64 lba, zs_lba;
4472f0d1cf93SDouglas Gilbert 	u8 *arr = NULL, *desc;
4473f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
44744a5fc1c6SDamien Le Moal 	struct sdeb_zone_state *zsp = NULL;
4475b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4476f0d1cf93SDouglas Gilbert 
4477f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4478f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4479f0d1cf93SDouglas Gilbert 		return check_condition_result;
4480f0d1cf93SDouglas Gilbert 	}
4481f0d1cf93SDouglas Gilbert 	zs_lba = get_unaligned_be64(cmd + 2);
4482f0d1cf93SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
44833344b58bSGeorge Kennedy 	if (alloc_len == 0)
44843344b58bSGeorge Kennedy 		return 0;	/* not an error */
4485f0d1cf93SDouglas Gilbert 	rep_opts = cmd[14] & 0x3f;
4486f0d1cf93SDouglas Gilbert 	partial = cmd[14] & 0x80;
4487f0d1cf93SDouglas Gilbert 
4488f0d1cf93SDouglas Gilbert 	if (zs_lba >= sdebug_capacity) {
4489f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4490f0d1cf93SDouglas Gilbert 		return check_condition_result;
4491f0d1cf93SDouglas Gilbert 	}
4492f0d1cf93SDouglas Gilbert 
44934a5fc1c6SDamien Le Moal 	rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
4494f0d1cf93SDouglas Gilbert 
449507f2ca13SHarshit Mogalapalli 	arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
4496f0d1cf93SDouglas Gilbert 	if (!arr) {
4497f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4498f0d1cf93SDouglas Gilbert 				INSUFF_RES_ASCQ);
4499f0d1cf93SDouglas Gilbert 		return check_condition_result;
4500f0d1cf93SDouglas Gilbert 	}
4501f0d1cf93SDouglas Gilbert 
45027109f370SDouglas Gilbert 	sdeb_read_lock(sip);
4503f0d1cf93SDouglas Gilbert 
4504f0d1cf93SDouglas Gilbert 	desc = arr + 64;
45054a5fc1c6SDamien Le Moal 	for (lba = zs_lba; lba < sdebug_capacity;
45064a5fc1c6SDamien Le Moal 	     lba = zsp->z_start + zsp->z_size) {
45074a5fc1c6SDamien Le Moal 		if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba))
4508f0d1cf93SDouglas Gilbert 			break;
4509f0d1cf93SDouglas Gilbert 		zsp = zbc_zone(devip, lba);
4510f0d1cf93SDouglas Gilbert 		switch (rep_opts) {
4511f0d1cf93SDouglas Gilbert 		case 0x00:
4512f0d1cf93SDouglas Gilbert 			/* All zones */
4513f0d1cf93SDouglas Gilbert 			break;
4514f0d1cf93SDouglas Gilbert 		case 0x01:
4515f0d1cf93SDouglas Gilbert 			/* Empty zones */
4516f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC1_EMPTY)
4517f0d1cf93SDouglas Gilbert 				continue;
4518f0d1cf93SDouglas Gilbert 			break;
4519f0d1cf93SDouglas Gilbert 		case 0x02:
4520f0d1cf93SDouglas Gilbert 			/* Implicit open zones */
4521f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4522f0d1cf93SDouglas Gilbert 				continue;
4523f0d1cf93SDouglas Gilbert 			break;
4524f0d1cf93SDouglas Gilbert 		case 0x03:
4525f0d1cf93SDouglas Gilbert 			/* Explicit open zones */
4526f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4527f0d1cf93SDouglas Gilbert 				continue;
4528f0d1cf93SDouglas Gilbert 			break;
4529f0d1cf93SDouglas Gilbert 		case 0x04:
4530f0d1cf93SDouglas Gilbert 			/* Closed zones */
4531f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC4_CLOSED)
4532f0d1cf93SDouglas Gilbert 				continue;
4533f0d1cf93SDouglas Gilbert 			break;
4534f0d1cf93SDouglas Gilbert 		case 0x05:
4535f0d1cf93SDouglas Gilbert 			/* Full zones */
4536f0d1cf93SDouglas Gilbert 			if (zsp->z_cond != ZC5_FULL)
4537f0d1cf93SDouglas Gilbert 				continue;
4538f0d1cf93SDouglas Gilbert 			break;
4539f0d1cf93SDouglas Gilbert 		case 0x06:
4540f0d1cf93SDouglas Gilbert 		case 0x07:
4541f0d1cf93SDouglas Gilbert 		case 0x10:
4542f0d1cf93SDouglas Gilbert 			/*
454364e14eceSDamien Le Moal 			 * Read-only, offline, reset WP recommended are
454464e14eceSDamien Le Moal 			 * not emulated: no zones to report;
4545f0d1cf93SDouglas Gilbert 			 */
4546f0d1cf93SDouglas Gilbert 			continue;
454764e14eceSDamien Le Moal 		case 0x11:
454864e14eceSDamien Le Moal 			/* non-seq-resource set */
454964e14eceSDamien Le Moal 			if (!zsp->z_non_seq_resource)
455064e14eceSDamien Le Moal 				continue;
455164e14eceSDamien Le Moal 			break;
45524a5fc1c6SDamien Le Moal 		case 0x3e:
45534a5fc1c6SDamien Le Moal 			/* All zones except gap zones. */
45544a5fc1c6SDamien Le Moal 			if (zbc_zone_is_gap(zsp))
45554a5fc1c6SDamien Le Moal 				continue;
45564a5fc1c6SDamien Le Moal 			break;
4557f0d1cf93SDouglas Gilbert 		case 0x3f:
4558f0d1cf93SDouglas Gilbert 			/* Not write pointer (conventional) zones */
45594a5fc1c6SDamien Le Moal 			if (zbc_zone_is_seq(zsp))
4560f0d1cf93SDouglas Gilbert 				continue;
4561f0d1cf93SDouglas Gilbert 			break;
4562f0d1cf93SDouglas Gilbert 		default:
4563f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
4564f0d1cf93SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
4565f0d1cf93SDouglas Gilbert 			ret = check_condition_result;
4566f0d1cf93SDouglas Gilbert 			goto fini;
4567f0d1cf93SDouglas Gilbert 		}
4568f0d1cf93SDouglas Gilbert 
4569f0d1cf93SDouglas Gilbert 		if (nrz < rep_max_zones) {
4570f0d1cf93SDouglas Gilbert 			/* Fill zone descriptor */
457164e14eceSDamien Le Moal 			desc[0] = zsp->z_type;
4572f0d1cf93SDouglas Gilbert 			desc[1] = zsp->z_cond << 4;
457364e14eceSDamien Le Moal 			if (zsp->z_non_seq_resource)
457464e14eceSDamien Le Moal 				desc[1] |= 1 << 1;
4575f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_size, desc + 8);
4576f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_start, desc + 16);
4577f0d1cf93SDouglas Gilbert 			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4578f0d1cf93SDouglas Gilbert 			desc += 64;
4579f0d1cf93SDouglas Gilbert 		}
4580f0d1cf93SDouglas Gilbert 
4581f0d1cf93SDouglas Gilbert 		if (partial && nrz >= rep_max_zones)
4582f0d1cf93SDouglas Gilbert 			break;
4583f0d1cf93SDouglas Gilbert 
4584f0d1cf93SDouglas Gilbert 		nrz++;
4585f0d1cf93SDouglas Gilbert 	}
4586f0d1cf93SDouglas Gilbert 
4587f0d1cf93SDouglas Gilbert 	/* Report header */
45884a5fc1c6SDamien Le Moal 	/* Zone list length. */
4589f0d1cf93SDouglas Gilbert 	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
45904a5fc1c6SDamien Le Moal 	/* Maximum LBA */
4591f0d1cf93SDouglas Gilbert 	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
45924a5fc1c6SDamien Le Moal 	/* Zone starting LBA granularity. */
45934a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
45944a5fc1c6SDamien Le Moal 		put_unaligned_be64(devip->zsize, arr + 16);
4595f0d1cf93SDouglas Gilbert 
4596f0d1cf93SDouglas Gilbert 	rep_len = (unsigned long)desc - (unsigned long)arr;
459736e07d7eSGeorge Kennedy 	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
4598f0d1cf93SDouglas Gilbert 
4599f0d1cf93SDouglas Gilbert fini:
46007109f370SDouglas Gilbert 	sdeb_read_unlock(sip);
4601f0d1cf93SDouglas Gilbert 	kfree(arr);
4602f0d1cf93SDouglas Gilbert 	return ret;
4603f0d1cf93SDouglas Gilbert }
4604f0d1cf93SDouglas Gilbert 
4605f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */
zbc_open_all(struct sdebug_dev_info * devip)4606f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip)
4607f0d1cf93SDouglas Gilbert {
4608f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp = &devip->zstate[0];
4609f0d1cf93SDouglas Gilbert 	unsigned int i;
4610f0d1cf93SDouglas Gilbert 
4611f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++, zsp++) {
4612f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4613f0d1cf93SDouglas Gilbert 			zbc_open_zone(devip, &devip->zstate[i], true);
4614f0d1cf93SDouglas Gilbert 	}
4615f0d1cf93SDouglas Gilbert }
4616f0d1cf93SDouglas Gilbert 
resp_open_zone(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4617f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4618f0d1cf93SDouglas Gilbert {
4619f0d1cf93SDouglas Gilbert 	int res = 0;
4620f0d1cf93SDouglas Gilbert 	u64 z_id;
4621f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
4622f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4623f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4624f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4625b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4626f0d1cf93SDouglas Gilbert 
4627f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4628f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4629f0d1cf93SDouglas Gilbert 		return check_condition_result;
4630f0d1cf93SDouglas Gilbert 	}
4631f0d1cf93SDouglas Gilbert 
46327109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4633f0d1cf93SDouglas Gilbert 
4634f0d1cf93SDouglas Gilbert 	if (all) {
4635f0d1cf93SDouglas Gilbert 		/* Check if all closed zones can be open */
4636f0d1cf93SDouglas Gilbert 		if (devip->max_open &&
4637f0d1cf93SDouglas Gilbert 		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4638f0d1cf93SDouglas Gilbert 			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4639f0d1cf93SDouglas Gilbert 					INSUFF_ZONE_ASCQ);
4640f0d1cf93SDouglas Gilbert 			res = check_condition_result;
4641f0d1cf93SDouglas Gilbert 			goto fini;
4642f0d1cf93SDouglas Gilbert 		}
4643f0d1cf93SDouglas Gilbert 		/* Open all closed zones */
4644f0d1cf93SDouglas Gilbert 		zbc_open_all(devip);
4645f0d1cf93SDouglas Gilbert 		goto fini;
4646f0d1cf93SDouglas Gilbert 	}
4647f0d1cf93SDouglas Gilbert 
4648f0d1cf93SDouglas Gilbert 	/* Open the specified zone */
4649f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4650f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4651f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4652f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4653f0d1cf93SDouglas Gilbert 		goto fini;
4654f0d1cf93SDouglas Gilbert 	}
4655f0d1cf93SDouglas Gilbert 
4656f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4657f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4658f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4659f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4660f0d1cf93SDouglas Gilbert 		goto fini;
4661f0d1cf93SDouglas Gilbert 	}
4662f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4663f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4664f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4665f0d1cf93SDouglas Gilbert 		goto fini;
4666f0d1cf93SDouglas Gilbert 	}
4667f0d1cf93SDouglas Gilbert 
4668f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4669f0d1cf93SDouglas Gilbert 	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4670f0d1cf93SDouglas Gilbert 		goto fini;
4671f0d1cf93SDouglas Gilbert 
4672f0d1cf93SDouglas Gilbert 	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4673f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4674f0d1cf93SDouglas Gilbert 				INSUFF_ZONE_ASCQ);
4675f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4676f0d1cf93SDouglas Gilbert 		goto fini;
4677f0d1cf93SDouglas Gilbert 	}
4678f0d1cf93SDouglas Gilbert 
4679f0d1cf93SDouglas Gilbert 	zbc_open_zone(devip, zsp, true);
4680f0d1cf93SDouglas Gilbert fini:
46817109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4682f0d1cf93SDouglas Gilbert 	return res;
4683f0d1cf93SDouglas Gilbert }
4684f0d1cf93SDouglas Gilbert 
zbc_close_all(struct sdebug_dev_info * devip)4685f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip)
4686f0d1cf93SDouglas Gilbert {
4687f0d1cf93SDouglas Gilbert 	unsigned int i;
4688f0d1cf93SDouglas Gilbert 
4689f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4690f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, &devip->zstate[i]);
4691f0d1cf93SDouglas Gilbert }
4692f0d1cf93SDouglas Gilbert 
resp_close_zone(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4693f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp,
4694f0d1cf93SDouglas Gilbert 			   struct sdebug_dev_info *devip)
4695f0d1cf93SDouglas Gilbert {
4696f0d1cf93SDouglas Gilbert 	int res = 0;
4697f0d1cf93SDouglas Gilbert 	u64 z_id;
4698f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4699f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4700f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4701b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4702f0d1cf93SDouglas Gilbert 
4703f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4704f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4705f0d1cf93SDouglas Gilbert 		return check_condition_result;
4706f0d1cf93SDouglas Gilbert 	}
4707f0d1cf93SDouglas Gilbert 
47087109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4709f0d1cf93SDouglas Gilbert 
4710f0d1cf93SDouglas Gilbert 	if (all) {
4711f0d1cf93SDouglas Gilbert 		zbc_close_all(devip);
4712f0d1cf93SDouglas Gilbert 		goto fini;
4713f0d1cf93SDouglas Gilbert 	}
4714f0d1cf93SDouglas Gilbert 
4715f0d1cf93SDouglas Gilbert 	/* Close specified zone */
4716f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4717f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4718f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4719f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4720f0d1cf93SDouglas Gilbert 		goto fini;
4721f0d1cf93SDouglas Gilbert 	}
4722f0d1cf93SDouglas Gilbert 
4723f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4724f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4725f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4726f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4727f0d1cf93SDouglas Gilbert 		goto fini;
4728f0d1cf93SDouglas Gilbert 	}
4729f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4730f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4731f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4732f0d1cf93SDouglas Gilbert 		goto fini;
4733f0d1cf93SDouglas Gilbert 	}
4734f0d1cf93SDouglas Gilbert 
4735f0d1cf93SDouglas Gilbert 	zbc_close_zone(devip, zsp);
4736f0d1cf93SDouglas Gilbert fini:
47377109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4738f0d1cf93SDouglas Gilbert 	return res;
4739f0d1cf93SDouglas Gilbert }
4740f0d1cf93SDouglas Gilbert 
zbc_finish_zone(struct sdebug_dev_info * devip,struct sdeb_zone_state * zsp,bool empty)4741f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip,
4742f0d1cf93SDouglas Gilbert 			    struct sdeb_zone_state *zsp, bool empty)
4743f0d1cf93SDouglas Gilbert {
4744f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc = zsp->z_cond;
4745f0d1cf93SDouglas Gilbert 
4746f0d1cf93SDouglas Gilbert 	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4747f0d1cf93SDouglas Gilbert 	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4748f0d1cf93SDouglas Gilbert 		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4749f0d1cf93SDouglas Gilbert 			zbc_close_zone(devip, zsp);
4750f0d1cf93SDouglas Gilbert 		if (zsp->z_cond == ZC4_CLOSED)
4751f0d1cf93SDouglas Gilbert 			devip->nr_closed--;
4752f0d1cf93SDouglas Gilbert 		zsp->z_wp = zsp->z_start + zsp->z_size;
4753f0d1cf93SDouglas Gilbert 		zsp->z_cond = ZC5_FULL;
4754f0d1cf93SDouglas Gilbert 	}
4755f0d1cf93SDouglas Gilbert }
4756f0d1cf93SDouglas Gilbert 
zbc_finish_all(struct sdebug_dev_info * devip)4757f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip)
4758f0d1cf93SDouglas Gilbert {
4759f0d1cf93SDouglas Gilbert 	unsigned int i;
4760f0d1cf93SDouglas Gilbert 
4761f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4762f0d1cf93SDouglas Gilbert 		zbc_finish_zone(devip, &devip->zstate[i], false);
4763f0d1cf93SDouglas Gilbert }
4764f0d1cf93SDouglas Gilbert 
resp_finish_zone(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4765f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp,
4766f0d1cf93SDouglas Gilbert 			    struct sdebug_dev_info *devip)
4767f0d1cf93SDouglas Gilbert {
4768f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4769f0d1cf93SDouglas Gilbert 	int res = 0;
4770f0d1cf93SDouglas Gilbert 	u64 z_id;
4771f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4772f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4773b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4774f0d1cf93SDouglas Gilbert 
4775f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4776f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4777f0d1cf93SDouglas Gilbert 		return check_condition_result;
4778f0d1cf93SDouglas Gilbert 	}
4779f0d1cf93SDouglas Gilbert 
47807109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4781f0d1cf93SDouglas Gilbert 
4782f0d1cf93SDouglas Gilbert 	if (all) {
4783f0d1cf93SDouglas Gilbert 		zbc_finish_all(devip);
4784f0d1cf93SDouglas Gilbert 		goto fini;
4785f0d1cf93SDouglas Gilbert 	}
4786f0d1cf93SDouglas Gilbert 
4787f0d1cf93SDouglas Gilbert 	/* Finish the specified zone */
4788f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4789f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4790f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4791f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4792f0d1cf93SDouglas Gilbert 		goto fini;
4793f0d1cf93SDouglas Gilbert 	}
4794f0d1cf93SDouglas Gilbert 
4795f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4796f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4797f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4798f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4799f0d1cf93SDouglas Gilbert 		goto fini;
4800f0d1cf93SDouglas Gilbert 	}
4801f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4802f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4803f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4804f0d1cf93SDouglas Gilbert 		goto fini;
4805f0d1cf93SDouglas Gilbert 	}
4806f0d1cf93SDouglas Gilbert 
4807f0d1cf93SDouglas Gilbert 	zbc_finish_zone(devip, zsp, true);
4808f0d1cf93SDouglas Gilbert fini:
48097109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4810f0d1cf93SDouglas Gilbert 	return res;
4811f0d1cf93SDouglas Gilbert }
4812f0d1cf93SDouglas Gilbert 
zbc_rwp_zone(struct sdebug_dev_info * devip,struct sdeb_zone_state * zsp)4813f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4814f0d1cf93SDouglas Gilbert 			 struct sdeb_zone_state *zsp)
4815f0d1cf93SDouglas Gilbert {
4816f0d1cf93SDouglas Gilbert 	enum sdebug_z_cond zc;
48172d62253eSShin'ichiro Kawasaki 	struct sdeb_store_info *sip = devip2sip(devip, false);
4818f0d1cf93SDouglas Gilbert 
48194a5fc1c6SDamien Le Moal 	if (!zbc_zone_is_seq(zsp))
4820f0d1cf93SDouglas Gilbert 		return;
4821f0d1cf93SDouglas Gilbert 
4822f0d1cf93SDouglas Gilbert 	zc = zsp->z_cond;
4823f0d1cf93SDouglas Gilbert 	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4824f0d1cf93SDouglas Gilbert 		zbc_close_zone(devip, zsp);
4825f0d1cf93SDouglas Gilbert 
4826f0d1cf93SDouglas Gilbert 	if (zsp->z_cond == ZC4_CLOSED)
4827f0d1cf93SDouglas Gilbert 		devip->nr_closed--;
4828f0d1cf93SDouglas Gilbert 
48292d62253eSShin'ichiro Kawasaki 	if (zsp->z_wp > zsp->z_start)
48302d62253eSShin'ichiro Kawasaki 		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
48312d62253eSShin'ichiro Kawasaki 		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
48322d62253eSShin'ichiro Kawasaki 
483364e14eceSDamien Le Moal 	zsp->z_non_seq_resource = false;
4834f0d1cf93SDouglas Gilbert 	zsp->z_wp = zsp->z_start;
4835f0d1cf93SDouglas Gilbert 	zsp->z_cond = ZC1_EMPTY;
4836f0d1cf93SDouglas Gilbert }
4837f0d1cf93SDouglas Gilbert 
zbc_rwp_all(struct sdebug_dev_info * devip)4838f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip)
4839f0d1cf93SDouglas Gilbert {
4840f0d1cf93SDouglas Gilbert 	unsigned int i;
4841f0d1cf93SDouglas Gilbert 
4842f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++)
4843f0d1cf93SDouglas Gilbert 		zbc_rwp_zone(devip, &devip->zstate[i]);
4844f0d1cf93SDouglas Gilbert }
4845f0d1cf93SDouglas Gilbert 
resp_rwp_zone(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)4846f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4847f0d1cf93SDouglas Gilbert {
4848f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4849f0d1cf93SDouglas Gilbert 	int res = 0;
4850f0d1cf93SDouglas Gilbert 	u64 z_id;
4851f0d1cf93SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4852f0d1cf93SDouglas Gilbert 	bool all = cmd[14] & 0x01;
4853b6ff8ca7SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip, false);
4854f0d1cf93SDouglas Gilbert 
4855f0d1cf93SDouglas Gilbert 	if (!sdebug_dev_is_zoned(devip)) {
4856f0d1cf93SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
4857f0d1cf93SDouglas Gilbert 		return check_condition_result;
4858f0d1cf93SDouglas Gilbert 	}
4859f0d1cf93SDouglas Gilbert 
48607109f370SDouglas Gilbert 	sdeb_write_lock(sip);
4861f0d1cf93SDouglas Gilbert 
4862f0d1cf93SDouglas Gilbert 	if (all) {
4863f0d1cf93SDouglas Gilbert 		zbc_rwp_all(devip);
4864f0d1cf93SDouglas Gilbert 		goto fini;
4865f0d1cf93SDouglas Gilbert 	}
4866f0d1cf93SDouglas Gilbert 
4867f0d1cf93SDouglas Gilbert 	z_id = get_unaligned_be64(cmd + 2);
4868f0d1cf93SDouglas Gilbert 	if (z_id >= sdebug_capacity) {
4869f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4870f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4871f0d1cf93SDouglas Gilbert 		goto fini;
4872f0d1cf93SDouglas Gilbert 	}
4873f0d1cf93SDouglas Gilbert 
4874f0d1cf93SDouglas Gilbert 	zsp = zbc_zone(devip, z_id);
4875f0d1cf93SDouglas Gilbert 	if (z_id != zsp->z_start) {
4876f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4877f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4878f0d1cf93SDouglas Gilbert 		goto fini;
4879f0d1cf93SDouglas Gilbert 	}
4880f0d1cf93SDouglas Gilbert 	if (zbc_zone_is_conv(zsp)) {
4881f0d1cf93SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4882f0d1cf93SDouglas Gilbert 		res = check_condition_result;
4883f0d1cf93SDouglas Gilbert 		goto fini;
4884f0d1cf93SDouglas Gilbert 	}
4885f0d1cf93SDouglas Gilbert 
4886f0d1cf93SDouglas Gilbert 	zbc_rwp_zone(devip, zsp);
4887f0d1cf93SDouglas Gilbert fini:
48887109f370SDouglas Gilbert 	sdeb_write_unlock(sip);
4889f0d1cf93SDouglas Gilbert 	return res;
4890f0d1cf93SDouglas Gilbert }
4891f0d1cf93SDouglas Gilbert 
get_tag(struct scsi_cmnd * cmnd)4892c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd)
4893c10fa55fSJohn Garry {
4894a6e76e6fSBart Van Assche 	return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
4895c10fa55fSJohn Garry }
4896c10fa55fSJohn Garry 
4897c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
sdebug_q_cmd_complete(struct sdebug_defer * sd_dp)4898fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
48991da177e4SLinus Torvalds {
49001107c7b2SJohn Garry 	struct sdebug_queued_cmd *sqcp = container_of(sd_dp, struct sdebug_queued_cmd, sd_dp);
4901f1437cd1SJohn Garry 	unsigned long flags;
49021107c7b2SJohn Garry 	struct scsi_cmnd *scp = sqcp->scmd;
49031107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc;
49041107c7b2SJohn Garry 	bool aborted;
49051da177e4SLinus Torvalds 
4906c4837394SDouglas Gilbert 	if (sdebug_statistics) {
4907cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
4908c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4909c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
4910c4837394SDouglas Gilbert 	}
4911f1437cd1SJohn Garry 
49121107c7b2SJohn Garry 	if (!scp) {
49131107c7b2SJohn Garry 		pr_err("scmd=NULL\n");
49141107c7b2SJohn Garry 		goto out;
49151da177e4SLinus Torvalds 	}
4916151f0ec9SJohn Garry 
49171107c7b2SJohn Garry 	sdsc = scsi_cmd_priv(scp);
49181107c7b2SJohn Garry 	spin_lock_irqsave(&sdsc->lock, flags);
49191107c7b2SJohn Garry 	aborted = sd_dp->aborted;
49201107c7b2SJohn Garry 	if (unlikely(aborted))
49211107c7b2SJohn Garry 		sd_dp->aborted = false;
49221107c7b2SJohn Garry 	ASSIGN_QUEUED_CMD(scp, NULL);
4923cbf67842SDouglas Gilbert 
49241107c7b2SJohn Garry 	spin_unlock_irqrestore(&sdsc->lock, flags);
49251da177e4SLinus Torvalds 
49261107c7b2SJohn Garry 	if (aborted) {
4927f037b5cbSJohn Garry 		pr_info("bypassing scsi_done() due to aborted cmd, kicking-off EH\n");
4928f037b5cbSJohn Garry 		blk_abort_request(scsi_cmd_to_rq(scp));
49291107c7b2SJohn Garry 		goto out;
49307382f9d8SDouglas Gilbert 	}
49311107c7b2SJohn Garry 
49326c2c7d6aSBart Van Assche 	scsi_done(scp); /* callback to mid level */
49331107c7b2SJohn Garry out:
49341107c7b2SJohn Garry 	sdebug_free_queued_cmd(sqcp);
4935cbf67842SDouglas Gilbert }
4936cbf67842SDouglas Gilbert 
4937cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
sdebug_q_cmd_hrt_complete(struct hrtimer * timer)4938fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4939cbf67842SDouglas Gilbert {
4940a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4941a10bc12aSDouglas Gilbert 						  hrt);
4942a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4943cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4944cbf67842SDouglas Gilbert }
49451da177e4SLinus Torvalds 
4946a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
sdebug_q_cmd_wq_complete(struct work_struct * work)4947fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4948a10bc12aSDouglas Gilbert {
4949a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4950a10bc12aSDouglas Gilbert 						  ew.work);
4951a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4952a10bc12aSDouglas Gilbert }
4953a10bc12aSDouglas Gilbert 
495409ba24c1SDouglas Gilbert static bool got_shared_uuid;
4955bf476433SChristoph Hellwig static uuid_t shared_uuid;
495609ba24c1SDouglas Gilbert 
sdebug_device_create_zones(struct sdebug_dev_info * devip)4957f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4958f0d1cf93SDouglas Gilbert {
4959f0d1cf93SDouglas Gilbert 	struct sdeb_zone_state *zsp;
4960f0d1cf93SDouglas Gilbert 	sector_t capacity = get_sdebug_capacity();
49614a5fc1c6SDamien Le Moal 	sector_t conv_capacity;
4962f0d1cf93SDouglas Gilbert 	sector_t zstart = 0;
4963f0d1cf93SDouglas Gilbert 	unsigned int i;
4964f0d1cf93SDouglas Gilbert 
4965f0d1cf93SDouglas Gilbert 	/*
496698e0a689SDamien Le Moal 	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
496798e0a689SDamien Le Moal 	 * a zone size allowing for at least 4 zones on the device. Otherwise,
4968f0d1cf93SDouglas Gilbert 	 * use the specified zone size checking that at least 2 zones can be
4969f0d1cf93SDouglas Gilbert 	 * created for the device.
4970f0d1cf93SDouglas Gilbert 	 */
497198e0a689SDamien Le Moal 	if (!sdeb_zbc_zone_size_mb) {
4972f0d1cf93SDouglas Gilbert 		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4973f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4974f0d1cf93SDouglas Gilbert 		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4975f0d1cf93SDouglas Gilbert 			devip->zsize >>= 1;
4976f0d1cf93SDouglas Gilbert 		if (devip->zsize < 2) {
4977f0d1cf93SDouglas Gilbert 			pr_err("Device capacity too small\n");
4978f0d1cf93SDouglas Gilbert 			return -EINVAL;
4979f0d1cf93SDouglas Gilbert 		}
4980f0d1cf93SDouglas Gilbert 	} else {
4981108e36f0SDamien Le Moal 		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4982108e36f0SDamien Le Moal 			pr_err("Zone size is not a power of 2\n");
4983108e36f0SDamien Le Moal 			return -EINVAL;
4984108e36f0SDamien Le Moal 		}
498598e0a689SDamien Le Moal 		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
4986f0d1cf93SDouglas Gilbert 			>> ilog2(sdebug_sector_size);
4987f0d1cf93SDouglas Gilbert 		if (devip->zsize >= capacity) {
4988f0d1cf93SDouglas Gilbert 			pr_err("Zone size too large for device capacity\n");
4989f0d1cf93SDouglas Gilbert 			return -EINVAL;
4990f0d1cf93SDouglas Gilbert 		}
4991f0d1cf93SDouglas Gilbert 	}
4992f0d1cf93SDouglas Gilbert 
4993f0d1cf93SDouglas Gilbert 	devip->zsize_shift = ilog2(devip->zsize);
4994f0d1cf93SDouglas Gilbert 	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4995f0d1cf93SDouglas Gilbert 
49964a5fc1c6SDamien Le Moal 	if (sdeb_zbc_zone_cap_mb == 0) {
49974a5fc1c6SDamien Le Moal 		devip->zcap = devip->zsize;
49984a5fc1c6SDamien Le Moal 	} else {
49994a5fc1c6SDamien Le Moal 		devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >>
50004a5fc1c6SDamien Le Moal 			      ilog2(sdebug_sector_size);
50014a5fc1c6SDamien Le Moal 		if (devip->zcap > devip->zsize) {
50024a5fc1c6SDamien Le Moal 			pr_err("Zone capacity too large\n");
50034a5fc1c6SDamien Le Moal 			return -EINVAL;
50044a5fc1c6SDamien Le Moal 		}
50054a5fc1c6SDamien Le Moal 	}
50064a5fc1c6SDamien Le Moal 
50074a5fc1c6SDamien Le Moal 	conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift;
50084a5fc1c6SDamien Le Moal 	if (conv_capacity >= capacity) {
5009aa8fecf9SDamien Le Moal 		pr_err("Number of conventional zones too large\n");
5010aa8fecf9SDamien Le Moal 		return -EINVAL;
5011aa8fecf9SDamien Le Moal 	}
5012aa8fecf9SDamien Le Moal 	devip->nr_conv_zones = sdeb_zbc_nr_conv;
50134a5fc1c6SDamien Le Moal 	devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >>
50144a5fc1c6SDamien Le Moal 			      devip->zsize_shift;
50154a5fc1c6SDamien Le Moal 	devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones;
50164a5fc1c6SDamien Le Moal 
50174a5fc1c6SDamien Le Moal 	/* Add gap zones if zone capacity is smaller than the zone size */
50184a5fc1c6SDamien Le Moal 	if (devip->zcap < devip->zsize)
50194a5fc1c6SDamien Le Moal 		devip->nr_zones += devip->nr_seq_zones;
5020aa8fecf9SDamien Le Moal 
502164e14eceSDamien Le Moal 	if (devip->zmodel == BLK_ZONED_HM) {
502264e14eceSDamien Le Moal 		/* zbc_max_open_zones can be 0, meaning "not reported" */
5023380603a5SDamien Le Moal 		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
5024f0d1cf93SDouglas Gilbert 			devip->max_open = (devip->nr_zones - 1) / 2;
5025f0d1cf93SDouglas Gilbert 		else
5026380603a5SDamien Le Moal 			devip->max_open = sdeb_zbc_max_open;
502764e14eceSDamien Le Moal 	}
5028f0d1cf93SDouglas Gilbert 
5029f0d1cf93SDouglas Gilbert 	devip->zstate = kcalloc(devip->nr_zones,
5030f0d1cf93SDouglas Gilbert 				sizeof(struct sdeb_zone_state), GFP_KERNEL);
5031f0d1cf93SDouglas Gilbert 	if (!devip->zstate)
5032f0d1cf93SDouglas Gilbert 		return -ENOMEM;
5033f0d1cf93SDouglas Gilbert 
5034f0d1cf93SDouglas Gilbert 	for (i = 0; i < devip->nr_zones; i++) {
5035f0d1cf93SDouglas Gilbert 		zsp = &devip->zstate[i];
5036f0d1cf93SDouglas Gilbert 
5037f0d1cf93SDouglas Gilbert 		zsp->z_start = zstart;
5038f0d1cf93SDouglas Gilbert 
5039aa8fecf9SDamien Le Moal 		if (i < devip->nr_conv_zones) {
504035dbe2b9SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_CNV;
5041f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
5042f0d1cf93SDouglas Gilbert 			zsp->z_wp = (sector_t)-1;
50434a5fc1c6SDamien Le Moal 			zsp->z_size =
50444a5fc1c6SDamien Le Moal 				min_t(u64, devip->zsize, capacity - zstart);
50454a5fc1c6SDamien Le Moal 		} else if ((zstart & (devip->zsize - 1)) == 0) {
504664e14eceSDamien Le Moal 			if (devip->zmodel == BLK_ZONED_HM)
504735dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWR;
504864e14eceSDamien Le Moal 			else
504935dbe2b9SDamien Le Moal 				zsp->z_type = ZBC_ZTYPE_SWP;
5050f0d1cf93SDouglas Gilbert 			zsp->z_cond = ZC1_EMPTY;
5051f0d1cf93SDouglas Gilbert 			zsp->z_wp = zsp->z_start;
50524a5fc1c6SDamien Le Moal 			zsp->z_size =
50534a5fc1c6SDamien Le Moal 				min_t(u64, devip->zcap, capacity - zstart);
50544a5fc1c6SDamien Le Moal 		} else {
50554a5fc1c6SDamien Le Moal 			zsp->z_type = ZBC_ZTYPE_GAP;
50564a5fc1c6SDamien Le Moal 			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
50574a5fc1c6SDamien Le Moal 			zsp->z_wp = (sector_t)-1;
50584a5fc1c6SDamien Le Moal 			zsp->z_size = min_t(u64, devip->zsize - devip->zcap,
50594a5fc1c6SDamien Le Moal 					    capacity - zstart);
5060f0d1cf93SDouglas Gilbert 		}
5061f0d1cf93SDouglas Gilbert 
50624a5fc1c6SDamien Le Moal 		WARN_ON_ONCE((int)zsp->z_size <= 0);
5063f0d1cf93SDouglas Gilbert 		zstart += zsp->z_size;
5064f0d1cf93SDouglas Gilbert 	}
5065f0d1cf93SDouglas Gilbert 
5066f0d1cf93SDouglas Gilbert 	return 0;
5067f0d1cf93SDouglas Gilbert }
5068f0d1cf93SDouglas Gilbert 
sdebug_device_create(struct sdebug_host_info * sdbg_host,gfp_t flags)5069fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
5070fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
50715cb2fc06SFUJITA Tomonori {
50725cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
50735cb2fc06SFUJITA Tomonori 
50745cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
50755cb2fc06SFUJITA Tomonori 	if (devip) {
507609ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
5077bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
507809ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
507909ba24c1SDouglas Gilbert 			if (got_shared_uuid)
508009ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
508109ba24c1SDouglas Gilbert 			else {
5082bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
508309ba24c1SDouglas Gilbert 				got_shared_uuid = true;
508409ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
508509ba24c1SDouglas Gilbert 			}
508609ba24c1SDouglas Gilbert 		}
50875cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
5088f0d1cf93SDouglas Gilbert 		if (sdeb_zbc_in_use) {
508964e14eceSDamien Le Moal 			devip->zmodel = sdeb_zbc_model;
5090f0d1cf93SDouglas Gilbert 			if (sdebug_device_create_zones(devip)) {
5091f0d1cf93SDouglas Gilbert 				kfree(devip);
5092f0d1cf93SDouglas Gilbert 				return NULL;
5093f0d1cf93SDouglas Gilbert 			}
509464e14eceSDamien Le Moal 		} else {
509564e14eceSDamien Le Moal 			devip->zmodel = BLK_ZONED_NONE;
5096f0d1cf93SDouglas Gilbert 		}
5097fc13638aSDouglas Gilbert 		devip->create_ts = ktime_get_boottime();
5098fc13638aSDouglas Gilbert 		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
50995cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
51005cb2fc06SFUJITA Tomonori 	}
51015cb2fc06SFUJITA Tomonori 	return devip;
51025cb2fc06SFUJITA Tomonori }
51035cb2fc06SFUJITA Tomonori 
find_build_dev_info(struct scsi_device * sdev)5104f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
51051da177e4SLinus Torvalds {
51061da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51071da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
5108f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
51091da177e4SLinus Torvalds 
5110785d6b7cSJohn Garry 	sdbg_host = shost_to_sdebug_host(sdev->host);
5111ad0c7775SDouglas Gilbert 
51121da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
51131da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
51141da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
51151da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
51161da177e4SLinus Torvalds 			return devip;
51171da177e4SLinus Torvalds 		else {
51181da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
51191da177e4SLinus Torvalds 				open_devip = devip;
51201da177e4SLinus Torvalds 		}
51211da177e4SLinus Torvalds 	}
51225cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
51235cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
51245cb2fc06SFUJITA Tomonori 		if (!open_devip) {
5125c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51261da177e4SLinus Torvalds 			return NULL;
51271da177e4SLinus Torvalds 		}
51281da177e4SLinus Torvalds 	}
5129a75869d1SFUJITA Tomonori 
51301da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
51311da177e4SLinus Torvalds 	open_devip->target = sdev->id;
51321da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
51331da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
5134500d0d24SDouglas Gilbert 	set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
5135c2248fc9SDouglas Gilbert 	open_devip->used = true;
51361da177e4SLinus Torvalds 	return open_devip;
51371da177e4SLinus Torvalds }
51381da177e4SLinus Torvalds 
scsi_debug_slave_alloc(struct scsi_device * sdp)51398dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
51401da177e4SLinus Torvalds {
5141773642d9SDouglas Gilbert 	if (sdebug_verbose)
5142c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
51438dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
51448dea0d02SFUJITA Tomonori 	return 0;
51458dea0d02SFUJITA Tomonori }
51461da177e4SLinus Torvalds 
scsi_debug_slave_configure(struct scsi_device * sdp)51478dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
51488dea0d02SFUJITA Tomonori {
5149f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
5150f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
5151a34c4e98SFUJITA Tomonori 
5152773642d9SDouglas Gilbert 	if (sdebug_verbose)
5153c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
51548dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5155b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5156b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5157b01f6f83SDouglas Gilbert 	if (devip == NULL) {
5158f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5159b01f6f83SDouglas Gilbert 		if (devip == NULL)
51608dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
5161f46eb0e9SDouglas Gilbert 	}
5162c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
5163773642d9SDouglas Gilbert 	if (sdebug_no_uld)
516478d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
51659b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
51668dea0d02SFUJITA Tomonori 	return 0;
51678dea0d02SFUJITA Tomonori }
51688dea0d02SFUJITA Tomonori 
scsi_debug_slave_destroy(struct scsi_device * sdp)51698dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
51708dea0d02SFUJITA Tomonori {
51718dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
51728dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
51738dea0d02SFUJITA Tomonori 
5174773642d9SDouglas Gilbert 	if (sdebug_verbose)
5175c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
51768dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
51778dea0d02SFUJITA Tomonori 	if (devip) {
517825985edcSLucas De Marchi 		/* make this slot available for re-use */
5179c2248fc9SDouglas Gilbert 		devip->used = false;
51808dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
51818dea0d02SFUJITA Tomonori 	}
51828dea0d02SFUJITA Tomonori }
51838dea0d02SFUJITA Tomonori 
51841107c7b2SJohn Garry /* Returns true if we require the queued memory to be freed by the caller. */
stop_qc_helper(struct sdebug_defer * sd_dp,enum sdeb_defer_type defer_t)51851107c7b2SJohn Garry static bool stop_qc_helper(struct sdebug_defer *sd_dp,
518610bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
5187c4837394SDouglas Gilbert {
51881107c7b2SJohn Garry 	if (defer_t == SDEB_DEFER_HRT) {
51891107c7b2SJohn Garry 		int res = hrtimer_try_to_cancel(&sd_dp->hrt);
5190c4837394SDouglas Gilbert 
51911107c7b2SJohn Garry 		switch (res) {
51921107c7b2SJohn Garry 		case 0: /* Not active, it must have already run */
51931107c7b2SJohn Garry 		case -1: /* -1 It's executing the CB */
51941107c7b2SJohn Garry 			return false;
51951107c7b2SJohn Garry 		case 1: /* Was active, we've now cancelled */
51961107c7b2SJohn Garry 		default:
5197a10bc12aSDouglas Gilbert 			return true;
51988dea0d02SFUJITA Tomonori 		}
51991107c7b2SJohn Garry 	} else if (defer_t == SDEB_DEFER_WQ) {
52001107c7b2SJohn Garry 		/* Cancel if pending */
52011107c7b2SJohn Garry 		if (cancel_work_sync(&sd_dp->ew.work))
52021107c7b2SJohn Garry 			return true;
52031107c7b2SJohn Garry 		/* Was not pending, so it must have run */
5204a10bc12aSDouglas Gilbert 		return false;
52051107c7b2SJohn Garry 	} else if (defer_t == SDEB_DEFER_POLL) {
52061107c7b2SJohn Garry 		return true;
52078dea0d02SFUJITA Tomonori 	}
52081107c7b2SJohn Garry 
52091107c7b2SJohn Garry 	return false;
52101107c7b2SJohn Garry }
52111107c7b2SJohn Garry 
52121107c7b2SJohn Garry 
scsi_debug_stop_cmnd(struct scsi_cmnd * cmnd)5213f1437cd1SJohn Garry static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd)
52141107c7b2SJohn Garry {
52151107c7b2SJohn Garry 	enum sdeb_defer_type l_defer_t;
52161107c7b2SJohn Garry 	struct sdebug_defer *sd_dp;
52171107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
5218f1437cd1SJohn Garry 	struct sdebug_queued_cmd *sqcp = TO_QUEUED_CMD(cmnd);
52191107c7b2SJohn Garry 
52201107c7b2SJohn Garry 	lockdep_assert_held(&sdsc->lock);
52211107c7b2SJohn Garry 
52221107c7b2SJohn Garry 	if (!sqcp)
52231107c7b2SJohn Garry 		return false;
52241107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
52251107c7b2SJohn Garry 	l_defer_t = READ_ONCE(sd_dp->defer_t);
52261107c7b2SJohn Garry 	ASSIGN_QUEUED_CMD(cmnd, NULL);
52271107c7b2SJohn Garry 
52281107c7b2SJohn Garry 	if (stop_qc_helper(sd_dp, l_defer_t))
52291107c7b2SJohn Garry 		sdebug_free_queued_cmd(sqcp);
52301107c7b2SJohn Garry 
52311107c7b2SJohn Garry 	return true;
52321107c7b2SJohn Garry }
52331107c7b2SJohn Garry 
52341107c7b2SJohn Garry /*
52351107c7b2SJohn Garry  * Called from scsi_debug_abort() only, which is for timed-out cmd.
52361107c7b2SJohn Garry  */
scsi_debug_abort_cmnd(struct scsi_cmnd * cmnd)52371107c7b2SJohn Garry static bool scsi_debug_abort_cmnd(struct scsi_cmnd *cmnd)
52381107c7b2SJohn Garry {
52391107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
5240f1437cd1SJohn Garry 	unsigned long flags;
52411107c7b2SJohn Garry 	bool res;
52421107c7b2SJohn Garry 
52431107c7b2SJohn Garry 	spin_lock_irqsave(&sdsc->lock, flags);
5244f1437cd1SJohn Garry 	res = scsi_debug_stop_cmnd(cmnd);
52451107c7b2SJohn Garry 	spin_unlock_irqrestore(&sdsc->lock, flags);
52461107c7b2SJohn Garry 
52471107c7b2SJohn Garry 	return res;
52488dea0d02SFUJITA Tomonori }
52498dea0d02SFUJITA Tomonori 
52509c559c9bSJohn Garry /*
52519c559c9bSJohn Garry  * All we can do is set the cmnd as internally aborted and wait for it to
52529c559c9bSJohn Garry  * finish. We cannot call scsi_done() as normal completion path may do that.
52539c559c9bSJohn Garry  */
sdebug_stop_cmnd(struct request * rq,void * data)52549c559c9bSJohn Garry static bool sdebug_stop_cmnd(struct request *rq, void *data)
52559c559c9bSJohn Garry {
52569c559c9bSJohn Garry 	scsi_debug_abort_cmnd(blk_mq_rq_to_pdu(rq));
52579c559c9bSJohn Garry 
52589c559c9bSJohn Garry 	return true;
52598dea0d02SFUJITA Tomonori }
52608dea0d02SFUJITA Tomonori 
5261a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
stop_all_queued(void)5262f19fe8f3SBart Van Assche static void stop_all_queued(void)
52638dea0d02SFUJITA Tomonori {
52649c559c9bSJohn Garry 	struct sdebug_host_info *sdhp;
52658dea0d02SFUJITA Tomonori 
52669c559c9bSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
52679c559c9bSJohn Garry 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
52689c559c9bSJohn Garry 		struct Scsi_Host *shost = sdhp->shost;
5269cbf67842SDouglas Gilbert 
52709c559c9bSJohn Garry 		blk_mq_tagset_busy_iter(&shost->tag_set, sdebug_stop_cmnd, NULL);
5271cbf67842SDouglas Gilbert 	}
52729c559c9bSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
5273c4837394SDouglas Gilbert }
52741da177e4SLinus Torvalds 
scsi_debug_abort(struct scsi_cmnd * SCpnt)52751da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
52761da177e4SLinus Torvalds {
52771107c7b2SJohn Garry 	bool ok = scsi_debug_abort_cmnd(SCpnt);
5278a10bc12aSDouglas Gilbert 
52791da177e4SLinus Torvalds 	++num_aborts;
528006be9fbeSJohn Garry 
528106be9fbeSJohn Garry 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5282a10bc12aSDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5283a10bc12aSDouglas Gilbert 			    "%s: command%s found\n", __func__,
5284a10bc12aSDouglas Gilbert 			    ok ? "" : " not");
528506be9fbeSJohn Garry 
52861da177e4SLinus Torvalds 	return SUCCESS;
52871da177e4SLinus Torvalds }
52881da177e4SLinus Torvalds 
scsi_debug_stop_all_queued_iter(struct request * rq,void * data)5289*0c028b6aSJohn Garry static bool scsi_debug_stop_all_queued_iter(struct request *rq, void *data)
5290*0c028b6aSJohn Garry {
5291*0c028b6aSJohn Garry 	struct scsi_device *sdp = data;
5292*0c028b6aSJohn Garry 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
5293*0c028b6aSJohn Garry 
5294*0c028b6aSJohn Garry 	if (scmd->device == sdp)
5295*0c028b6aSJohn Garry 		scsi_debug_abort_cmnd(scmd);
5296*0c028b6aSJohn Garry 
5297*0c028b6aSJohn Garry 	return true;
5298*0c028b6aSJohn Garry }
5299*0c028b6aSJohn Garry 
5300*0c028b6aSJohn Garry /* Deletes (stops) timers or work queues of all queued commands per sdev */
scsi_debug_stop_all_queued(struct scsi_device * sdp)5301*0c028b6aSJohn Garry static void scsi_debug_stop_all_queued(struct scsi_device *sdp)
5302*0c028b6aSJohn Garry {
5303*0c028b6aSJohn Garry 	struct Scsi_Host *shost = sdp->host;
5304*0c028b6aSJohn Garry 
5305*0c028b6aSJohn Garry 	blk_mq_tagset_busy_iter(&shost->tag_set,
5306*0c028b6aSJohn Garry 				scsi_debug_stop_all_queued_iter, sdp);
5307*0c028b6aSJohn Garry }
5308*0c028b6aSJohn Garry 
scsi_debug_device_reset(struct scsi_cmnd * SCpnt)53091da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
53101da177e4SLinus Torvalds {
5311cbf67842SDouglas Gilbert 	struct scsi_device *sdp = SCpnt->device;
5312a19226f8SJohn Garry 	struct sdebug_dev_info *devip = sdp->hostdata;
5313a19226f8SJohn Garry 
5314a19226f8SJohn Garry 	++num_dev_resets;
5315cbf67842SDouglas Gilbert 
5316773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5317cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5318*0c028b6aSJohn Garry 
5319*0c028b6aSJohn Garry 	scsi_debug_stop_all_queued(sdp);
53201da177e4SLinus Torvalds 	if (devip)
5321cbf67842SDouglas Gilbert 		set_bit(SDEBUG_UA_POR, devip->uas_bm);
5322a19226f8SJohn Garry 
53231da177e4SLinus Torvalds 	return SUCCESS;
53241da177e4SLinus Torvalds }
53251da177e4SLinus Torvalds 
scsi_debug_target_reset(struct scsi_cmnd * SCpnt)5326cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5327cbf67842SDouglas Gilbert {
5328a15df530SJohn Garry 	struct scsi_device *sdp = SCpnt->device;
5329a15df530SJohn Garry 	struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host);
5330cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5331cbf67842SDouglas Gilbert 	int k = 0;
5332cbf67842SDouglas Gilbert 
5333cbf67842SDouglas Gilbert 	++num_target_resets;
5334773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5335cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5336a15df530SJohn Garry 
5337a15df530SJohn Garry 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
5338cbf67842SDouglas Gilbert 		if (devip->target == sdp->id) {
5339cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5340cbf67842SDouglas Gilbert 			++k;
5341cbf67842SDouglas Gilbert 		}
5342cbf67842SDouglas Gilbert 	}
5343a15df530SJohn Garry 
5344773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5345cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5346cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
5347a15df530SJohn Garry 
5348cbf67842SDouglas Gilbert 	return SUCCESS;
5349cbf67842SDouglas Gilbert }
5350cbf67842SDouglas Gilbert 
scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)53511da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
53521da177e4SLinus Torvalds {
5353519bfc14SJohn Garry 	struct scsi_device *sdp = SCpnt->device;
5354519bfc14SJohn Garry 	struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host);
5355cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5356cbf67842SDouglas Gilbert 	int k = 0;
53571da177e4SLinus Torvalds 
53581da177e4SLinus Torvalds 	++num_bus_resets;
5359519bfc14SJohn Garry 
5360773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5361cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5362519bfc14SJohn Garry 
5363519bfc14SJohn Garry 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
5364cbf67842SDouglas Gilbert 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5365cbf67842SDouglas Gilbert 		++k;
53661da177e4SLinus Torvalds 	}
5367519bfc14SJohn Garry 
5368773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5369cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
5370cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
53711da177e4SLinus Torvalds 	return SUCCESS;
53721da177e4SLinus Torvalds }
53731da177e4SLinus Torvalds 
scsi_debug_host_reset(struct scsi_cmnd * SCpnt)53741da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
53751da177e4SLinus Torvalds {
53761da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
5377cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5378cbf67842SDouglas Gilbert 	int k = 0;
53791da177e4SLinus Torvalds 
53801da177e4SLinus Torvalds 	++num_host_resets;
53819c230382SJohn Garry 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
5382cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
53830aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
53841da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
5385cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
5386cbf67842SDouglas Gilbert 				    dev_list) {
5387cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5388cbf67842SDouglas Gilbert 			++k;
5389cbf67842SDouglas Gilbert 		}
53901da177e4SLinus Torvalds 	}
53910aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
5392f19fe8f3SBart Van Assche 	stop_all_queued();
5393773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
5394cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
5395cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
53961da177e4SLinus Torvalds 	return SUCCESS;
53971da177e4SLinus Torvalds }
53981da177e4SLinus Torvalds 
sdebug_build_parts(unsigned char * ramp,unsigned long store_size)539987c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
54001da177e4SLinus Torvalds {
54011442f76dSChristoph Hellwig 	struct msdos_partition *pp;
5402979e0dc3SJohn Pittman 	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
54031da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
54041da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
54051da177e4SLinus Torvalds 
54061da177e4SLinus Torvalds 	/* assume partition table already zeroed */
5407773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
54081da177e4SLinus Torvalds 		return;
5409773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5410773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
5411c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
54121da177e4SLinus Torvalds 	}
54138c657235SJohn Pittman 	num_sectors = (int)get_sdebug_capacity();
54141da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
5415773642d9SDouglas Gilbert 			   / sdebug_num_parts;
54161da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
54171da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
5418979e0dc3SJohn Pittman 	max_part_secs = sectors_per_part;
5419979e0dc3SJohn Pittman 	for (k = 1; k < sdebug_num_parts; ++k) {
54201da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
54211da177e4SLinus Torvalds 			    * heads_by_sects;
5422979e0dc3SJohn Pittman 		if (starts[k] - starts[k - 1] < max_part_secs)
5423979e0dc3SJohn Pittman 			max_part_secs = starts[k] - starts[k - 1];
5424979e0dc3SJohn Pittman 	}
5425773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
5426773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
54271da177e4SLinus Torvalds 
54281da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
54291da177e4SLinus Torvalds 	ramp[511] = 0xAA;
54301442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
54311da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
54321da177e4SLinus Torvalds 		start_sec = starts[k];
5433979e0dc3SJohn Pittman 		end_sec = starts[k] + max_part_secs - 1;
54341da177e4SLinus Torvalds 		pp->boot_ind = 0;
54351da177e4SLinus Torvalds 
54361da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
54371da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
54381da177e4SLinus Torvalds 			   / sdebug_sectors_per;
54391da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
54401da177e4SLinus Torvalds 
54411da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
54421da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
54431da177e4SLinus Torvalds 			       / sdebug_sectors_per;
54441da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
54451da177e4SLinus Torvalds 
5446150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
5447150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
54481da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
54491da177e4SLinus Torvalds 	}
54501da177e4SLinus Torvalds }
54511da177e4SLinus Torvalds 
block_unblock_all_queues(bool block)5452f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block)
5453c4837394SDouglas Gilbert {
5454a0473bf3SJohn Garry 	struct sdebug_host_info *sdhp;
5455c4837394SDouglas Gilbert 
545625b80b2cSJohn Garry 	lockdep_assert_held(&sdebug_host_list_mutex);
545725b80b2cSJohn Garry 
5458a0473bf3SJohn Garry 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
5459a0473bf3SJohn Garry 		struct Scsi_Host *shost = sdhp->shost;
5460a0473bf3SJohn Garry 
5461a0473bf3SJohn Garry 		if (block)
5462a0473bf3SJohn Garry 			scsi_block_requests(shost);
5463a0473bf3SJohn Garry 		else
5464a0473bf3SJohn Garry 			scsi_unblock_requests(shost);
5465a0473bf3SJohn Garry 	}
5466c4837394SDouglas Gilbert }
5467c4837394SDouglas Gilbert 
5468c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5469c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
5470c4837394SDouglas Gilbert  */
tweak_cmnd_count(void)5471c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
5472c4837394SDouglas Gilbert {
5473c4837394SDouglas Gilbert 	int count, modulo;
5474c4837394SDouglas Gilbert 
5475c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
5476c4837394SDouglas Gilbert 	if (modulo < 2)
5477c4837394SDouglas Gilbert 		return;
547825b80b2cSJohn Garry 
547925b80b2cSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
5480f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
5481c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
5482c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5483f19fe8f3SBart Van Assche 	block_unblock_all_queues(false);
548425b80b2cSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
5485c4837394SDouglas Gilbert }
5486c4837394SDouglas Gilbert 
clear_queue_stats(void)5487c4837394SDouglas Gilbert static void clear_queue_stats(void)
5488c4837394SDouglas Gilbert {
5489c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
5490c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
5491c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
5492c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
5493c4837394SDouglas Gilbert }
5494c4837394SDouglas Gilbert 
inject_on_this_cmd(void)54953a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void)
5496c4837394SDouglas Gilbert {
54973a90a63dSDouglas Gilbert 	if (sdebug_every_nth == 0)
54983a90a63dSDouglas Gilbert 		return false;
54993a90a63dSDouglas Gilbert 	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5500c4837394SDouglas Gilbert }
5501c4837394SDouglas Gilbert 
5502a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
5503a2aede97SDouglas Gilbert 
55041107c7b2SJohn Garry 
sdebug_free_queued_cmd(struct sdebug_queued_cmd * sqcp)55051107c7b2SJohn Garry void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp)
55061107c7b2SJohn Garry {
55071107c7b2SJohn Garry 	if (sqcp)
55081107c7b2SJohn Garry 		kmem_cache_free(queued_cmd_cache, sqcp);
55091107c7b2SJohn Garry }
55101107c7b2SJohn Garry 
sdebug_alloc_queued_cmd(struct scsi_cmnd * scmd)55111107c7b2SJohn Garry static struct sdebug_queued_cmd *sdebug_alloc_queued_cmd(struct scsi_cmnd *scmd)
55121107c7b2SJohn Garry {
55131107c7b2SJohn Garry 	struct sdebug_queued_cmd *sqcp;
55141107c7b2SJohn Garry 	struct sdebug_defer *sd_dp;
55151107c7b2SJohn Garry 
55161107c7b2SJohn Garry 	sqcp = kmem_cache_zalloc(queued_cmd_cache, GFP_ATOMIC);
55171107c7b2SJohn Garry 	if (!sqcp)
55181107c7b2SJohn Garry 		return NULL;
55191107c7b2SJohn Garry 
55201107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
55211107c7b2SJohn Garry 
55221107c7b2SJohn Garry 	hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
55231107c7b2SJohn Garry 	sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
55241107c7b2SJohn Garry 	INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
55251107c7b2SJohn Garry 
55261107c7b2SJohn Garry 	sqcp->scmd = scmd;
55271107c7b2SJohn Garry 
55281107c7b2SJohn Garry 	return sqcp;
55291107c7b2SJohn Garry }
55301107c7b2SJohn Garry 
5531c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
5532c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
5533c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
5534c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5535c4837394SDouglas Gilbert  */
schedule_resp(struct scsi_cmnd * cmnd,struct sdebug_dev_info * devip,int scsi_result,int (* pfp)(struct scsi_cmnd *,struct sdebug_dev_info *),int delta_jiff,int ndelay)5536fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
5537f66b8517SMartin Wilck 			 int scsi_result,
5538f19fe8f3SBart Van Assche 			 int (*pfp)(struct scsi_cmnd *,
5539f19fe8f3SBart Van Assche 				    struct sdebug_dev_info *),
5540f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
55411da177e4SLinus Torvalds {
55421107c7b2SJohn Garry 	struct request *rq = scsi_cmd_to_rq(cmnd);
55431107c7b2SJohn Garry 	bool polled = rq->cmd_flags & REQ_POLLED;
55441107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd);
5545f1437cd1SJohn Garry 	unsigned long flags;
5546a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
5547c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
5548299b6c07STomas Winkler 	struct scsi_device *sdp;
5549a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
55501da177e4SLinus Torvalds 
5551b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
5552b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
5553f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
5554f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
55551da177e4SLinus Torvalds 	}
5556299b6c07STomas Winkler 	sdp = cmnd->device;
5557299b6c07STomas Winkler 
5558f19fe8f3SBart Van Assche 	if (delta_jiff == 0)
5559cd62b7daSDouglas Gilbert 		goto respond_in_thread;
55601da177e4SLinus Torvalds 
5561151f0ec9SJohn Garry 
55620befb879SJohn Garry 	if (unlikely(sdebug_every_nth && (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5563f46eb0e9SDouglas Gilbert 		     (scsi_result == 0))) {
5564151f0ec9SJohn Garry 		int num_in_q = scsi_device_busy(sdp);
5565151f0ec9SJohn Garry 		int qdepth = cmnd->device->queue_depth;
5566151f0ec9SJohn Garry 
55676500d204SJohn Garry 		if ((num_in_q == qdepth) &&
5568cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
5569773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
5570cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
5571cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
5572151f0ec9SJohn Garry 
5573151f0ec9SJohn Garry 			if (unlikely(SDEBUG_OPT_Q_NOISE & sdebug_opts))
5574151f0ec9SJohn Garry 				sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, <inject> status: TASK SET FULL\n",
5575151f0ec9SJohn Garry 					    __func__, num_in_q);
55761da177e4SLinus Torvalds 		}
5577cbf67842SDouglas Gilbert 	}
5578cbf67842SDouglas Gilbert 
55791107c7b2SJohn Garry 	sqcp = sdebug_alloc_queued_cmd(cmnd);
55801107c7b2SJohn Garry 	if (!sqcp) {
5581f1437cd1SJohn Garry 		pr_err("%s no alloc\n", __func__);
558210bde980SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
558374595c04SDouglas Gilbert 	}
55841107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
5585c10fa55fSJohn Garry 
55866ce913feSChristoph Hellwig 	if (polled)
5587a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
5588a2aede97SDouglas Gilbert 
5589a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
55903a90a63dSDouglas Gilbert 	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
5591f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
5592f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
5593f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
5594f66b8517SMartin Wilck 	}
5595f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
5596f66b8517SMartin Wilck 		cmnd->result = scsi_result;
55973a90a63dSDouglas Gilbert 	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
55983a90a63dSDouglas Gilbert 		if (atomic_read(&sdeb_inject_pending)) {
55993a90a63dSDouglas Gilbert 			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
56003a90a63dSDouglas Gilbert 			atomic_set(&sdeb_inject_pending, 0);
56013a90a63dSDouglas Gilbert 			cmnd->result = check_condition_result;
56023a90a63dSDouglas Gilbert 		}
56033a90a63dSDouglas Gilbert 	}
5604f66b8517SMartin Wilck 
5605f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
5606f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5607f66b8517SMartin Wilck 			    __func__, cmnd->result);
5608f66b8517SMartin Wilck 
560910bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
5610b333a819SDouglas Gilbert 		ktime_t kt;
5611cbf67842SDouglas Gilbert 
5612b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
56130c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
56140c4bc91dSDouglas Gilbert 
56150c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
56168032bf12SJason A. Donenfeld 				ns = get_random_u32_below((u32)ns);
56170c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
56180c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
56190c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
56208032bf12SJason A. Donenfeld 					ns = get_random_u32_below((u32)ns);
56210c4bc91dSDouglas Gilbert 				ns <<= 12;
56220c4bc91dSDouglas Gilbert 			}
56230c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
56240c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
56258032bf12SJason A. Donenfeld 			kt = sdebug_random ? get_random_u32_below((u32)ndelay) :
56260c4bc91dSDouglas Gilbert 					     (u32)ndelay;
5627a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5628a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
5629a2aede97SDouglas Gilbert 
5630a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
5631a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
56321107c7b2SJohn Garry 					sdebug_free_queued_cmd(sqcp);
56336c2c7d6aSBart Van Assche 					scsi_done(cmnd);
5634a2aede97SDouglas Gilbert 					return 0;
5635a2aede97SDouglas Gilbert 				}
5636a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
5637a2aede97SDouglas Gilbert 				kt -= d;
5638a2aede97SDouglas Gilbert 			}
56390c4bc91dSDouglas Gilbert 		}
56404a0c6f43SDouglas Gilbert 		if (sdebug_statistics)
56414a0c6f43SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
56421107c7b2SJohn Garry 		if (polled) {
56431107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
56441107c7b2SJohn Garry 			sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
56451107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
56461107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
56471107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
56481107c7b2SJohn Garry 		} else {
56491107c7b2SJohn Garry 			/* schedule the invocation of scsi_done() for a later time */
56501107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
56511107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
56521107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
56531107c7b2SJohn Garry 			hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
56541107c7b2SJohn Garry 			/*
56551107c7b2SJohn Garry 			 * The completion handler will try to grab sqcp->lock,
56561107c7b2SJohn Garry 			 * so there is no chance that the completion handler
56571107c7b2SJohn Garry 			 * will call scsi_done() until we release the lock
56581107c7b2SJohn Garry 			 * here (so ok to keep referencing sdsc).
56591107c7b2SJohn Garry 			 */
56601107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
56611107c7b2SJohn Garry 		}
5662c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
56634a0c6f43SDouglas Gilbert 		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5664f037b5cbSJohn Garry 			     atomic_read(&sdeb_inject_pending))) {
56654a0c6f43SDouglas Gilbert 			sd_dp->aborted = true;
5666f037b5cbSJohn Garry 			atomic_set(&sdeb_inject_pending, 0);
5667f037b5cbSJohn Garry 			sdev_printk(KERN_INFO, sdp, "abort request tag=%#x\n",
5668f037b5cbSJohn Garry 				    blk_mq_unique_tag_to_tag(get_tag(cmnd)));
5669f037b5cbSJohn Garry 		}
5670f037b5cbSJohn Garry 
5671c4837394SDouglas Gilbert 		if (sdebug_statistics)
5672c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
56731107c7b2SJohn Garry 		if (polled) {
56741107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
56751107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
56761107c7b2SJohn Garry 			sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
56771107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
56781107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
56791107c7b2SJohn Garry 		} else {
56801107c7b2SJohn Garry 			spin_lock_irqsave(&sdsc->lock, flags);
56811107c7b2SJohn Garry 			ASSIGN_QUEUED_CMD(cmnd, sqcp);
56821107c7b2SJohn Garry 			WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
56831107c7b2SJohn Garry 			schedule_work(&sd_dp->ew.work);
56841107c7b2SJohn Garry 			spin_unlock_irqrestore(&sdsc->lock, flags);
56851107c7b2SJohn Garry 		}
5686cbf67842SDouglas Gilbert 	}
5687151f0ec9SJohn Garry 
56881da177e4SLinus Torvalds 	return 0;
5689cd62b7daSDouglas Gilbert 
5690cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
5691f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5692f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
5693f19fe8f3SBart Van Assche 	if (cmnd->result == 0 && scsi_result != 0)
5694cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
56956c2c7d6aSBart Van Assche 	scsi_done(cmnd);
5696cd62b7daSDouglas Gilbert 	return 0;
56971da177e4SLinus Torvalds }
5698cbf67842SDouglas Gilbert 
569923183910SDouglas Gilbert /* Note: The following macros create attribute files in the
570023183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
570123183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
570223183910SDouglas Gilbert    as it can when the corresponding attribute in the
570323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
570423183910SDouglas Gilbert  */
5705773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5706773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
57079b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
5708773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
5709c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
5710773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5711773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
5712773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
5713773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5714773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5715773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5716773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5717773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
5718c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
5719e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
5720e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
5721e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
5722e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
57235d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id,
57245d807076SDouglas Gilbert 		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
57255d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
5726773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5727773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5728773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
5729773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
5730ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
5731773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5732773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
57335d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int,
57345d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
57355d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int,
57365d807076SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5737773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5738773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
57397109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
5740773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5741773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5742773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5743773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
57445d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
5745773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
574687c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
574787c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
5748773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5749773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
57500c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
5751773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5752773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5753773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
5754c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
5755773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
5756c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
5757c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO);
5758fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
5759773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5760773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5761773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5762773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
576309ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
57645d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
5765773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
576623183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
57679447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
5768773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
57695b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
57709267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
57714a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO);
5772380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
5773aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
577498e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
57751da177e4SLinus Torvalds 
57761da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
57771da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
57781da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5779b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
57801da177e4SLinus Torvalds 
57815d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
57825b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
57839b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
57840759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
5785cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
5786c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
57875b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
57885b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
5789c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
5790beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
579123183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
57925b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
5793185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
5794c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue,
5795c10fa55fSJohn Garry 		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
5796e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
57979b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
57989b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
57995d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
58005d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz,
58015d807076SDouglas Gilbert 		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
58025b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
58035b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
58045b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
58055b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
5806ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
5807fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
5808cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
5809d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
58105d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
5811cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
5812c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
58137109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
581478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
58151da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
5816c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
581732c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
581886e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
58195d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
58205d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
58215d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
5822fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
58231da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
58240c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
5825d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
5826760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
5827ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
5828c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
5829c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
5830c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
5831fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
58325b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
58335b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
58346014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
58356014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
583609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
583709ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
5838c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
58395b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
58409447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
58415b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
58429267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
58434a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)");
5844380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
5845aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
584698e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
58471da177e4SLinus Torvalds 
5848760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
5849760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
58501da177e4SLinus Torvalds 
scsi_debug_info(struct Scsi_Host * shp)58511da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
58521da177e4SLinus Torvalds {
5853c4837394SDouglas Gilbert 	int k;
5854c4837394SDouglas Gilbert 
5855760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5856760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
5857760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
5858c4837394SDouglas Gilbert 		return sdebug_info;
5859760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5860760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5861760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
5862760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
58631da177e4SLinus Torvalds 	return sdebug_info;
58641da177e4SLinus Torvalds }
58651da177e4SLinus Torvalds 
5866cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
scsi_debug_write_info(struct Scsi_Host * host,char * buffer,int length)5867fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5868fd32119bSDouglas Gilbert 				 int length)
58691da177e4SLinus Torvalds {
58701da177e4SLinus Torvalds 	char arr[16];
5871c8ed555aSAl Viro 	int opts;
58721da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
58731da177e4SLinus Torvalds 
58741da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
58751da177e4SLinus Torvalds 		return -EACCES;
58761da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
58771da177e4SLinus Torvalds 	arr[minLen] = '\0';
5878c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
58791da177e4SLinus Torvalds 		return -EINVAL;
5880773642d9SDouglas Gilbert 	sdebug_opts = opts;
5881773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5882773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5883773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
5884c4837394SDouglas Gilbert 		tweak_cmnd_count();
58851da177e4SLinus Torvalds 	return length;
58861da177e4SLinus Torvalds }
5887c8ed555aSAl Viro 
5888f1437cd1SJohn Garry struct sdebug_submit_queue_data {
5889f1437cd1SJohn Garry 	int *first;
5890f1437cd1SJohn Garry 	int *last;
5891f1437cd1SJohn Garry 	int queue_num;
5892f1437cd1SJohn Garry };
5893f1437cd1SJohn Garry 
sdebug_submit_queue_iter(struct request * rq,void * opaque)5894f1437cd1SJohn Garry static bool sdebug_submit_queue_iter(struct request *rq, void *opaque)
5895f1437cd1SJohn Garry {
5896f1437cd1SJohn Garry 	struct sdebug_submit_queue_data *data = opaque;
5897f1437cd1SJohn Garry 	u32 unique_tag = blk_mq_unique_tag(rq);
5898f1437cd1SJohn Garry 	u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag);
5899f1437cd1SJohn Garry 	u16 tag = blk_mq_unique_tag_to_tag(unique_tag);
5900f1437cd1SJohn Garry 	int queue_num = data->queue_num;
5901f1437cd1SJohn Garry 
5902f1437cd1SJohn Garry 	if (hwq != queue_num)
5903f1437cd1SJohn Garry 		return true;
5904f1437cd1SJohn Garry 
5905f1437cd1SJohn Garry 	/* Rely on iter'ing in ascending tag order */
5906f1437cd1SJohn Garry 	if (*data->first == -1)
5907f1437cd1SJohn Garry 		*data->first = *data->last = tag;
5908f1437cd1SJohn Garry 	else
5909f1437cd1SJohn Garry 		*data->last = tag;
5910f1437cd1SJohn Garry 
5911f1437cd1SJohn Garry 	return true;
5912f1437cd1SJohn Garry }
5913f1437cd1SJohn Garry 
5914cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5915cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
5916cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
scsi_debug_show_info(struct seq_file * m,struct Scsi_Host * host)5917c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5918c8ed555aSAl Viro {
591987c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
5920f1437cd1SJohn Garry 	int j;
5921cbf67842SDouglas Gilbert 
5922c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5923c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
5924c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5925c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5926c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
5927c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5928c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5929c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
5930c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5931c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5932c4837394SDouglas Gilbert 		   num_aborts);
5933c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5934c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
5935c4837394SDouglas Gilbert 		   num_host_resets);
5936c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5937c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
5938458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5939458df78bSBart Van Assche 		   sdebug_statistics);
59404a0c6f43SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
5941c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
5942c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
5943c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
59444a0c6f43SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf),
59454a0c6f43SDouglas Gilbert 		   atomic_read(&sdeb_mq_poll_count));
5946cbf67842SDouglas Gilbert 
5947c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
5948f1437cd1SJohn Garry 	for (j = 0; j < submit_queues; ++j) {
5949f1437cd1SJohn Garry 		int f = -1, l = -1;
5950f1437cd1SJohn Garry 		struct sdebug_submit_queue_data data = {
5951f1437cd1SJohn Garry 			.queue_num = j,
5952f1437cd1SJohn Garry 			.first = &f,
5953f1437cd1SJohn Garry 			.last = &l,
5954f1437cd1SJohn Garry 		};
5955c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
5956f1437cd1SJohn Garry 		blk_mq_tagset_busy_iter(&host->tag_set, sdebug_submit_queue_iter,
5957f1437cd1SJohn Garry 					&data);
5958f1437cd1SJohn Garry 		if (f >= 0) {
5959c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
5960c4837394SDouglas Gilbert 				   "first,last bits", f, l);
5961c4837394SDouglas Gilbert 		}
5962cbf67842SDouglas Gilbert 	}
596387c715dcSDouglas Gilbert 
596487c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
596587c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
596687c715dcSDouglas Gilbert 		bool niu;
596787c715dcSDouglas Gilbert 		int idx;
596887c715dcSDouglas Gilbert 		unsigned long l_idx;
596987c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
597087c715dcSDouglas Gilbert 
597187c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
597287c715dcSDouglas Gilbert 		j = 0;
597387c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
597487c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
597587c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
597687c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
597787c715dcSDouglas Gilbert 			++j;
597887c715dcSDouglas Gilbert 		}
597987c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
598087c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
598187c715dcSDouglas Gilbert 		j = 0;
598287c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
598387c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
598487c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
598587c715dcSDouglas Gilbert 			idx = (int)l_idx;
598687c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
598787c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
598887c715dcSDouglas Gilbert 			++j;
598987c715dcSDouglas Gilbert 		}
599087c715dcSDouglas Gilbert 	}
5991c8ed555aSAl Viro 	return 0;
59921da177e4SLinus Torvalds }
59931da177e4SLinus Torvalds 
delay_show(struct device_driver * ddp,char * buf)599482069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
59951da177e4SLinus Torvalds {
5996c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
59971da177e4SLinus Torvalds }
5998c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5999c4837394SDouglas Gilbert  * of delay is jiffies.
6000c4837394SDouglas Gilbert  */
delay_store(struct device_driver * ddp,const char * buf,size_t count)600182069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
600282069379SAkinobu Mita 			   size_t count)
60031da177e4SLinus Torvalds {
6004c2206098SDouglas Gilbert 	int jdelay, res;
60051da177e4SLinus Torvalds 
6006b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
6007cbf67842SDouglas Gilbert 		res = count;
6008c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
600912f3eef0SJohn Garry 			struct sdebug_host_info *sdhp;
6010cbf67842SDouglas Gilbert 
601125b80b2cSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
6012f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
601312f3eef0SJohn Garry 
601412f3eef0SJohn Garry 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
601512f3eef0SJohn Garry 				struct Scsi_Host *shost = sdhp->shost;
601612f3eef0SJohn Garry 
601712f3eef0SJohn Garry 				if (scsi_host_busy(shost)) {
6018c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6019c4837394SDouglas Gilbert 					break;
6020c4837394SDouglas Gilbert 				}
6021c4837394SDouglas Gilbert 			}
6022c4837394SDouglas Gilbert 			if (res > 0) {
6023c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
6024773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
60251da177e4SLinus Torvalds 			}
6026f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
602725b80b2cSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
6028cbf67842SDouglas Gilbert 		}
6029cbf67842SDouglas Gilbert 		return res;
60301da177e4SLinus Torvalds 	}
60311da177e4SLinus Torvalds 	return -EINVAL;
60321da177e4SLinus Torvalds }
603382069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
60341da177e4SLinus Torvalds 
ndelay_show(struct device_driver * ddp,char * buf)6035cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
6036cbf67842SDouglas Gilbert {
6037773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
6038cbf67842SDouglas Gilbert }
6039cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
6040c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
ndelay_store(struct device_driver * ddp,const char * buf,size_t count)6041cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
6042cbf67842SDouglas Gilbert 			    size_t count)
6043cbf67842SDouglas Gilbert {
6044c4837394SDouglas Gilbert 	int ndelay, res;
6045cbf67842SDouglas Gilbert 
6046cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
6047c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
6048cbf67842SDouglas Gilbert 		res = count;
6049773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
605012f3eef0SJohn Garry 			struct sdebug_host_info *sdhp;
6051c4837394SDouglas Gilbert 
605225b80b2cSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
6053f19fe8f3SBart Van Assche 			block_unblock_all_queues(true);
605412f3eef0SJohn Garry 
605512f3eef0SJohn Garry 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
605612f3eef0SJohn Garry 				struct Scsi_Host *shost = sdhp->shost;
605712f3eef0SJohn Garry 
605812f3eef0SJohn Garry 				if (scsi_host_busy(shost)) {
6059c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
6060c4837394SDouglas Gilbert 					break;
6061c4837394SDouglas Gilbert 				}
6062c4837394SDouglas Gilbert 			}
606312f3eef0SJohn Garry 
6064c4837394SDouglas Gilbert 			if (res > 0) {
6065773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
6066c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
6067c2206098SDouglas Gilbert 							: DEF_JDELAY;
6068cbf67842SDouglas Gilbert 			}
6069f19fe8f3SBart Van Assche 			block_unblock_all_queues(false);
607025b80b2cSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
6071cbf67842SDouglas Gilbert 		}
6072cbf67842SDouglas Gilbert 		return res;
6073cbf67842SDouglas Gilbert 	}
6074cbf67842SDouglas Gilbert 	return -EINVAL;
6075cbf67842SDouglas Gilbert }
6076cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
6077cbf67842SDouglas Gilbert 
opts_show(struct device_driver * ddp,char * buf)607882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
60791da177e4SLinus Torvalds {
6080773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
60811da177e4SLinus Torvalds }
60821da177e4SLinus Torvalds 
opts_store(struct device_driver * ddp,const char * buf,size_t count)608382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
608482069379SAkinobu Mita 			  size_t count)
60851da177e4SLinus Torvalds {
60861da177e4SLinus Torvalds 	int opts;
60871da177e4SLinus Torvalds 	char work[20];
60881da177e4SLinus Torvalds 
60899a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
60909a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
60919a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
60921da177e4SLinus Torvalds 				goto opts_done;
60931da177e4SLinus Torvalds 		} else {
60949a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
60951da177e4SLinus Torvalds 				goto opts_done;
60961da177e4SLinus Torvalds 		}
60971da177e4SLinus Torvalds 	}
60981da177e4SLinus Torvalds 	return -EINVAL;
60991da177e4SLinus Torvalds opts_done:
6100773642d9SDouglas Gilbert 	sdebug_opts = opts;
6101773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
6102773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
6103c4837394SDouglas Gilbert 	tweak_cmnd_count();
61041da177e4SLinus Torvalds 	return count;
61051da177e4SLinus Torvalds }
610682069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
61071da177e4SLinus Torvalds 
ptype_show(struct device_driver * ddp,char * buf)610882069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
61091da177e4SLinus Torvalds {
6110773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
61111da177e4SLinus Torvalds }
ptype_store(struct device_driver * ddp,const char * buf,size_t count)611282069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
611382069379SAkinobu Mita 			   size_t count)
61141da177e4SLinus Torvalds {
61151da177e4SLinus Torvalds 	int n;
61161da177e4SLinus Torvalds 
6117f0d1cf93SDouglas Gilbert 	/* Cannot change from or to TYPE_ZBC with sysfs */
6118f0d1cf93SDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC)
6119f0d1cf93SDouglas Gilbert 		return -EINVAL;
6120f0d1cf93SDouglas Gilbert 
61211da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6122f0d1cf93SDouglas Gilbert 		if (n == TYPE_ZBC)
6123f0d1cf93SDouglas Gilbert 			return -EINVAL;
6124773642d9SDouglas Gilbert 		sdebug_ptype = n;
61251da177e4SLinus Torvalds 		return count;
61261da177e4SLinus Torvalds 	}
61271da177e4SLinus Torvalds 	return -EINVAL;
61281da177e4SLinus Torvalds }
612982069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
61301da177e4SLinus Torvalds 
dsense_show(struct device_driver * ddp,char * buf)613182069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
61321da177e4SLinus Torvalds {
6133773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
61341da177e4SLinus Torvalds }
dsense_store(struct device_driver * ddp,const char * buf,size_t count)613582069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
613682069379SAkinobu Mita 			    size_t count)
61371da177e4SLinus Torvalds {
61381da177e4SLinus Torvalds 	int n;
61391da177e4SLinus Torvalds 
61401da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6141773642d9SDouglas Gilbert 		sdebug_dsense = n;
61421da177e4SLinus Torvalds 		return count;
61431da177e4SLinus Torvalds 	}
61441da177e4SLinus Torvalds 	return -EINVAL;
61451da177e4SLinus Torvalds }
614682069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
61471da177e4SLinus Torvalds 
fake_rw_show(struct device_driver * ddp,char * buf)614882069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
614923183910SDouglas Gilbert {
6150773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
615123183910SDouglas Gilbert }
fake_rw_store(struct device_driver * ddp,const char * buf,size_t count)615282069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
615382069379SAkinobu Mita 			     size_t count)
615423183910SDouglas Gilbert {
615587c715dcSDouglas Gilbert 	int n, idx;
615623183910SDouglas Gilbert 
615723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
615887c715dcSDouglas Gilbert 		bool want_store = (n == 0);
615987c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
616087c715dcSDouglas Gilbert 
6161cbf67842SDouglas Gilbert 		n = (n > 0);
6162773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
616387c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
616487c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
6165cbf67842SDouglas Gilbert 
616687c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
616787c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
616887c715dcSDouglas Gilbert 				idx = sdebug_add_store();
616987c715dcSDouglas Gilbert 				if (idx < 0)
617087c715dcSDouglas Gilbert 					return idx;
617187c715dcSDouglas Gilbert 			} else {
617287c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
617387c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
617487c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
6175cbf67842SDouglas Gilbert 			}
617687c715dcSDouglas Gilbert 			/* make all hosts use same store */
617787c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
617887c715dcSDouglas Gilbert 					    host_list) {
617987c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
618087c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
618187c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
618287c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
618387c715dcSDouglas Gilbert 				}
618487c715dcSDouglas Gilbert 			}
618587c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
618687c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
618787c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
6188cbf67842SDouglas Gilbert 		}
6189773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
619023183910SDouglas Gilbert 		return count;
619123183910SDouglas Gilbert 	}
619223183910SDouglas Gilbert 	return -EINVAL;
619323183910SDouglas Gilbert }
619482069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
619523183910SDouglas Gilbert 
no_lun_0_show(struct device_driver * ddp,char * buf)619682069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
6197c65b1445SDouglas Gilbert {
6198773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
6199c65b1445SDouglas Gilbert }
no_lun_0_store(struct device_driver * ddp,const char * buf,size_t count)620082069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
620182069379SAkinobu Mita 			      size_t count)
6202c65b1445SDouglas Gilbert {
6203c65b1445SDouglas Gilbert 	int n;
6204c65b1445SDouglas Gilbert 
6205c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6206773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
6207c65b1445SDouglas Gilbert 		return count;
6208c65b1445SDouglas Gilbert 	}
6209c65b1445SDouglas Gilbert 	return -EINVAL;
6210c65b1445SDouglas Gilbert }
621182069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
6212c65b1445SDouglas Gilbert 
num_tgts_show(struct device_driver * ddp,char * buf)621382069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
62141da177e4SLinus Torvalds {
6215773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
62161da177e4SLinus Torvalds }
num_tgts_store(struct device_driver * ddp,const char * buf,size_t count)621782069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
621882069379SAkinobu Mita 			      size_t count)
62191da177e4SLinus Torvalds {
62201da177e4SLinus Torvalds 	int n;
62211da177e4SLinus Torvalds 
62221da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6223773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
62241da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
62251da177e4SLinus Torvalds 		return count;
62261da177e4SLinus Torvalds 	}
62271da177e4SLinus Torvalds 	return -EINVAL;
62281da177e4SLinus Torvalds }
622982069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
62301da177e4SLinus Torvalds 
dev_size_mb_show(struct device_driver * ddp,char * buf)623182069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
62321da177e4SLinus Torvalds {
6233773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
62341da177e4SLinus Torvalds }
623582069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
62361da177e4SLinus Torvalds 
per_host_store_show(struct device_driver * ddp,char * buf)623787c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
623887c715dcSDouglas Gilbert {
623987c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
624087c715dcSDouglas Gilbert }
624187c715dcSDouglas Gilbert 
per_host_store_store(struct device_driver * ddp,const char * buf,size_t count)624287c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
624387c715dcSDouglas Gilbert 				    size_t count)
624487c715dcSDouglas Gilbert {
624587c715dcSDouglas Gilbert 	bool v;
624687c715dcSDouglas Gilbert 
624787c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
624887c715dcSDouglas Gilbert 		return -EINVAL;
624987c715dcSDouglas Gilbert 
625087c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
625187c715dcSDouglas Gilbert 	return count;
625287c715dcSDouglas Gilbert }
625387c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
625487c715dcSDouglas Gilbert 
num_parts_show(struct device_driver * ddp,char * buf)625582069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
62561da177e4SLinus Torvalds {
6257773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
62581da177e4SLinus Torvalds }
625982069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
62601da177e4SLinus Torvalds 
every_nth_show(struct device_driver * ddp,char * buf)626182069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
62621da177e4SLinus Torvalds {
6263773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
62641da177e4SLinus Torvalds }
every_nth_store(struct device_driver * ddp,const char * buf,size_t count)626582069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
626682069379SAkinobu Mita 			       size_t count)
62671da177e4SLinus Torvalds {
62681da177e4SLinus Torvalds 	int nth;
62693a90a63dSDouglas Gilbert 	char work[20];
62701da177e4SLinus Torvalds 
62713a90a63dSDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
62723a90a63dSDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
62733a90a63dSDouglas Gilbert 			if (kstrtoint(work + 2, 16, &nth) == 0)
62743a90a63dSDouglas Gilbert 				goto every_nth_done;
62753a90a63dSDouglas Gilbert 		} else {
62763a90a63dSDouglas Gilbert 			if (kstrtoint(work, 10, &nth) == 0)
62773a90a63dSDouglas Gilbert 				goto every_nth_done;
62783a90a63dSDouglas Gilbert 		}
62793a90a63dSDouglas Gilbert 	}
62803a90a63dSDouglas Gilbert 	return -EINVAL;
62813a90a63dSDouglas Gilbert 
62823a90a63dSDouglas Gilbert every_nth_done:
6283773642d9SDouglas Gilbert 	sdebug_every_nth = nth;
6284c4837394SDouglas Gilbert 	if (nth && !sdebug_statistics) {
6285c4837394SDouglas Gilbert 		pr_info("every_nth needs statistics=1, set it\n");
6286c4837394SDouglas Gilbert 		sdebug_statistics = true;
6287c4837394SDouglas Gilbert 	}
6288c4837394SDouglas Gilbert 	tweak_cmnd_count();
62891da177e4SLinus Torvalds 	return count;
62901da177e4SLinus Torvalds }
629182069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
62921da177e4SLinus Torvalds 
lun_format_show(struct device_driver * ddp,char * buf)6293ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6294ad0c7775SDouglas Gilbert {
6295ad0c7775SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6296ad0c7775SDouglas Gilbert }
lun_format_store(struct device_driver * ddp,const char * buf,size_t count)6297ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6298ad0c7775SDouglas Gilbert 				size_t count)
6299ad0c7775SDouglas Gilbert {
6300ad0c7775SDouglas Gilbert 	int n;
6301ad0c7775SDouglas Gilbert 	bool changed;
6302ad0c7775SDouglas Gilbert 
6303ad0c7775SDouglas Gilbert 	if (kstrtoint(buf, 0, &n))
6304ad0c7775SDouglas Gilbert 		return -EINVAL;
6305ad0c7775SDouglas Gilbert 	if (n >= 0) {
6306ad0c7775SDouglas Gilbert 		if (n > (int)SAM_LUN_AM_FLAT) {
6307ad0c7775SDouglas Gilbert 			pr_warn("only LUN address methods 0 and 1 are supported\n");
6308ad0c7775SDouglas Gilbert 			return -EINVAL;
6309ad0c7775SDouglas Gilbert 		}
6310ad0c7775SDouglas Gilbert 		changed = ((int)sdebug_lun_am != n);
6311ad0c7775SDouglas Gilbert 		sdebug_lun_am = n;
6312ad0c7775SDouglas Gilbert 		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
6313ad0c7775SDouglas Gilbert 			struct sdebug_host_info *sdhp;
6314ad0c7775SDouglas Gilbert 			struct sdebug_dev_info *dp;
6315ad0c7775SDouglas Gilbert 
63160aaa3fadSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
6317ad0c7775SDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6318ad0c7775SDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6319ad0c7775SDouglas Gilbert 					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6320ad0c7775SDouglas Gilbert 				}
6321ad0c7775SDouglas Gilbert 			}
63220aaa3fadSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
6323ad0c7775SDouglas Gilbert 		}
6324ad0c7775SDouglas Gilbert 		return count;
6325ad0c7775SDouglas Gilbert 	}
6326ad0c7775SDouglas Gilbert 	return -EINVAL;
6327ad0c7775SDouglas Gilbert }
6328ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format);
6329ad0c7775SDouglas Gilbert 
max_luns_show(struct device_driver * ddp,char * buf)633082069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
63311da177e4SLinus Torvalds {
6332773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
63331da177e4SLinus Torvalds }
max_luns_store(struct device_driver * ddp,const char * buf,size_t count)633482069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
633582069379SAkinobu Mita 			      size_t count)
63361da177e4SLinus Torvalds {
63371da177e4SLinus Torvalds 	int n;
633819c8ead7SEwan D. Milne 	bool changed;
63391da177e4SLinus Torvalds 
63401da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
63418d039e22SDouglas Gilbert 		if (n > 256) {
63428d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
63438d039e22SDouglas Gilbert 			return -EINVAL;
63448d039e22SDouglas Gilbert 		}
6345773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
6346773642d9SDouglas Gilbert 		sdebug_max_luns = n;
63471da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
6348773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
634919c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
635019c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
635119c8ead7SEwan D. Milne 
63520aaa3fadSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
635319c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
635419c8ead7SEwan D. Milne 					    host_list) {
635519c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
635619c8ead7SEwan D. Milne 						    dev_list) {
635719c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
635819c8ead7SEwan D. Milne 						dp->uas_bm);
635919c8ead7SEwan D. Milne 				}
636019c8ead7SEwan D. Milne 			}
63610aaa3fadSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
636219c8ead7SEwan D. Milne 		}
63631da177e4SLinus Torvalds 		return count;
63641da177e4SLinus Torvalds 	}
63651da177e4SLinus Torvalds 	return -EINVAL;
63661da177e4SLinus Torvalds }
636782069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
63681da177e4SLinus Torvalds 
max_queue_show(struct device_driver * ddp,char * buf)636982069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
637078d4e5a0SDouglas Gilbert {
6371773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
637278d4e5a0SDouglas Gilbert }
6373cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
6374cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
max_queue_store(struct device_driver * ddp,const char * buf,size_t count)637582069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
637682069379SAkinobu Mita 			       size_t count)
637778d4e5a0SDouglas Gilbert {
637857f7225aSJohn Garry 	int n;
637978d4e5a0SDouglas Gilbert 
638078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
6381c10fa55fSJohn Garry 	    (n <= SDEBUG_CANQUEUE) &&
6382c10fa55fSJohn Garry 	    (sdebug_host_max_queue == 0)) {
638325b80b2cSJohn Garry 		mutex_lock(&sdebug_host_list_mutex);
638457f7225aSJohn Garry 
638557f7225aSJohn Garry 		/* We may only change sdebug_max_queue when we have no shosts */
638657f7225aSJohn Garry 		if (list_empty(&sdebug_host_list))
6387773642d9SDouglas Gilbert 			sdebug_max_queue = n;
6388cbf67842SDouglas Gilbert 		else
638957f7225aSJohn Garry 			count = -EBUSY;
639025b80b2cSJohn Garry 		mutex_unlock(&sdebug_host_list_mutex);
639178d4e5a0SDouglas Gilbert 		return count;
639278d4e5a0SDouglas Gilbert 	}
639378d4e5a0SDouglas Gilbert 	return -EINVAL;
639478d4e5a0SDouglas Gilbert }
639582069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
639678d4e5a0SDouglas Gilbert 
host_max_queue_show(struct device_driver * ddp,char * buf)6397c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6398c10fa55fSJohn Garry {
6399c10fa55fSJohn Garry 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6400c10fa55fSJohn Garry }
6401c10fa55fSJohn Garry 
no_rwlock_show(struct device_driver * ddp,char * buf)64027109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
64037109f370SDouglas Gilbert {
64047109f370SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
64057109f370SDouglas Gilbert }
64067109f370SDouglas Gilbert 
no_rwlock_store(struct device_driver * ddp,const char * buf,size_t count)64077109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
64087109f370SDouglas Gilbert {
64097109f370SDouglas Gilbert 	bool v;
64107109f370SDouglas Gilbert 
64117109f370SDouglas Gilbert 	if (kstrtobool(buf, &v))
64127109f370SDouglas Gilbert 		return -EINVAL;
64137109f370SDouglas Gilbert 
64147109f370SDouglas Gilbert 	sdebug_no_rwlock = v;
64157109f370SDouglas Gilbert 	return count;
64167109f370SDouglas Gilbert }
64177109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock);
64187109f370SDouglas Gilbert 
6419c10fa55fSJohn Garry /*
6420c10fa55fSJohn Garry  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6421c10fa55fSJohn Garry  * in range [0, sdebug_host_max_queue), we can't change it.
6422c10fa55fSJohn Garry  */
6423c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue);
6424c10fa55fSJohn Garry 
no_uld_show(struct device_driver * ddp,char * buf)642582069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
642678d4e5a0SDouglas Gilbert {
6427773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
642878d4e5a0SDouglas Gilbert }
642982069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
643078d4e5a0SDouglas Gilbert 
scsi_level_show(struct device_driver * ddp,char * buf)643182069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
64321da177e4SLinus Torvalds {
6433773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
64341da177e4SLinus Torvalds }
643582069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
64361da177e4SLinus Torvalds 
virtual_gb_show(struct device_driver * ddp,char * buf)643782069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
6438c65b1445SDouglas Gilbert {
6439773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
6440c65b1445SDouglas Gilbert }
virtual_gb_store(struct device_driver * ddp,const char * buf,size_t count)644182069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
644282069379SAkinobu Mita 				size_t count)
6443c65b1445SDouglas Gilbert {
6444c65b1445SDouglas Gilbert 	int n;
64450d01c5dfSDouglas Gilbert 	bool changed;
6446c65b1445SDouglas Gilbert 
6447f0d1cf93SDouglas Gilbert 	/* Ignore capacity change for ZBC drives for now */
6448f0d1cf93SDouglas Gilbert 	if (sdeb_zbc_in_use)
6449f0d1cf93SDouglas Gilbert 		return -ENOTSUPP;
6450f0d1cf93SDouglas Gilbert 
6451c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6452773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
6453773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
645428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
64550d01c5dfSDouglas Gilbert 		if (changed) {
64560d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
64570d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
645828898873SFUJITA Tomonori 
64590aaa3fadSJohn Garry 			mutex_lock(&sdebug_host_list_mutex);
64600d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
64610d01c5dfSDouglas Gilbert 					    host_list) {
64620d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
64630d01c5dfSDouglas Gilbert 						    dev_list) {
64640d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
64650d01c5dfSDouglas Gilbert 						dp->uas_bm);
64660d01c5dfSDouglas Gilbert 				}
64670d01c5dfSDouglas Gilbert 			}
64680aaa3fadSJohn Garry 			mutex_unlock(&sdebug_host_list_mutex);
64690d01c5dfSDouglas Gilbert 		}
6470c65b1445SDouglas Gilbert 		return count;
6471c65b1445SDouglas Gilbert 	}
6472c65b1445SDouglas Gilbert 	return -EINVAL;
6473c65b1445SDouglas Gilbert }
647482069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
6475c65b1445SDouglas Gilbert 
add_host_show(struct device_driver * ddp,char * buf)647682069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
64771da177e4SLinus Torvalds {
647887c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
6479f19fe8f3SBart Van Assche 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
64801da177e4SLinus Torvalds }
64811da177e4SLinus Torvalds 
add_host_store(struct device_driver * ddp,const char * buf,size_t count)648282069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
648382069379SAkinobu Mita 			      size_t count)
64841da177e4SLinus Torvalds {
6485f19fe8f3SBart Van Assche 	bool found;
6486f19fe8f3SBart Van Assche 	unsigned long idx;
6487f19fe8f3SBart Van Assche 	struct sdeb_store_info *sip;
6488f19fe8f3SBart Van Assche 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
64891da177e4SLinus Torvalds 	int delta_hosts;
64901da177e4SLinus Torvalds 
6491f19fe8f3SBart Van Assche 	if (sscanf(buf, "%d", &delta_hosts) != 1)
64921da177e4SLinus Torvalds 		return -EINVAL;
64931da177e4SLinus Torvalds 	if (delta_hosts > 0) {
64941da177e4SLinus Torvalds 		do {
6495f19fe8f3SBart Van Assche 			found = false;
6496f19fe8f3SBart Van Assche 			if (want_phs) {
6497f19fe8f3SBart Van Assche 				xa_for_each_marked(per_store_ap, idx, sip,
6498f19fe8f3SBart Van Assche 						   SDEB_XA_NOT_IN_USE) {
6499f19fe8f3SBart Van Assche 					sdeb_most_recent_idx = (int)idx;
6500f19fe8f3SBart Van Assche 					found = true;
650187c715dcSDouglas Gilbert 					break;
650287c715dcSDouglas Gilbert 				}
6503f19fe8f3SBart Van Assche 				if (found)	/* re-use case */
6504f19fe8f3SBart Van Assche 					sdebug_add_host_helper((int)idx);
6505f19fe8f3SBart Van Assche 				else
6506f19fe8f3SBart Van Assche 					sdebug_do_add_host(true);
6507f19fe8f3SBart Van Assche 			} else {
6508f19fe8f3SBart Van Assche 				sdebug_do_add_host(false);
6509f19fe8f3SBart Van Assche 			}
6510f19fe8f3SBart Van Assche 		} while (--delta_hosts);
6511f19fe8f3SBart Van Assche 	} else if (delta_hosts < 0) {
6512f19fe8f3SBart Van Assche 		do {
651387c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
65141da177e4SLinus Torvalds 		} while (++delta_hosts);
65151da177e4SLinus Torvalds 	}
65161da177e4SLinus Torvalds 	return count;
65171da177e4SLinus Torvalds }
651882069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
65191da177e4SLinus Torvalds 
vpd_use_hostno_show(struct device_driver * ddp,char * buf)652082069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
652123183910SDouglas Gilbert {
6522773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
652323183910SDouglas Gilbert }
vpd_use_hostno_store(struct device_driver * ddp,const char * buf,size_t count)652482069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
652582069379SAkinobu Mita 				    size_t count)
652623183910SDouglas Gilbert {
652723183910SDouglas Gilbert 	int n;
652823183910SDouglas Gilbert 
652923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6530773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
653123183910SDouglas Gilbert 		return count;
653223183910SDouglas Gilbert 	}
653323183910SDouglas Gilbert 	return -EINVAL;
653423183910SDouglas Gilbert }
653582069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
653623183910SDouglas Gilbert 
statistics_show(struct device_driver * ddp,char * buf)6537c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6538c4837394SDouglas Gilbert {
6539c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6540c4837394SDouglas Gilbert }
statistics_store(struct device_driver * ddp,const char * buf,size_t count)6541c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6542c4837394SDouglas Gilbert 				size_t count)
6543c4837394SDouglas Gilbert {
6544c4837394SDouglas Gilbert 	int n;
6545c4837394SDouglas Gilbert 
6546c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6547c4837394SDouglas Gilbert 		if (n > 0)
6548c4837394SDouglas Gilbert 			sdebug_statistics = true;
6549c4837394SDouglas Gilbert 		else {
6550c4837394SDouglas Gilbert 			clear_queue_stats();
6551c4837394SDouglas Gilbert 			sdebug_statistics = false;
6552c4837394SDouglas Gilbert 		}
6553c4837394SDouglas Gilbert 		return count;
6554c4837394SDouglas Gilbert 	}
6555c4837394SDouglas Gilbert 	return -EINVAL;
6556c4837394SDouglas Gilbert }
6557c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
6558c4837394SDouglas Gilbert 
sector_size_show(struct device_driver * ddp,char * buf)655982069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
6560597136abSMartin K. Petersen {
6561773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
6562597136abSMartin K. Petersen }
656382069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
6564597136abSMartin K. Petersen 
submit_queues_show(struct device_driver * ddp,char * buf)6565c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6566c4837394SDouglas Gilbert {
6567c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6568c4837394SDouglas Gilbert }
6569c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
6570c4837394SDouglas Gilbert 
dix_show(struct device_driver * ddp,char * buf)657182069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
6572c6a44287SMartin K. Petersen {
6573773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
6574c6a44287SMartin K. Petersen }
657582069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
6576c6a44287SMartin K. Petersen 
dif_show(struct device_driver * ddp,char * buf)657782069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
6578c6a44287SMartin K. Petersen {
6579773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
6580c6a44287SMartin K. Petersen }
658182069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
6582c6a44287SMartin K. Petersen 
guard_show(struct device_driver * ddp,char * buf)658382069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
6584c6a44287SMartin K. Petersen {
6585773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
6586c6a44287SMartin K. Petersen }
658782069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
6588c6a44287SMartin K. Petersen 
ato_show(struct device_driver * ddp,char * buf)658982069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
6590c6a44287SMartin K. Petersen {
6591773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
6592c6a44287SMartin K. Petersen }
659382069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
6594c6a44287SMartin K. Petersen 
map_show(struct device_driver * ddp,char * buf)659582069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
659644d92694SMartin K. Petersen {
659787c715dcSDouglas Gilbert 	ssize_t count = 0;
659844d92694SMartin K. Petersen 
65995b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
660044d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
660144d92694SMartin K. Petersen 				 sdebug_store_sectors);
660244d92694SMartin K. Petersen 
660387c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
660487c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
660587c715dcSDouglas Gilbert 
660687c715dcSDouglas Gilbert 		if (sip)
6607c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
660887c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
660987c715dcSDouglas Gilbert 	}
661044d92694SMartin K. Petersen 	buf[count++] = '\n';
6611c7badc90STejun Heo 	buf[count] = '\0';
661244d92694SMartin K. Petersen 
661344d92694SMartin K. Petersen 	return count;
661444d92694SMartin K. Petersen }
661582069379SAkinobu Mita static DRIVER_ATTR_RO(map);
661644d92694SMartin K. Petersen 
random_show(struct device_driver * ddp,char * buf)66170c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
66180c4bc91dSDouglas Gilbert {
66190c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
66200c4bc91dSDouglas Gilbert }
66210c4bc91dSDouglas Gilbert 
random_store(struct device_driver * ddp,const char * buf,size_t count)66220c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
66230c4bc91dSDouglas Gilbert 			    size_t count)
66240c4bc91dSDouglas Gilbert {
66250c4bc91dSDouglas Gilbert 	bool v;
66260c4bc91dSDouglas Gilbert 
66270c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
66280c4bc91dSDouglas Gilbert 		return -EINVAL;
66290c4bc91dSDouglas Gilbert 
66300c4bc91dSDouglas Gilbert 	sdebug_random = v;
66310c4bc91dSDouglas Gilbert 	return count;
66320c4bc91dSDouglas Gilbert }
66330c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
66340c4bc91dSDouglas Gilbert 
removable_show(struct device_driver * ddp,char * buf)663582069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
6636d986788bSMartin Pitt {
6637773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
6638d986788bSMartin Pitt }
removable_store(struct device_driver * ddp,const char * buf,size_t count)663982069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
664082069379SAkinobu Mita 			       size_t count)
6641d986788bSMartin Pitt {
6642d986788bSMartin Pitt 	int n;
6643d986788bSMartin Pitt 
6644d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6645773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
6646d986788bSMartin Pitt 		return count;
6647d986788bSMartin Pitt 	}
6648d986788bSMartin Pitt 	return -EINVAL;
6649d986788bSMartin Pitt }
665082069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
6651d986788bSMartin Pitt 
host_lock_show(struct device_driver * ddp,char * buf)6652cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6653cbf67842SDouglas Gilbert {
6654773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
6655cbf67842SDouglas Gilbert }
6656185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
host_lock_store(struct device_driver * ddp,const char * buf,size_t count)6657cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6658cbf67842SDouglas Gilbert 			       size_t count)
6659cbf67842SDouglas Gilbert {
6660185dd232SDouglas Gilbert 	int n;
6661cbf67842SDouglas Gilbert 
6662cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6663185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
6664185dd232SDouglas Gilbert 		return count;
6665cbf67842SDouglas Gilbert 	}
6666cbf67842SDouglas Gilbert 	return -EINVAL;
6667cbf67842SDouglas Gilbert }
6668cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
6669cbf67842SDouglas Gilbert 
strict_show(struct device_driver * ddp,char * buf)6670c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
6671c2248fc9SDouglas Gilbert {
6672773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
6673c2248fc9SDouglas Gilbert }
strict_store(struct device_driver * ddp,const char * buf,size_t count)6674c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6675c2248fc9SDouglas Gilbert 			    size_t count)
6676c2248fc9SDouglas Gilbert {
6677c2248fc9SDouglas Gilbert 	int n;
6678c2248fc9SDouglas Gilbert 
6679c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
6680773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
6681c2248fc9SDouglas Gilbert 		return count;
6682c2248fc9SDouglas Gilbert 	}
6683c2248fc9SDouglas Gilbert 	return -EINVAL;
6684c2248fc9SDouglas Gilbert }
6685c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
6686c2248fc9SDouglas Gilbert 
uuid_ctl_show(struct device_driver * ddp,char * buf)668709ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
668809ba24c1SDouglas Gilbert {
668909ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
669009ba24c1SDouglas Gilbert }
669109ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
669209ba24c1SDouglas Gilbert 
cdb_len_show(struct device_driver * ddp,char * buf)66939b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
66949b760fd8SDouglas Gilbert {
66959b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
66969b760fd8SDouglas Gilbert }
cdb_len_store(struct device_driver * ddp,const char * buf,size_t count)66979b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
66989b760fd8SDouglas Gilbert 			     size_t count)
66999b760fd8SDouglas Gilbert {
67009b760fd8SDouglas Gilbert 	int ret, n;
67019b760fd8SDouglas Gilbert 
67029b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
67039b760fd8SDouglas Gilbert 	if (ret)
67049b760fd8SDouglas Gilbert 		return ret;
67059b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
67069b760fd8SDouglas Gilbert 	all_config_cdb_len();
67079b760fd8SDouglas Gilbert 	return count;
67089b760fd8SDouglas Gilbert }
67099b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
67109b760fd8SDouglas Gilbert 
67119267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = {
67129267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "none",
67139267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "host-aware",
67149267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "host-managed",
67159267e0ebSDouglas Gilbert };
67169267e0ebSDouglas Gilbert 
67179267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = {
67189267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "no",
67199267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "aware",
67209267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "managed",
67219267e0ebSDouglas Gilbert };
67229267e0ebSDouglas Gilbert 
67239267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = {
67249267e0ebSDouglas Gilbert 	[BLK_ZONED_NONE] = "0",
67259267e0ebSDouglas Gilbert 	[BLK_ZONED_HA]   = "1",
67269267e0ebSDouglas Gilbert 	[BLK_ZONED_HM]   = "2",
67279267e0ebSDouglas Gilbert };
67289267e0ebSDouglas Gilbert 
sdeb_zbc_model_str(const char * cp)67299267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp)
67309267e0ebSDouglas Gilbert {
67319267e0ebSDouglas Gilbert 	int res = sysfs_match_string(zbc_model_strs_a, cp);
67329267e0ebSDouglas Gilbert 
67339267e0ebSDouglas Gilbert 	if (res < 0) {
67349267e0ebSDouglas Gilbert 		res = sysfs_match_string(zbc_model_strs_b, cp);
67359267e0ebSDouglas Gilbert 		if (res < 0) {
67369267e0ebSDouglas Gilbert 			res = sysfs_match_string(zbc_model_strs_c, cp);
673747742bdeSDan Carpenter 			if (res < 0)
67389267e0ebSDouglas Gilbert 				return -EINVAL;
67399267e0ebSDouglas Gilbert 		}
67409267e0ebSDouglas Gilbert 	}
67419267e0ebSDouglas Gilbert 	return res;
67429267e0ebSDouglas Gilbert }
67439267e0ebSDouglas Gilbert 
zbc_show(struct device_driver * ddp,char * buf)67449267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf)
67459267e0ebSDouglas Gilbert {
67469267e0ebSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%s\n",
67479267e0ebSDouglas Gilbert 			 zbc_model_strs_a[sdeb_zbc_model]);
67489267e0ebSDouglas Gilbert }
67499267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc);
6750cbf67842SDouglas Gilbert 
tur_ms_to_ready_show(struct device_driver * ddp,char * buf)6751fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6752fc13638aSDouglas Gilbert {
6753fc13638aSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6754fc13638aSDouglas Gilbert }
6755fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready);
6756fc13638aSDouglas Gilbert 
675782069379SAkinobu Mita /* Note: The following array creates attribute files in the
675823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
675923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
676023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
676187c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
676223183910SDouglas Gilbert  */
67636ecaff7fSRandy Dunlap 
676482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
676582069379SAkinobu Mita 	&driver_attr_delay.attr,
676682069379SAkinobu Mita 	&driver_attr_opts.attr,
676782069379SAkinobu Mita 	&driver_attr_ptype.attr,
676882069379SAkinobu Mita 	&driver_attr_dsense.attr,
676982069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
6770c10fa55fSJohn Garry 	&driver_attr_host_max_queue.attr,
677182069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
677282069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
677382069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
677482069379SAkinobu Mita 	&driver_attr_num_parts.attr,
677582069379SAkinobu Mita 	&driver_attr_every_nth.attr,
6776ad0c7775SDouglas Gilbert 	&driver_attr_lun_format.attr,
677782069379SAkinobu Mita 	&driver_attr_max_luns.attr,
677882069379SAkinobu Mita 	&driver_attr_max_queue.attr,
67797109f370SDouglas Gilbert 	&driver_attr_no_rwlock.attr,
678082069379SAkinobu Mita 	&driver_attr_no_uld.attr,
678182069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
678282069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
678382069379SAkinobu Mita 	&driver_attr_add_host.attr,
678487c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
678582069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
678682069379SAkinobu Mita 	&driver_attr_sector_size.attr,
6787c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
6788c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
678982069379SAkinobu Mita 	&driver_attr_dix.attr,
679082069379SAkinobu Mita 	&driver_attr_dif.attr,
679182069379SAkinobu Mita 	&driver_attr_guard.attr,
679282069379SAkinobu Mita 	&driver_attr_ato.attr,
679382069379SAkinobu Mita 	&driver_attr_map.attr,
67940c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
679582069379SAkinobu Mita 	&driver_attr_removable.attr,
6796cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
6797cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
6798c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
679909ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
68009b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
6801fc13638aSDouglas Gilbert 	&driver_attr_tur_ms_to_ready.attr,
68029267e0ebSDouglas Gilbert 	&driver_attr_zbc.attr,
680382069379SAkinobu Mita 	NULL,
680482069379SAkinobu Mita };
680582069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
68061da177e4SLinus Torvalds 
680711ddcecaSAkinobu Mita static struct device *pseudo_primary;
68088dea0d02SFUJITA Tomonori 
scsi_debug_init(void)68091da177e4SLinus Torvalds static int __init scsi_debug_init(void)
68101da177e4SLinus Torvalds {
681187c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
68125f2578e5SFUJITA Tomonori 	unsigned long sz;
681387c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
681487c715dcSDouglas Gilbert 	int idx = -1;
68151da177e4SLinus Torvalds 
6816773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
6817c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
6818773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
6819773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
6820c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
6821cbf67842SDouglas Gilbert 
6822773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
6823597136abSMartin K. Petersen 	case  512:
6824597136abSMartin K. Petersen 	case 1024:
6825597136abSMartin K. Petersen 	case 2048:
6826597136abSMartin K. Petersen 	case 4096:
6827597136abSMartin K. Petersen 		break;
6828597136abSMartin K. Petersen 	default:
6829773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
6830597136abSMartin K. Petersen 		return -EINVAL;
6831597136abSMartin K. Petersen 	}
6832597136abSMartin K. Petersen 
6833773642d9SDouglas Gilbert 	switch (sdebug_dif) {
68348475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
6835f46eb0e9SDouglas Gilbert 		break;
68368475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
68378475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
68388475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6839f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
6840c6a44287SMartin K. Petersen 		break;
6841c6a44287SMartin K. Petersen 
6842c6a44287SMartin K. Petersen 	default:
6843c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
6844c6a44287SMartin K. Petersen 		return -EINVAL;
6845c6a44287SMartin K. Petersen 	}
6846c6a44287SMartin K. Petersen 
6847aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
6848aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
6849aa5334c4SMaurizio Lombardi 		return -EINVAL;
6850aa5334c4SMaurizio Lombardi 	}
6851aa5334c4SMaurizio Lombardi 
6852773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
6853c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
6854c6a44287SMartin K. Petersen 		return -EINVAL;
6855c6a44287SMartin K. Petersen 	}
6856c6a44287SMartin K. Petersen 
6857773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
6858c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
6859c6a44287SMartin K. Petersen 		return -EINVAL;
6860c6a44287SMartin K. Petersen 	}
6861c6a44287SMartin K. Petersen 
6862773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
6863773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
6864ea61fca5SMartin K. Petersen 		return -EINVAL;
6865ea61fca5SMartin K. Petersen 	}
6866ad0c7775SDouglas Gilbert 
6867ad0c7775SDouglas Gilbert 	sdebug_lun_am = sdebug_lun_am_i;
6868ad0c7775SDouglas Gilbert 	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6869ad0c7775SDouglas Gilbert 		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6870ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6871ad0c7775SDouglas Gilbert 	}
6872ad0c7775SDouglas Gilbert 
68738d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
6874ad0c7775SDouglas Gilbert 		if (sdebug_max_luns > 16384) {
6875ad0c7775SDouglas Gilbert 			pr_warn("max_luns can be no more than 16384, use default\n");
68768d039e22SDouglas Gilbert 			sdebug_max_luns = DEF_MAX_LUNS;
68778d039e22SDouglas Gilbert 		}
6878ad0c7775SDouglas Gilbert 		sdebug_lun_am = SAM_LUN_AM_FLAT;
6879ad0c7775SDouglas Gilbert 	}
6880ea61fca5SMartin K. Petersen 
6881773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
6882773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
6883ea61fca5SMartin K. Petersen 		return -EINVAL;
6884ea61fca5SMartin K. Petersen 	}
6885ea61fca5SMartin K. Petersen 
6886c4837394SDouglas Gilbert 	if (submit_queues < 1) {
6887c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
6888c4837394SDouglas Gilbert 		return -EINVAL;
6889c4837394SDouglas Gilbert 	}
6890c87bf24cSJohn Garry 
6891c87bf24cSJohn Garry 	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6892c87bf24cSJohn Garry 		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6893c87bf24cSJohn Garry 		return -EINVAL;
6894c87bf24cSJohn Garry 	}
6895c87bf24cSJohn Garry 
6896c10fa55fSJohn Garry 	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6897c10fa55fSJohn Garry 	    (sdebug_host_max_queue < 0)) {
6898c10fa55fSJohn Garry 		pr_err("host_max_queue must be in range [0 %d]\n",
6899c10fa55fSJohn Garry 		       SDEBUG_CANQUEUE);
6900c10fa55fSJohn Garry 		return -EINVAL;
6901c10fa55fSJohn Garry 	}
6902c10fa55fSJohn Garry 
6903c10fa55fSJohn Garry 	if (sdebug_host_max_queue &&
6904c10fa55fSJohn Garry 	    (sdebug_max_queue != sdebug_host_max_queue)) {
6905c10fa55fSJohn Garry 		sdebug_max_queue = sdebug_host_max_queue;
6906c10fa55fSJohn Garry 		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6907c10fa55fSJohn Garry 			sdebug_max_queue);
6908c10fa55fSJohn Garry 	}
6909c10fa55fSJohn Garry 
6910f0d1cf93SDouglas Gilbert 	/*
69119267e0ebSDouglas Gilbert 	 * check for host managed zoned block device specified with
69129267e0ebSDouglas Gilbert 	 * ptype=0x14 or zbc=XXX.
6913f0d1cf93SDouglas Gilbert 	 */
69149267e0ebSDouglas Gilbert 	if (sdebug_ptype == TYPE_ZBC) {
69159267e0ebSDouglas Gilbert 		sdeb_zbc_model = BLK_ZONED_HM;
69169267e0ebSDouglas Gilbert 	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
69179267e0ebSDouglas Gilbert 		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
6918f1437cd1SJohn Garry 		if (k < 0)
6919f1437cd1SJohn Garry 			return k;
69209267e0ebSDouglas Gilbert 		sdeb_zbc_model = k;
69219267e0ebSDouglas Gilbert 		switch (sdeb_zbc_model) {
69229267e0ebSDouglas Gilbert 		case BLK_ZONED_NONE:
692364e14eceSDamien Le Moal 		case BLK_ZONED_HA:
69249267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_DISK;
69259267e0ebSDouglas Gilbert 			break;
69269267e0ebSDouglas Gilbert 		case BLK_ZONED_HM:
69279267e0ebSDouglas Gilbert 			sdebug_ptype = TYPE_ZBC;
69289267e0ebSDouglas Gilbert 			break;
69299267e0ebSDouglas Gilbert 		default:
69309267e0ebSDouglas Gilbert 			pr_err("Invalid ZBC model\n");
6931f1437cd1SJohn Garry 			return -EINVAL;
69329267e0ebSDouglas Gilbert 		}
69339267e0ebSDouglas Gilbert 	}
69349267e0ebSDouglas Gilbert 	if (sdeb_zbc_model != BLK_ZONED_NONE) {
6935f0d1cf93SDouglas Gilbert 		sdeb_zbc_in_use = true;
69369267e0ebSDouglas Gilbert 		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
69379267e0ebSDouglas Gilbert 			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
69389267e0ebSDouglas Gilbert 	}
6939f0d1cf93SDouglas Gilbert 
69409267e0ebSDouglas Gilbert 	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
69419267e0ebSDouglas Gilbert 		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
6942773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
6943773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
6944773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6945773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
694628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
69471da177e4SLinus Torvalds 
69481da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
69491da177e4SLinus Torvalds 	sdebug_heads = 8;
69501da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
6951773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
69521da177e4SLinus Torvalds 		sdebug_heads = 64;
6953773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
6954fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
69551da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
69561da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
69571da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
69581da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
69591da177e4SLinus Torvalds 		sdebug_heads = 255;
69601da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
69611da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
69621da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
69631da177e4SLinus Torvalds 	}
69645b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
6965773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
6966773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
69676014759cSMartin K. Petersen 
6968773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
6969773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
69706014759cSMartin K. Petersen 
6971773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
6972773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
69736014759cSMartin K. Petersen 
6974773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
6975773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
6976773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
6977c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
6978f1437cd1SJohn Garry 			return -EINVAL;
697944d92694SMartin K. Petersen 		}
698044d92694SMartin K. Petersen 	}
698187c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
698287c715dcSDouglas Gilbert 	if (want_store) {
698387c715dcSDouglas Gilbert 		idx = sdebug_add_store();
6984f1437cd1SJohn Garry 		if (idx < 0)
6985f1437cd1SJohn Garry 			return idx;
698644d92694SMartin K. Petersen 	}
698744d92694SMartin K. Petersen 
69889b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
69899b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
6990c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
69919b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
69926ecaff7fSRandy Dunlap 		goto free_vm;
69936ecaff7fSRandy Dunlap 	}
69946ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
69956ecaff7fSRandy Dunlap 	if (ret < 0) {
6996c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
69976ecaff7fSRandy Dunlap 		goto dev_unreg;
69986ecaff7fSRandy Dunlap 	}
69996ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
70006ecaff7fSRandy Dunlap 	if (ret < 0) {
7001c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
70026ecaff7fSRandy Dunlap 		goto bus_unreg;
70036ecaff7fSRandy Dunlap 	}
70041da177e4SLinus Torvalds 
700587c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
7006773642d9SDouglas Gilbert 	sdebug_add_host = 0;
70071da177e4SLinus Torvalds 
70081107c7b2SJohn Garry 	queued_cmd_cache = KMEM_CACHE(sdebug_queued_cmd, SLAB_HWCACHE_ALIGN);
7009b32283d7SHarshit Mogalapalli 	if (!queued_cmd_cache) {
7010b32283d7SHarshit Mogalapalli 		ret = -ENOMEM;
70111107c7b2SJohn Garry 		goto driver_unreg;
7012b32283d7SHarshit Mogalapalli 	}
70131107c7b2SJohn Garry 
701487c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
701587c715dcSDouglas Gilbert 		if (want_store && k == 0) {
701687c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
701787c715dcSDouglas Gilbert 			if (ret < 0) {
701887c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
701987c715dcSDouglas Gilbert 				       k, -ret);
702087c715dcSDouglas Gilbert 				break;
702187c715dcSDouglas Gilbert 			}
702287c715dcSDouglas Gilbert 		} else {
702387c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
702487c715dcSDouglas Gilbert 						 sdebug_per_host_store);
702587c715dcSDouglas Gilbert 			if (ret < 0) {
702687c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
70271da177e4SLinus Torvalds 				break;
70281da177e4SLinus Torvalds 			}
70291da177e4SLinus Torvalds 		}
703087c715dcSDouglas Gilbert 	}
7031773642d9SDouglas Gilbert 	if (sdebug_verbose)
7032f19fe8f3SBart Van Assche 		pr_info("built %d host(s)\n", sdebug_num_hosts);
7033c1287970STomas Winkler 
70341da177e4SLinus Torvalds 	return 0;
70356ecaff7fSRandy Dunlap 
70361107c7b2SJohn Garry driver_unreg:
70371107c7b2SJohn Garry 	driver_unregister(&sdebug_driverfs_driver);
70386ecaff7fSRandy Dunlap bus_unreg:
70396ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
70406ecaff7fSRandy Dunlap dev_unreg:
70419b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
70426ecaff7fSRandy Dunlap free_vm:
704387c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
70446ecaff7fSRandy Dunlap 	return ret;
70451da177e4SLinus Torvalds }
70461da177e4SLinus Torvalds 
scsi_debug_exit(void)70471da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
70481da177e4SLinus Torvalds {
7049f19fe8f3SBart Van Assche 	int k = sdebug_num_hosts;
70501da177e4SLinus Torvalds 
7051f19fe8f3SBart Van Assche 	for (; k; k--)
705287c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
70531107c7b2SJohn Garry 	kmem_cache_destroy(queued_cmd_cache);
70541da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
70551da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
70569b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
70571da177e4SLinus Torvalds 
705887c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
705987c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
70601da177e4SLinus Torvalds }
70611da177e4SLinus Torvalds 
70621da177e4SLinus Torvalds device_initcall(scsi_debug_init);
70631da177e4SLinus Torvalds module_exit(scsi_debug_exit);
70641da177e4SLinus Torvalds 
sdebug_release_adapter(struct device * dev)70651da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
70661da177e4SLinus Torvalds {
70671da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
70681da177e4SLinus Torvalds 
7069785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
70701da177e4SLinus Torvalds 	kfree(sdbg_host);
70711da177e4SLinus Torvalds }
70721da177e4SLinus Torvalds 
707387c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
sdebug_erase_store(int idx,struct sdeb_store_info * sip)707487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
70751da177e4SLinus Torvalds {
707687c715dcSDouglas Gilbert 	if (idx < 0)
707787c715dcSDouglas Gilbert 		return;
707887c715dcSDouglas Gilbert 	if (!sip) {
707987c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
708087c715dcSDouglas Gilbert 			return;
708187c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
708287c715dcSDouglas Gilbert 		if (!sip)
708387c715dcSDouglas Gilbert 			return;
708487c715dcSDouglas Gilbert 	}
708587c715dcSDouglas Gilbert 	vfree(sip->map_storep);
708687c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
708787c715dcSDouglas Gilbert 	vfree(sip->storep);
708887c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
708987c715dcSDouglas Gilbert 	kfree(sip);
709087c715dcSDouglas Gilbert }
709187c715dcSDouglas Gilbert 
709287c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
sdebug_erase_all_stores(bool apart_from_first)709387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
709487c715dcSDouglas Gilbert {
709587c715dcSDouglas Gilbert 	unsigned long idx;
709687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
709787c715dcSDouglas Gilbert 
709887c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
709987c715dcSDouglas Gilbert 		if (apart_from_first)
710087c715dcSDouglas Gilbert 			apart_from_first = false;
710187c715dcSDouglas Gilbert 		else
710287c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
710387c715dcSDouglas Gilbert 	}
710487c715dcSDouglas Gilbert 	if (apart_from_first)
710587c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
710687c715dcSDouglas Gilbert }
710787c715dcSDouglas Gilbert 
710887c715dcSDouglas Gilbert /*
710987c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
711087c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
711187c715dcSDouglas Gilbert  */
sdebug_add_store(void)711287c715dcSDouglas Gilbert static int sdebug_add_store(void)
711387c715dcSDouglas Gilbert {
711487c715dcSDouglas Gilbert 	int res;
711587c715dcSDouglas Gilbert 	u32 n_idx;
711687c715dcSDouglas Gilbert 	unsigned long iflags;
711787c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
711887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
711987c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
712087c715dcSDouglas Gilbert 
712187c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
712287c715dcSDouglas Gilbert 	if (!sip)
712387c715dcSDouglas Gilbert 		return -ENOMEM;
712487c715dcSDouglas Gilbert 
712587c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
712687c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
712787c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
712887c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
712987c715dcSDouglas Gilbert 		kfree(sip);
713087c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
713187c715dcSDouglas Gilbert 		return res;
713287c715dcSDouglas Gilbert 	}
713387c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
713487c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
713587c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
713687c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
713787c715dcSDouglas Gilbert 
713887c715dcSDouglas Gilbert 	res = -ENOMEM;
713987c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
714087c715dcSDouglas Gilbert 	if (!sip->storep) {
714187c715dcSDouglas Gilbert 		pr_err("user data oom\n");
714287c715dcSDouglas Gilbert 		goto err;
714387c715dcSDouglas Gilbert 	}
714487c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
714587c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
714687c715dcSDouglas Gilbert 
714787c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
714887c715dcSDouglas Gilbert 	if (sdebug_dix) {
714987c715dcSDouglas Gilbert 		int dif_size;
715087c715dcSDouglas Gilbert 
715187c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
715287c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
715387c715dcSDouglas Gilbert 
715487c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
715587c715dcSDouglas Gilbert 			sip->dif_storep);
715687c715dcSDouglas Gilbert 
715787c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
715887c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
715987c715dcSDouglas Gilbert 			goto err;
716087c715dcSDouglas Gilbert 		}
716187c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
716287c715dcSDouglas Gilbert 	}
716387c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
716487c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
716587c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
716687c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
716787c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
716887c715dcSDouglas Gilbert 
716987c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
717087c715dcSDouglas Gilbert 
717187c715dcSDouglas Gilbert 		if (!sip->map_storep) {
717287c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
717387c715dcSDouglas Gilbert 			goto err;
717487c715dcSDouglas Gilbert 		}
717587c715dcSDouglas Gilbert 
717687c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
717787c715dcSDouglas Gilbert 
717887c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
717987c715dcSDouglas Gilbert 		if (sdebug_num_parts)
718087c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
718187c715dcSDouglas Gilbert 	}
718287c715dcSDouglas Gilbert 
718387c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
718487c715dcSDouglas Gilbert 	return (int)n_idx;
718587c715dcSDouglas Gilbert err:
718687c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
718787c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
718887c715dcSDouglas Gilbert 	return res;
718987c715dcSDouglas Gilbert }
719087c715dcSDouglas Gilbert 
sdebug_add_host_helper(int per_host_idx)719187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
719287c715dcSDouglas Gilbert {
719387c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
719487c715dcSDouglas Gilbert 	int error = -ENOMEM;
71951da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
71968b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
71971da177e4SLinus Torvalds 
719824669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
719987c715dcSDouglas Gilbert 	if (!sdbg_host)
72001da177e4SLinus Torvalds 		return -ENOMEM;
720187c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
720287c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
720387c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
720487c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
72051da177e4SLinus Torvalds 
72061da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
72071da177e4SLinus Torvalds 
7208773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
72091da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
72105cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
721187c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
72121da177e4SLinus Torvalds 			goto clean;
72131da177e4SLinus Torvalds 	}
72141da177e4SLinus Torvalds 
72150aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
72161da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
72170aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
72181da177e4SLinus Torvalds 
72191da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
72209b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
72211da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
7222f19fe8f3SBart Van Assche 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
72231da177e4SLinus Torvalds 
72241da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
7225e208a1d7SYuan Can 	if (error) {
72260aaa3fadSJohn Garry 		mutex_lock(&sdebug_host_list_mutex);
7227e208a1d7SYuan Can 		list_del(&sdbg_host->host_list);
72280aaa3fadSJohn Garry 		mutex_unlock(&sdebug_host_list_mutex);
72291da177e4SLinus Torvalds 		goto clean;
7230e208a1d7SYuan Can 	}
72311da177e4SLinus Torvalds 
7232f19fe8f3SBart Van Assche 	++sdebug_num_hosts;
723387c715dcSDouglas Gilbert 	return 0;
72341da177e4SLinus Torvalds 
72351da177e4SLinus Torvalds clean:
72368b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
72378b40228fSFUJITA Tomonori 				 dev_list) {
72381da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7239f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
72401da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
72411da177e4SLinus Torvalds 	}
7242e6d773f9SYang Yingliang 	if (sdbg_host->dev.release)
7243e6d773f9SYang Yingliang 		put_device(&sdbg_host->dev);
7244e6d773f9SYang Yingliang 	else
72451da177e4SLinus Torvalds 		kfree(sdbg_host);
724687c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
72471da177e4SLinus Torvalds 	return error;
72481da177e4SLinus Torvalds }
72491da177e4SLinus Torvalds 
sdebug_do_add_host(bool mk_new_store)725087c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
72511da177e4SLinus Torvalds {
725287c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
725387c715dcSDouglas Gilbert 
725487c715dcSDouglas Gilbert 	if (mk_new_store) {
725587c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
725687c715dcSDouglas Gilbert 		if (ph_idx < 0)
725787c715dcSDouglas Gilbert 			return ph_idx;
725887c715dcSDouglas Gilbert 	}
725987c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
726087c715dcSDouglas Gilbert }
726187c715dcSDouglas Gilbert 
sdebug_do_remove_host(bool the_end)726287c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
726387c715dcSDouglas Gilbert {
726487c715dcSDouglas Gilbert 	int idx = -1;
72651da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
726687c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
72671da177e4SLinus Torvalds 
72680aaa3fadSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
72691da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
72701da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
72711da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
727287c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
72731da177e4SLinus Torvalds 	}
727487c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
727587c715dcSDouglas Gilbert 		bool unique = true;
727687c715dcSDouglas Gilbert 
727787c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
727887c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
727987c715dcSDouglas Gilbert 				continue;
728087c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
728187c715dcSDouglas Gilbert 				unique = false;
728287c715dcSDouglas Gilbert 				break;
728387c715dcSDouglas Gilbert 			}
728487c715dcSDouglas Gilbert 		}
728587c715dcSDouglas Gilbert 		if (unique) {
728687c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
728787c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
728887c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
728987c715dcSDouglas Gilbert 		}
729087c715dcSDouglas Gilbert 	}
729187c715dcSDouglas Gilbert 	if (sdbg_host)
729287c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
72930aaa3fadSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
72941da177e4SLinus Torvalds 
72951da177e4SLinus Torvalds 	if (!sdbg_host)
72961da177e4SLinus Torvalds 		return;
72971da177e4SLinus Torvalds 
72981da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
7299f19fe8f3SBart Van Assche 	--sdebug_num_hosts;
73001da177e4SLinus Torvalds }
73011da177e4SLinus Torvalds 
sdebug_change_qdepth(struct scsi_device * sdev,int qdepth)7302fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
7303cbf67842SDouglas Gilbert {
7304151f0ec9SJohn Garry 	struct sdebug_dev_info *devip = sdev->hostdata;
7305151f0ec9SJohn Garry 
7306151f0ec9SJohn Garry 	if (!devip)
7307151f0ec9SJohn Garry 		return	-ENODEV;
7308cbf67842SDouglas Gilbert 
730925b80b2cSJohn Garry 	mutex_lock(&sdebug_host_list_mutex);
7310f19fe8f3SBart Van Assche 	block_unblock_all_queues(true);
731125b80b2cSJohn Garry 
7312fc09acb7SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE) {
7313fc09acb7SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE;
7314fc09acb7SDouglas Gilbert 		pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7315fc09acb7SDouglas Gilbert 			qdepth, SDEBUG_CANQUEUE);
7316fc09acb7SDouglas Gilbert 	}
7317cbf67842SDouglas Gilbert 	if (qdepth < 1)
7318cbf67842SDouglas Gilbert 		qdepth = 1;
7319fc09acb7SDouglas Gilbert 	if (qdepth != sdev->queue_depth)
7320db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(sdev, qdepth);
7321cbf67842SDouglas Gilbert 
732225b80b2cSJohn Garry 	block_unblock_all_queues(false);
732325b80b2cSJohn Garry 	mutex_unlock(&sdebug_host_list_mutex);
732425b80b2cSJohn Garry 
7325151f0ec9SJohn Garry 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
7326151f0ec9SJohn Garry 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d\n", __func__, qdepth);
732725b80b2cSJohn Garry 
7328cbf67842SDouglas Gilbert 	return sdev->queue_depth;
7329cbf67842SDouglas Gilbert }
7330cbf67842SDouglas Gilbert 
fake_timeout(struct scsi_cmnd * scp)7331c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
7332817fd66bSDouglas Gilbert {
7333c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
7334773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
7335773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
7336773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
7337c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
7338773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
7339817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
7340c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
7341817fd66bSDouglas Gilbert 	}
7342c4837394SDouglas Gilbert 	return false;
7343817fd66bSDouglas Gilbert }
7344817fd66bSDouglas Gilbert 
7345fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */
resp_not_ready(struct scsi_cmnd * scp,struct sdebug_dev_info * devip)7346fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7347fc13638aSDouglas Gilbert {
7348fc13638aSDouglas Gilbert 	int stopped_state;
7349fc13638aSDouglas Gilbert 	u64 diff_ns = 0;
7350fc13638aSDouglas Gilbert 	ktime_t now_ts = ktime_get_boottime();
7351fc13638aSDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7352fc13638aSDouglas Gilbert 
7353fc13638aSDouglas Gilbert 	stopped_state = atomic_read(&devip->stopped);
7354fc13638aSDouglas Gilbert 	if (stopped_state == 2) {
7355fc13638aSDouglas Gilbert 		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7356fc13638aSDouglas Gilbert 			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7357fc13638aSDouglas Gilbert 			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7358fc13638aSDouglas Gilbert 				/* tur_ms_to_ready timer extinguished */
7359fc13638aSDouglas Gilbert 				atomic_set(&devip->stopped, 0);
7360fc13638aSDouglas Gilbert 				return 0;
7361fc13638aSDouglas Gilbert 			}
7362fc13638aSDouglas Gilbert 		}
7363fc13638aSDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7364fc13638aSDouglas Gilbert 		if (sdebug_verbose)
7365fc13638aSDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
7366fc13638aSDouglas Gilbert 				    "%s: Not ready: in process of becoming ready\n", my_name);
7367fc13638aSDouglas Gilbert 		if (scp->cmnd[0] == TEST_UNIT_READY) {
7368fc13638aSDouglas Gilbert 			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7369fc13638aSDouglas Gilbert 
7370fc13638aSDouglas Gilbert 			if (diff_ns <= tur_nanosecs_to_ready)
7371fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready - diff_ns;
7372fc13638aSDouglas Gilbert 			else
7373fc13638aSDouglas Gilbert 				diff_ns = tur_nanosecs_to_ready;
7374fc13638aSDouglas Gilbert 			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7375fc13638aSDouglas Gilbert 			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
7376fc13638aSDouglas Gilbert 			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7377fc13638aSDouglas Gilbert 						   diff_ns);
7378fc13638aSDouglas Gilbert 			return check_condition_result;
7379fc13638aSDouglas Gilbert 		}
7380fc13638aSDouglas Gilbert 	}
7381fc13638aSDouglas Gilbert 	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7382fc13638aSDouglas Gilbert 	if (sdebug_verbose)
7383fc13638aSDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7384fc13638aSDouglas Gilbert 			    my_name);
7385fc13638aSDouglas Gilbert 	return check_condition_result;
7386fc13638aSDouglas Gilbert }
7387fc13638aSDouglas Gilbert 
sdebug_map_queues(struct Scsi_Host * shost)7388a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost)
7389c4b57d89SKashyap Desai {
7390c4b57d89SKashyap Desai 	int i, qoff;
7391c4b57d89SKashyap Desai 
7392c4b57d89SKashyap Desai 	if (shost->nr_hw_queues == 1)
7393a4e1d0b7SBart Van Assche 		return;
7394c4b57d89SKashyap Desai 
7395c4b57d89SKashyap Desai 	for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7396c4b57d89SKashyap Desai 		struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7397c4b57d89SKashyap Desai 
7398c4b57d89SKashyap Desai 		map->nr_queues  = 0;
7399c4b57d89SKashyap Desai 
7400c4b57d89SKashyap Desai 		if (i == HCTX_TYPE_DEFAULT)
7401c4b57d89SKashyap Desai 			map->nr_queues = submit_queues - poll_queues;
7402c4b57d89SKashyap Desai 		else if (i == HCTX_TYPE_POLL)
7403c4b57d89SKashyap Desai 			map->nr_queues = poll_queues;
7404c4b57d89SKashyap Desai 
7405c4b57d89SKashyap Desai 		if (!map->nr_queues) {
7406c4b57d89SKashyap Desai 			BUG_ON(i == HCTX_TYPE_DEFAULT);
7407c4b57d89SKashyap Desai 			continue;
7408c4b57d89SKashyap Desai 		}
7409c4b57d89SKashyap Desai 
7410c4b57d89SKashyap Desai 		map->queue_offset = qoff;
7411c4b57d89SKashyap Desai 		blk_mq_map_queues(map);
7412c4b57d89SKashyap Desai 
7413c4b57d89SKashyap Desai 		qoff += map->nr_queues;
7414c4b57d89SKashyap Desai 	}
7415c4b57d89SKashyap Desai }
7416c4b57d89SKashyap Desai 
7417600d9eadSJohn Garry struct sdebug_blk_mq_poll_data {
7418600d9eadSJohn Garry 	unsigned int queue_num;
7419600d9eadSJohn Garry 	int *num_entries;
7420600d9eadSJohn Garry };
7421600d9eadSJohn Garry 
7422600d9eadSJohn Garry /*
7423600d9eadSJohn Garry  * We don't handle aborted commands here, but it does not seem possible to have
7424600d9eadSJohn Garry  * aborted polled commands from schedule_resp()
7425600d9eadSJohn Garry  */
sdebug_blk_mq_poll_iter(struct request * rq,void * opaque)7426600d9eadSJohn Garry static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque)
7427c4b57d89SKashyap Desai {
7428600d9eadSJohn Garry 	struct sdebug_blk_mq_poll_data *data = opaque;
7429600d9eadSJohn Garry 	struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
7430600d9eadSJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd);
74314a0c6f43SDouglas Gilbert 	struct sdebug_defer *sd_dp;
7432600d9eadSJohn Garry 	u32 unique_tag = blk_mq_unique_tag(rq);
7433600d9eadSJohn Garry 	u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag);
7434600d9eadSJohn Garry 	struct sdebug_queued_cmd *sqcp;
7435600d9eadSJohn Garry 	unsigned long flags;
7436600d9eadSJohn Garry 	int queue_num = data->queue_num;
7437600d9eadSJohn Garry 	ktime_t time;
7438c4b57d89SKashyap Desai 
7439600d9eadSJohn Garry 	/* We're only interested in one queue for this iteration */
7440600d9eadSJohn Garry 	if (hwq != queue_num)
7441600d9eadSJohn Garry 		return true;
74424a0c6f43SDouglas Gilbert 
7443600d9eadSJohn Garry 	/* Subsequent checks would fail if this failed, but check anyway */
7444600d9eadSJohn Garry 	if (!test_bit(SCMD_STATE_INFLIGHT, &cmd->state))
7445600d9eadSJohn Garry 		return true;
74464a0c6f43SDouglas Gilbert 
7447600d9eadSJohn Garry 	time = ktime_get_boottime();
74486a0d0ae3SDamien Le Moal 
7449600d9eadSJohn Garry 	spin_lock_irqsave(&sdsc->lock, flags);
7450600d9eadSJohn Garry 	sqcp = TO_QUEUED_CMD(cmd);
7451600d9eadSJohn Garry 	if (!sqcp) {
7452600d9eadSJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7453600d9eadSJohn Garry 		return true;
74544a0c6f43SDouglas Gilbert 	}
7455c4b57d89SKashyap Desai 
74561107c7b2SJohn Garry 	sd_dp = &sqcp->sd_dp;
7457600d9eadSJohn Garry 	if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) {
74581107c7b2SJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7459600d9eadSJohn Garry 		return true;
7460c4b57d89SKashyap Desai 	}
74614a0c6f43SDouglas Gilbert 
7462600d9eadSJohn Garry 	if (time < sd_dp->cmpl_ts) {
74631107c7b2SJohn Garry 		spin_unlock_irqrestore(&sdsc->lock, flags);
7464600d9eadSJohn Garry 		return true;
74651107c7b2SJohn Garry 	}
7466c4b57d89SKashyap Desai 
7467600d9eadSJohn Garry 	ASSIGN_QUEUED_CMD(cmd, NULL);
74681107c7b2SJohn Garry 	spin_unlock_irqrestore(&sdsc->lock, flags);
7469548ebb33SJohn Garry 
7470548ebb33SJohn Garry 	if (sdebug_statistics) {
7471548ebb33SJohn Garry 		atomic_inc(&sdebug_completions);
7472548ebb33SJohn Garry 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
7473548ebb33SJohn Garry 			atomic_inc(&sdebug_miss_cpus);
7474548ebb33SJohn Garry 	}
7475548ebb33SJohn Garry 
74761107c7b2SJohn Garry 	sdebug_free_queued_cmd(sqcp);
74771107c7b2SJohn Garry 
7478600d9eadSJohn Garry 	scsi_done(cmd); /* callback to mid level */
7479600d9eadSJohn Garry 	(*data->num_entries)++;
7480600d9eadSJohn Garry 	return true;
74814a0c6f43SDouglas Gilbert }
74823fd07aecSDamien Le Moal 
sdebug_blk_mq_poll(struct Scsi_Host * shost,unsigned int queue_num)7483600d9eadSJohn Garry static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7484600d9eadSJohn Garry {
7485600d9eadSJohn Garry 	int num_entries = 0;
7486600d9eadSJohn Garry 	struct sdebug_blk_mq_poll_data data = {
7487600d9eadSJohn Garry 		.queue_num = queue_num,
7488600d9eadSJohn Garry 		.num_entries = &num_entries,
7489600d9eadSJohn Garry 	};
7490600d9eadSJohn Garry 
7491600d9eadSJohn Garry 	blk_mq_tagset_busy_iter(&shost->tag_set, sdebug_blk_mq_poll_iter,
7492600d9eadSJohn Garry 				&data);
74933fd07aecSDamien Le Moal 
74944a0c6f43SDouglas Gilbert 	if (num_entries > 0)
74954a0c6f43SDouglas Gilbert 		atomic_add(num_entries, &sdeb_mq_poll_count);
7496c4b57d89SKashyap Desai 	return num_entries;
7497c4b57d89SKashyap Desai }
7498c4b57d89SKashyap Desai 
scsi_debug_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * scp)7499fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7500fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
7501c2248fc9SDouglas Gilbert {
7502c2248fc9SDouglas Gilbert 	u8 sdeb_i;
7503c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
7504c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
7505c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
7506c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
7507c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
7508c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
7509f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
7510c2248fc9SDouglas Gilbert 	int k, na;
7511c2248fc9SDouglas Gilbert 	int errsts = 0;
7512ad0c7775SDouglas Gilbert 	u64 lun_index = sdp->lun & 0x3FFF;
7513c2248fc9SDouglas Gilbert 	u32 flags;
7514c2248fc9SDouglas Gilbert 	u16 sa;
7515c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
7516c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
75173a90a63dSDouglas Gilbert 	bool inject_now;
7518c2248fc9SDouglas Gilbert 
7519c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
75203a90a63dSDouglas Gilbert 	if (sdebug_statistics) {
7521c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
75223a90a63dSDouglas Gilbert 		inject_now = inject_on_this_cmd();
75233a90a63dSDouglas Gilbert 	} else {
75243a90a63dSDouglas Gilbert 		inject_now = false;
75253a90a63dSDouglas Gilbert 	}
7526f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
7527f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
7528c2248fc9SDouglas Gilbert 		char b[120];
7529c2248fc9SDouglas Gilbert 		int n, len, sb;
7530c2248fc9SDouglas Gilbert 
7531c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
7532c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
7533c2248fc9SDouglas Gilbert 		if (len > 32)
7534c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
7535c2248fc9SDouglas Gilbert 		else {
7536c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
7537c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
7538c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
7539c2248fc9SDouglas Gilbert 		}
7540458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7541a6e76e6fSBart Van Assche 			    blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
7542c2248fc9SDouglas Gilbert 	}
75433a90a63dSDouglas Gilbert 	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
75447ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
754534d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
7546ad0c7775SDouglas Gilbert 	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
7547f46eb0e9SDouglas Gilbert 		goto err_out;
7548c2248fc9SDouglas Gilbert 
7549c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
7550c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
7551c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
7552f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
7553f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
7554c2248fc9SDouglas Gilbert 		if (NULL == devip)
7555f46eb0e9SDouglas Gilbert 			goto err_out;
7556c2248fc9SDouglas Gilbert 	}
75573a90a63dSDouglas Gilbert 	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
75583a90a63dSDouglas Gilbert 		atomic_set(&sdeb_inject_pending, 1);
75593a90a63dSDouglas Gilbert 
7560c2248fc9SDouglas Gilbert 	na = oip->num_attached;
7561c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
7562c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
7563c2248fc9SDouglas Gilbert 		r_oip = oip;
7564c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
7565c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
7566c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
7567c2248fc9SDouglas Gilbert 			else
7568c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
7569c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7570c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
7571c2248fc9SDouglas Gilbert 					break;
7572c2248fc9SDouglas Gilbert 			}
7573c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
7574c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7575c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
7576c2248fc9SDouglas Gilbert 					break;
7577c2248fc9SDouglas Gilbert 			}
7578c2248fc9SDouglas Gilbert 		}
7579c2248fc9SDouglas Gilbert 		if (k > na) {
7580c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
7581c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7582c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
7583c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7584c2248fc9SDouglas Gilbert 			else
7585c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
7586c2248fc9SDouglas Gilbert 			goto check_cond;
7587c2248fc9SDouglas Gilbert 		}
7588c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
7589c2248fc9SDouglas Gilbert 	flags = oip->flags;
7590f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
7591c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7592c2248fc9SDouglas Gilbert 		goto check_cond;
7593c2248fc9SDouglas Gilbert 	}
7594f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
7595773642d9SDouglas Gilbert 		if (sdebug_verbose)
7596773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7597773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
7598c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
7599c2248fc9SDouglas Gilbert 		goto check_cond;
7600c2248fc9SDouglas Gilbert 	}
7601f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
7602c2248fc9SDouglas Gilbert 		u8 rem;
7603c2248fc9SDouglas Gilbert 		int j;
7604c2248fc9SDouglas Gilbert 
7605c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7606c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
7607c2248fc9SDouglas Gilbert 			if (rem) {
7608c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
7609c2248fc9SDouglas Gilbert 					if (0x80 & rem)
7610c2248fc9SDouglas Gilbert 						break;
7611c2248fc9SDouglas Gilbert 				}
7612c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7613c2248fc9SDouglas Gilbert 				goto check_cond;
7614c2248fc9SDouglas Gilbert 			}
7615c2248fc9SDouglas Gilbert 		}
7616c2248fc9SDouglas Gilbert 	}
7617f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
7618b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
7619b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
7620f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
7621c2248fc9SDouglas Gilbert 		if (errsts)
7622c2248fc9SDouglas Gilbert 			goto check_cond;
7623c2248fc9SDouglas Gilbert 	}
7624fc13638aSDouglas Gilbert 	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7625fc13638aSDouglas Gilbert 		     atomic_read(&devip->stopped))) {
7626fc13638aSDouglas Gilbert 		errsts = resp_not_ready(scp, devip);
7627fc13638aSDouglas Gilbert 		if (errsts)
7628c2248fc9SDouglas Gilbert 			goto fini;
7629c2248fc9SDouglas Gilbert 	}
7630773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
7631c2248fc9SDouglas Gilbert 		goto fini;
7632f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
7633c4837394SDouglas Gilbert 		if (fake_timeout(scp))
7634c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
7635c2248fc9SDouglas Gilbert 	}
7636f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
7637f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
7638f66b8517SMartin Wilck 	else
7639f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
7640c2248fc9SDouglas Gilbert 
7641c2248fc9SDouglas Gilbert fini:
764267da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
7643f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
764475aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
764575aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
764680c49563SDouglas Gilbert 		/*
764775aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
764875aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
764975aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
765075aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
765180c49563SDouglas Gilbert 		 */
765280c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
76534f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
765480c49563SDouglas Gilbert 
76554f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
7656f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
765780c49563SDouglas Gilbert 	} else
7658f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
765910bde980SDouglas Gilbert 				     sdebug_ndelay);
7660c2248fc9SDouglas Gilbert check_cond:
7661f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
7662f46eb0e9SDouglas Gilbert err_out:
7663f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
7664c2248fc9SDouglas Gilbert }
7665c2248fc9SDouglas Gilbert 
sdebug_init_cmd_priv(struct Scsi_Host * shost,struct scsi_cmnd * cmd)76661107c7b2SJohn Garry static int sdebug_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
76671107c7b2SJohn Garry {
76681107c7b2SJohn Garry 	struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd);
76691107c7b2SJohn Garry 
76701107c7b2SJohn Garry 	spin_lock_init(&sdsc->lock);
76711107c7b2SJohn Garry 
76721107c7b2SJohn Garry 	return 0;
76731107c7b2SJohn Garry }
76741107c7b2SJohn Garry 
76751107c7b2SJohn Garry 
76769e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
7677c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
7678c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
76799e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
76809e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
76819e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
76829e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
76839e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
76849e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
76859e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
7686185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
7687cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
7688c4b57d89SKashyap Desai 	.map_queues =		sdebug_map_queues,
7689c4b57d89SKashyap Desai 	.mq_poll =		sdebug_blk_mq_poll,
76909e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
76919e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
7692cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
7693cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
76949e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
7695c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
76969e603ca0SFUJITA Tomonori 	.this_id =		7,
769765e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
7698cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
76996bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
770050c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
77019e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
7702c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
77031107c7b2SJohn Garry 	.cmd_size = sizeof(struct sdebug_scsi_cmd),
77041107c7b2SJohn Garry 	.init_cmd_priv = sdebug_init_cmd_priv,
77059e603ca0SFUJITA Tomonori };
77069e603ca0SFUJITA Tomonori 
sdebug_driver_probe(struct device * dev)77071da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
77081da177e4SLinus Torvalds {
77091da177e4SLinus Torvalds 	int error = 0;
77101da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
77111da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
7712f46eb0e9SDouglas Gilbert 	int hprot;
77131da177e4SLinus Torvalds 
7714785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
77151da177e4SLinus Torvalds 
7716773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
7717fc09acb7SDouglas Gilbert 	sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
77182a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
77194af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
77204af14d11SChristoph Hellwig 
7721785d6b7cSJohn Garry 	hpnt = scsi_host_alloc(&sdebug_driver_template, 0);
77221da177e4SLinus Torvalds 	if (NULL == hpnt) {
7723c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
77241da177e4SLinus Torvalds 		error = -ENODEV;
77251da177e4SLinus Torvalds 		return error;
77261da177e4SLinus Torvalds 	}
7727c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
77289b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
7729c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
7730c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
7731c4837394SDouglas Gilbert 	}
7732c10fa55fSJohn Garry 	/*
7733c10fa55fSJohn Garry 	 * Decide whether to tell scsi subsystem that we want mq. The
7734f7c4cdc7SJohn Garry 	 * following should give the same answer for each host.
7735c10fa55fSJohn Garry 	 */
7736c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
7737f7c4cdc7SJohn Garry 	if (sdebug_host_max_queue)
7738f7c4cdc7SJohn Garry 		hpnt->host_tagset = 1;
77391da177e4SLinus Torvalds 
7740c4b57d89SKashyap Desai 	/* poll queues are possible for nr_hw_queues > 1 */
7741c4b57d89SKashyap Desai 	if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7742c4b57d89SKashyap Desai 		pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7743c4b57d89SKashyap Desai 			 my_name, poll_queues, hpnt->nr_hw_queues);
7744c4b57d89SKashyap Desai 		poll_queues = 0;
7745c4b57d89SKashyap Desai 	}
7746c4b57d89SKashyap Desai 
7747c4b57d89SKashyap Desai 	/*
7748c4b57d89SKashyap Desai 	 * Poll queues don't need interrupts, but we need at least one I/O queue
7749c4b57d89SKashyap Desai 	 * left over for non-polled I/O.
7750c4b57d89SKashyap Desai 	 * If condition not met, trim poll_queues to 1 (just for simplicity).
7751c4b57d89SKashyap Desai 	 */
7752c4b57d89SKashyap Desai 	if (poll_queues >= submit_queues) {
7753fc09acb7SDouglas Gilbert 		if (submit_queues < 3)
7754c4b57d89SKashyap Desai 			pr_warn("%s: trim poll_queues to 1\n", my_name);
7755fc09acb7SDouglas Gilbert 		else
7756fc09acb7SDouglas Gilbert 			pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7757fc09acb7SDouglas Gilbert 				my_name, submit_queues - 1);
7758c4b57d89SKashyap Desai 		poll_queues = 1;
7759c4b57d89SKashyap Desai 	}
7760c4b57d89SKashyap Desai 	if (poll_queues)
7761c4b57d89SKashyap Desai 		hpnt->nr_maps = 3;
7762c4b57d89SKashyap Desai 
77631da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
7764773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7765773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
77661da177e4SLinus Torvalds 	else
7767773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
7768773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
7769f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
77701da177e4SLinus Torvalds 
7771f46eb0e9SDouglas Gilbert 	hprot = 0;
7772c6a44287SMartin K. Petersen 
7773773642d9SDouglas Gilbert 	switch (sdebug_dif) {
7774c6a44287SMartin K. Petersen 
77758475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
7776f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
7777773642d9SDouglas Gilbert 		if (sdebug_dix)
7778f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
7779c6a44287SMartin K. Petersen 		break;
7780c6a44287SMartin K. Petersen 
77818475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
7782f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
7783773642d9SDouglas Gilbert 		if (sdebug_dix)
7784f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
7785c6a44287SMartin K. Petersen 		break;
7786c6a44287SMartin K. Petersen 
77878475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
7788f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
7789773642d9SDouglas Gilbert 		if (sdebug_dix)
7790f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
7791c6a44287SMartin K. Petersen 		break;
7792c6a44287SMartin K. Petersen 
7793c6a44287SMartin K. Petersen 	default:
7794773642d9SDouglas Gilbert 		if (sdebug_dix)
7795f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
7796c6a44287SMartin K. Petersen 		break;
7797c6a44287SMartin K. Petersen 	}
7798c6a44287SMartin K. Petersen 
7799f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
7800c6a44287SMartin K. Petersen 
7801f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
7802c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
7803f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7804f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7805f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7806f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7807f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7808f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7809f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
7810c6a44287SMartin K. Petersen 
7811773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
7812c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7813c6a44287SMartin K. Petersen 	else
7814c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7815c6a44287SMartin K. Petersen 
7816773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7817773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
7818c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
7819c4837394SDouglas Gilbert 		sdebug_statistics = true;
78201da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
78211da177e4SLinus Torvalds 	if (error) {
7822c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
78231da177e4SLinus Torvalds 		error = -ENODEV;
78241da177e4SLinus Torvalds 		scsi_host_put(hpnt);
782587c715dcSDouglas Gilbert 	} else {
78261da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
782787c715dcSDouglas Gilbert 	}
78281da177e4SLinus Torvalds 
78291da177e4SLinus Torvalds 	return error;
78301da177e4SLinus Torvalds }
78311da177e4SLinus Torvalds 
sdebug_driver_remove(struct device * dev)7832fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev)
78331da177e4SLinus Torvalds {
78341da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
78358b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
78361da177e4SLinus Torvalds 
7837785d6b7cSJohn Garry 	sdbg_host = dev_to_sdebug_host(dev);
78381da177e4SLinus Torvalds 
78391da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
78401da177e4SLinus Torvalds 
78418b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
78428b40228fSFUJITA Tomonori 				 dev_list) {
78431da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
7844f0d1cf93SDouglas Gilbert 		kfree(sdbg_devinfo->zstate);
78451da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
78461da177e4SLinus Torvalds 	}
78471da177e4SLinus Torvalds 
78481da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
78491da177e4SLinus Torvalds }
78501da177e4SLinus Torvalds 
78518dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
78528dea0d02SFUJITA Tomonori 	.name = "pseudo",
78538dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
78548dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
785582069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
78568dea0d02SFUJITA Tomonori };
7857