xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision ed9f3e25)
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  *
1080c49563SDouglas Gilbert  * Copyright (C) 2001 - 2018 Douglas Gilbert
111da177e4SLinus Torvalds  *
1278d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15c1287970STomas Winkler 
16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17c1287970STomas Winkler 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
22b333a819SDouglas Gilbert #include <linux/jiffies.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/genhd.h>
271da177e4SLinus Torvalds #include <linux/fs.h>
281da177e4SLinus Torvalds #include <linux/init.h>
291da177e4SLinus Torvalds #include <linux/proc_fs.h>
301da177e4SLinus Torvalds #include <linux/vmalloc.h>
311da177e4SLinus Torvalds #include <linux/moduleparam.h>
32852e034dSJens Axboe #include <linux/scatterlist.h>
331da177e4SLinus Torvalds #include <linux/blkdev.h>
34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
35cbf67842SDouglas Gilbert #include <linux/spinlock.h>
36cbf67842SDouglas Gilbert #include <linux/interrupt.h>
37cbf67842SDouglas Gilbert #include <linux/atomic.h>
38cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
3909ba24c1SDouglas Gilbert #include <linux/uuid.h>
406ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
411442f76dSChristoph Hellwig #include <linux/msdos_partition.h>
420c4bc91dSDouglas Gilbert #include <linux/random.h>
4387c715dcSDouglas Gilbert #include <linux/xarray.h>
44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6380c49563SDouglas Gilbert #define SDEBUG_VERSION "0188"	/* format to fit INQUIRY revision field */
6440d07b52SDouglas Gilbert static const char *sdebug_version_date = "20190125";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
971da177e4SLinus Torvalds 
986f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
996f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1006f3cbf55SDouglas Gilbert 
1011da177e4SLinus Torvalds /* Default values for driver parameters */
1021da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1031da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1041da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1051da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1061da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1071da177e4SLinus Torvalds  */
1085b94e232SMartin K. Petersen #define DEF_ATO 1
1099b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
110c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1111da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1125b94e232SMartin K. Petersen #define DEF_DIF 0
1135b94e232SMartin K. Petersen #define DEF_DIX 0
11487c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false
1155b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1161da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1175b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1185b94e232SMartin K. Petersen #define DEF_GUARD 0
119cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1205b94e232SMartin K. Petersen #define DEF_LBPU 0
1215b94e232SMartin K. Petersen #define DEF_LBPWS 0
1225b94e232SMartin K. Petersen #define DEF_LBPWS10 0
123be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1245b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
125cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1265b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1271da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1281da177e4SLinus Torvalds #define DEF_OPTS   0
12932c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1305b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13186e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
132b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
1330c4bc91dSDouglas Gilbert #define DEF_RANDOM false
134d986788bSMartin Pitt #define DEF_REMOVABLE false
135760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1365b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1375b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1385b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1396014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1406014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1415b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1425b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1435b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
144c2248fc9SDouglas Gilbert #define DEF_STRICT 0
145c4837394SDouglas Gilbert #define DEF_STATISTICS false
146c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14709ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
148c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1491da177e4SLinus Torvalds 
150b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
151b01f6f83SDouglas Gilbert 
152773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
153773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
154773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
155773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
156773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
157773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
158773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
159773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
160773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
161773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
162773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
163773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
164773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
165773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
166773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
167773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1687ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1697382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
170773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
171773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
172773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
173773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
174773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1757ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1767382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1777382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1781da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
179fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1801da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
181773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1826f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
183773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1847382f9d8SDouglas Gilbert  *   - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
1857382f9d8SDouglas Gilbert  *     CMD_ABORT
1861da177e4SLinus Torvalds  *
1877382f9d8SDouglas Gilbert  * When "every_nth" < 0 then after "- every_nth" commands the selected
1887382f9d8SDouglas Gilbert  * error will be injected. The error will be injected on every subsequent
1897382f9d8SDouglas Gilbert  * command until some other action occurs; for example, the user writing
1907382f9d8SDouglas Gilbert  * a new value (other than -1 or 1) to every_nth:
1917382f9d8SDouglas Gilbert  *      echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
1921da177e4SLinus Torvalds  */
1931da177e4SLinus Torvalds 
194cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
195cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
196cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
197cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
198cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
199cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
200cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
2010d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
20219c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
203acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
204acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
205acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
206cbf67842SDouglas Gilbert 
207773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2081da177e4SLinus Torvalds  * sector on read commands: */
2091da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
21032f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2131da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2141da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2151da177e4SLinus Torvalds 
216c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
217c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
218c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
219c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
220c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
221c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
222c4837394SDouglas Gilbert  */
223c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
224c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
225cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
226cbf67842SDouglas Gilbert 
227fd32119bSDouglas Gilbert #define F_D_IN			1
228fd32119bSDouglas Gilbert #define F_D_OUT			2
229fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
230fd32119bSDouglas Gilbert #define F_D_UNKN		8
231fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
232fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
233fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
234fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
235fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
236fd32119bSDouglas Gilbert #define F_INV_OP		0x200
237fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
238fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
2394f2c8bf6SDouglas Gilbert #define F_SSU_DELAY		0x1000
2404f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY		0x2000
241fd32119bSDouglas Gilbert 
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 
253fd32119bSDouglas Gilbert 
254fd32119bSDouglas Gilbert struct sdebug_dev_info {
255fd32119bSDouglas Gilbert 	struct list_head dev_list;
256fd32119bSDouglas Gilbert 	unsigned int channel;
257fd32119bSDouglas Gilbert 	unsigned int target;
258fd32119bSDouglas Gilbert 	u64 lun;
259bf476433SChristoph Hellwig 	uuid_t lu_name;
260fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
261fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
262fd32119bSDouglas Gilbert 	atomic_t num_in_q;
263c4837394SDouglas Gilbert 	atomic_t stopped;
264fd32119bSDouglas Gilbert 	bool used;
265fd32119bSDouglas Gilbert };
266fd32119bSDouglas Gilbert 
267fd32119bSDouglas Gilbert struct sdebug_host_info {
268fd32119bSDouglas Gilbert 	struct list_head host_list;
26987c715dcSDouglas Gilbert 	int si_idx;	/* sdeb_store_info (per host) xarray index */
270fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
271fd32119bSDouglas Gilbert 	struct device dev;
272fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
273fd32119bSDouglas Gilbert };
274fd32119bSDouglas Gilbert 
27587c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */
27687c715dcSDouglas Gilbert struct sdeb_store_info {
27787c715dcSDouglas Gilbert 	rwlock_t macc_lck;	/* for atomic media access on this store */
27887c715dcSDouglas Gilbert 	u8 *storep;		/* user data storage (ram) */
27987c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep; /* protection info */
28087c715dcSDouglas Gilbert 	void *map_storep;	/* provisioning map */
28187c715dcSDouglas Gilbert };
28287c715dcSDouglas Gilbert 
283fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
284fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
285fd32119bSDouglas Gilbert 
28610bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
28710bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
28810bde980SDouglas Gilbert 
289fd32119bSDouglas Gilbert struct sdebug_defer {
290fd32119bSDouglas Gilbert 	struct hrtimer hrt;
291fd32119bSDouglas Gilbert 	struct execute_work ew;
292c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
293c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
294c4837394SDouglas Gilbert 	int issuing_cpu;
29510bde980SDouglas Gilbert 	bool init_hrt;
29610bde980SDouglas Gilbert 	bool init_wq;
2977382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
29810bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
299fd32119bSDouglas Gilbert };
300fd32119bSDouglas Gilbert 
301fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
302c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
303c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
304c4837394SDouglas Gilbert 	 */
305fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
306fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
307c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
308c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
309c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
310c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
311c4837394SDouglas Gilbert 	unsigned int inj_short:1;
3127ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
3137382f9d8SDouglas Gilbert 	unsigned int inj_cmd_abort:1;
314fd32119bSDouglas Gilbert };
315fd32119bSDouglas Gilbert 
316c4837394SDouglas Gilbert struct sdebug_queue {
317c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
318c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
319c4837394SDouglas Gilbert 	spinlock_t qc_lock;
320c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
321fd32119bSDouglas Gilbert };
322fd32119bSDouglas Gilbert 
323c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
324c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
325c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
326c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
327c4837394SDouglas Gilbert 
328fd32119bSDouglas Gilbert struct opcode_info_t {
329b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
330b01f6f83SDouglas Gilbert 				/* for terminating element */
331fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
332fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
333fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
334fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
335fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3369a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3379a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
338fd32119bSDouglas Gilbert };
339fd32119bSDouglas Gilbert 
340fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
341c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
342c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
343c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
344c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
345c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
346c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
347c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
348c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
349c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
350c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
351c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
352c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
353c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
35446f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
35546f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
356c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
357c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
358c3e2fe92SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
359481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
360c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
361c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
362c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
363c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
364c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
365c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
366c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
367c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
368c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
369c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
370c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
371ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
372ed9f3e25SDouglas Gilbert 	SDEB_I_LAST_ELEM_P1 = 30,	/* keep this last (previous + 1) */
373c2248fc9SDouglas Gilbert };
374c2248fc9SDouglas Gilbert 
375c4837394SDouglas Gilbert 
376c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
377c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
378c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
379c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
380c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
381c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
382c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
383c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
384c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
385c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
386c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
387c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
388ed9f3e25SDouglas Gilbert 	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
389c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
390c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
391c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
392c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
393c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
394c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
395c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
396fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
397c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
400c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
401c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
402c3e2fe92SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
403c3e2fe92SDouglas Gilbert 	0, 0, 0, SDEB_I_VERIFY,
404ed9f3e25SDouglas Gilbert 	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
40546f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
406c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
407c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
408c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
40946f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
41046f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
411c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
412c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
413c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
414c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
415c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
416c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
417c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
418c2248fc9SDouglas Gilbert };
419c2248fc9SDouglas Gilbert 
42080c49563SDouglas Gilbert /*
42180c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
42280c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
42380c49563SDouglas Gilbert  * command completion, they can mask their return value with
42480c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
42580c49563SDouglas Gilbert  */
42680c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
42780c49563SDouglas Gilbert 
428c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
429c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
430c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
431c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
432c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
433c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
434c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
435c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
436c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
437481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
438c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
439c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
440c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
441c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
442c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
44338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
44438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
445c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
446c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
447c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
44838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
449acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
45080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
451ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
452c2248fc9SDouglas Gilbert 
45387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store);
45487c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx);
45587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end);
45687c715dcSDouglas Gilbert static int sdebug_add_store(void);
45787c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
45887c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first);
45987c715dcSDouglas Gilbert 
46046f64e70SDouglas Gilbert /*
46146f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
46246f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
46346f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
46446f64e70SDouglas Gilbert  */
46546f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
466c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
467c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
468c2248fc9SDouglas Gilbert };
469c2248fc9SDouglas Gilbert 
47046f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
471c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
472c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
473c2248fc9SDouglas Gilbert };
474c2248fc9SDouglas Gilbert 
47546f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
47646f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
477b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
478c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
47946f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
480c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
48146f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
482b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
483c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
484c2248fc9SDouglas Gilbert };
485c2248fc9SDouglas Gilbert 
48646f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
48746f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
48846f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
48946f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
49046f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
49146f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
49246f64e70SDouglas Gilbert 		   0, 0, 0} },
49346f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
49446f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49546f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
496c2248fc9SDouglas Gilbert };
497c2248fc9SDouglas Gilbert 
498c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = {
499c3e2fe92SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
500c3e2fe92SDouglas Gilbert 	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
501c3e2fe92SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
502c3e2fe92SDouglas Gilbert };
503c3e2fe92SDouglas Gilbert 
50446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
505c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
506c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50746f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
508c2248fc9SDouglas Gilbert };
509c2248fc9SDouglas Gilbert 
51046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
51146f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
512b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
513c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
514481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
515481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
516481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
517c2248fc9SDouglas Gilbert };
518c2248fc9SDouglas Gilbert 
51946f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
52038d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
521c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
52246f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
52338d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
524c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
52546f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
526c2248fc9SDouglas Gilbert };
527c2248fc9SDouglas Gilbert 
52846f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
52946f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
530c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53146f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
532c2248fc9SDouglas Gilbert };
533c2248fc9SDouglas Gilbert 
53446f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
535c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
536c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
537c2248fc9SDouglas Gilbert };
538c2248fc9SDouglas Gilbert 
53946f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
540c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
541c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
542c2248fc9SDouglas Gilbert };
543c2248fc9SDouglas Gilbert 
54480c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5454f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
54680c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54780c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
54880c49563SDouglas Gilbert };
54980c49563SDouglas Gilbert 
550ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = {
551ed9f3e25SDouglas Gilbert 	{0, 0x90, 0, F_SYNC_DELAY | F_M_ACCESS, resp_pre_fetch, NULL,
552ed9f3e25SDouglas Gilbert 	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
553ed9f3e25SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
554ed9f3e25SDouglas Gilbert };
555ed9f3e25SDouglas Gilbert 
556c2248fc9SDouglas Gilbert 
557c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
558c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
559c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
560ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
561c2248fc9SDouglas Gilbert /* 0 */
56246f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
563c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
56446f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
565c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
566c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
567c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
56846f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
569c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
570c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
571c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
572c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
57346f64e70SDouglas Gilbert /* 5 */
57446f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
57546f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
57646f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
57746f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
57846f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
57946f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
58046f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
581c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
582c2248fc9SDouglas Gilbert 	     0, 0, 0} },
58346f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
584c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
585c2248fc9SDouglas Gilbert 	     0, 0} },
58646f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
58746f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
58846f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
589c2248fc9SDouglas Gilbert /* 10 */
59046f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
59146f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
59246f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59380c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
5944f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
595c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
59646f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
59746f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
59846f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
59946f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
600481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
601481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
602481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
60346f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
60446f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
60546f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
60646f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
60746f64e70SDouglas Gilbert /* 15 */
608c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
609c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
610c3e2fe92SDouglas Gilbert 	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
611c3e2fe92SDouglas Gilbert 	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
612c3e2fe92SDouglas Gilbert 	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
613c3e2fe92SDouglas Gilbert 			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
61446f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
61546f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
61646f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
61746f64e70SDouglas Gilbert 	     0xff, 0xff} },
61846f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
61946f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
620c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
621c2248fc9SDouglas Gilbert 	     0} },
62246f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
62346f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
624c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
625c2248fc9SDouglas Gilbert 	     0} },
626c2248fc9SDouglas Gilbert /* 20 */
627f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
628f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
629c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
630c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
631c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
632c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
633c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
634c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
63546f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
636b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
63746f64e70SDouglas Gilbert /* 25 */
638acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
639acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
640acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
64146f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
64246f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
64346f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
64446f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
6454f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
64680c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
647b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
64880c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
64946f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
650c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
651b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
652ed9f3e25SDouglas Gilbert 	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | F_M_ACCESS,
653ed9f3e25SDouglas Gilbert 	    resp_pre_fetch, pre_fetch_iarr,
654ed9f3e25SDouglas Gilbert 	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
655ed9f3e25SDouglas Gilbert 	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
656c2248fc9SDouglas Gilbert 
657ed9f3e25SDouglas Gilbert /* 30 */
658c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
659c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
660c2248fc9SDouglas Gilbert };
661c2248fc9SDouglas Gilbert 
66287c715dcSDouglas Gilbert static int sdebug_num_hosts;
66387c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
664773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
6659b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
666c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
667773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
668773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
669773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
670773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
671773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
672773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
673773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
674773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
675773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
676c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
677d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
678d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
679cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
680c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
681773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
682773642d9SDouglas Gilbert static int sdebug_no_uld;
683773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
684773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
685773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
686773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
687773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
68886e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
689b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
690773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
691773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
692773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
693773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
694773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
695773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
696773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
697773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
698773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
699773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
700773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
701773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
702773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
70309ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
7040c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM;
70587c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
706773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
707773642d9SDouglas Gilbert static bool sdebug_clustering;
708773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
709773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
710817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
711773642d9SDouglas Gilbert static bool sdebug_verbose;
712f46eb0e9SDouglas Gilbert static bool have_dif_prot;
7134f2c8bf6SDouglas Gilbert static bool write_since_sync;
714c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
7159447b6ceSMartin K. Petersen static bool sdebug_wp;
7161da177e4SLinus Torvalds 
717c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
7181da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
7211da177e4SLinus Torvalds    may still need them */
7221da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
7231da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
7241da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
7271da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
7281da177e4SLinus Torvalds 
72987c715dcSDouglas Gilbert static struct xarray per_store_arr;
73087c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr;
73187c715dcSDouglas Gilbert static int sdeb_first_idx = -1;		/* invalid index ==> none created */
73287c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1;
73387c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
7341da177e4SLinus Torvalds 
73544d92694SMartin K. Petersen static unsigned long map_size;
736cbf67842SDouglas Gilbert static int num_aborts;
737cbf67842SDouglas Gilbert static int num_dev_resets;
738cbf67842SDouglas Gilbert static int num_target_resets;
739cbf67842SDouglas Gilbert static int num_bus_resets;
740cbf67842SDouglas Gilbert static int num_host_resets;
741c6a44287SMartin K. Petersen static int dix_writes;
742c6a44287SMartin K. Petersen static int dix_reads;
743c6a44287SMartin K. Petersen static int dif_errors;
7441da177e4SLinus Torvalds 
745c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
746c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
747fd32119bSDouglas Gilbert 
7481da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
74987c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2);
75087c715dcSDouglas Gilbert 
75187c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2];
7521da177e4SLinus Torvalds 
753cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
754cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
7591da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
7601da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
7611da177e4SLinus Torvalds };
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds static const int check_condition_result =
7641da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
7651da177e4SLinus Torvalds 
766c6a44287SMartin K. Petersen static const int illegal_condition_result =
767c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
768c6a44287SMartin K. Petersen 
769cbf67842SDouglas Gilbert static const int device_qfull_result =
770cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
771cbf67842SDouglas Gilbert 
772ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET;
773ed9f3e25SDouglas Gilbert 
774fd32119bSDouglas Gilbert 
775760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
776760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
777760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
778760f3b03SDouglas Gilbert  */
779760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
780fd32119bSDouglas Gilbert {
781fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
782fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
783fd32119bSDouglas Gilbert }
784c65b1445SDouglas Gilbert 
78587c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip,
78687c715dcSDouglas Gilbert 			    unsigned long long lba)
78714faa944SAkinobu Mita {
78887c715dcSDouglas Gilbert 	struct sdeb_store_info *lsip = sip;
78914faa944SAkinobu Mita 
79087c715dcSDouglas Gilbert 	lba = do_div(lba, sdebug_store_sectors);
79187c715dcSDouglas Gilbert 	if (!sip || !sip->storep) {
79287c715dcSDouglas Gilbert 		WARN_ON_ONCE(true);
79387c715dcSDouglas Gilbert 		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
79487c715dcSDouglas Gilbert 	}
79587c715dcSDouglas Gilbert 	return lsip->storep + lba * sdebug_sector_size;
79614faa944SAkinobu Mita }
79714faa944SAkinobu Mita 
79887c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
79987c715dcSDouglas Gilbert 				      sector_t sector)
80014faa944SAkinobu Mita {
80149413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
80214faa944SAkinobu Mita 
80387c715dcSDouglas Gilbert 	return sip->dif_storep + sector;
80414faa944SAkinobu Mita }
80514faa944SAkinobu Mita 
8068dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
8078dea0d02SFUJITA Tomonori {
8088dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
8098dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
8108dea0d02SFUJITA Tomonori 
8118dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
8128dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8138dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
8148dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
815773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
816773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
8178dea0d02SFUJITA Tomonori 		else
818773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
819773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
820f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
8218dea0d02SFUJITA Tomonori 	}
8228dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
8238dea0d02SFUJITA Tomonori }
8248dea0d02SFUJITA Tomonori 
82522017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
82622017ed2SDouglas Gilbert 
82722017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
828fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
829fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
83022017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
83122017ed2SDouglas Gilbert {
83222017ed2SDouglas Gilbert 	unsigned char *sbuff;
83322017ed2SDouglas Gilbert 	u8 sks[4];
83422017ed2SDouglas Gilbert 	int sl, asc;
83522017ed2SDouglas Gilbert 
83622017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
83722017ed2SDouglas Gilbert 	if (!sbuff) {
83822017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
83922017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
84022017ed2SDouglas Gilbert 		return;
84122017ed2SDouglas Gilbert 	}
84222017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
84322017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
844773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
84522017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
84622017ed2SDouglas Gilbert 	sks[0] = 0x80;
84722017ed2SDouglas Gilbert 	if (c_d)
84822017ed2SDouglas Gilbert 		sks[0] |= 0x40;
84922017ed2SDouglas Gilbert 	if (in_bit >= 0) {
85022017ed2SDouglas Gilbert 		sks[0] |= 0x8;
85122017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
85222017ed2SDouglas Gilbert 	}
85322017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
854773642d9SDouglas Gilbert 	if (sdebug_dsense) {
85522017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
85622017ed2SDouglas Gilbert 		sbuff[7] = sl;
85722017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
85822017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
85922017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
86022017ed2SDouglas Gilbert 	} else
86122017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
862773642d9SDouglas Gilbert 	if (sdebug_verbose)
86322017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
86422017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
86522017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
86622017ed2SDouglas Gilbert }
86722017ed2SDouglas Gilbert 
868cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
8698dea0d02SFUJITA Tomonori {
8708dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
8718dea0d02SFUJITA Tomonori 
872cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
873cbf67842SDouglas Gilbert 	if (!sbuff) {
874cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
875cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
876cbf67842SDouglas Gilbert 		return;
877cbf67842SDouglas Gilbert 	}
878cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
8798dea0d02SFUJITA Tomonori 
880773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
8818dea0d02SFUJITA Tomonori 
882773642d9SDouglas Gilbert 	if (sdebug_verbose)
883cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
884cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
885cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
8868dea0d02SFUJITA Tomonori }
8871da177e4SLinus Torvalds 
888fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
88922017ed2SDouglas Gilbert {
89022017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
89122017ed2SDouglas Gilbert }
89222017ed2SDouglas Gilbert 
8936f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
8946f4e626fSNathan Chancellor 			    void __user *arg)
8951da177e4SLinus Torvalds {
896773642d9SDouglas Gilbert 	if (sdebug_verbose) {
897cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
898cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
899cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
900cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
901cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
902cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
903cbf67842SDouglas Gilbert 				    __func__);
904cbf67842SDouglas Gilbert 		else
905cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
906cbf67842SDouglas Gilbert 				    __func__, cmd);
9071da177e4SLinus Torvalds 	}
9081da177e4SLinus Torvalds 	return -EINVAL;
9091da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
9101da177e4SLinus Torvalds }
9111da177e4SLinus Torvalds 
9129b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
9139b760fd8SDouglas Gilbert {
9149b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
9159b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
9169b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
9179b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
9189b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
9199b760fd8SDouglas Gilbert 		break;
9209b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
9219b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
9229b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
9239b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
9249b760fd8SDouglas Gilbert 		break;
9259b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
9269b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
9279b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
9289b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
9299b760fd8SDouglas Gilbert 		break;
9309b760fd8SDouglas Gilbert 	case 16:
9319b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
9329b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
9339b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
9349b760fd8SDouglas Gilbert 		break;
9359b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
9369b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
9379b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
9389b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
9399b760fd8SDouglas Gilbert 		break;
9409b760fd8SDouglas Gilbert 	default:
9419b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
9429b760fd8SDouglas Gilbert 			sdebug_cdb_len);
9439b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
9449b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
9459b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
9469b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
9479b760fd8SDouglas Gilbert 		break;
9489b760fd8SDouglas Gilbert 	}
9499b760fd8SDouglas Gilbert }
9509b760fd8SDouglas Gilbert 
9519b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
9529b760fd8SDouglas Gilbert {
9539b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
9549b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
9559b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
9569b760fd8SDouglas Gilbert 
9579b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
9589b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9599b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
9609b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
9619b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
9629b760fd8SDouglas Gilbert 		}
9639b760fd8SDouglas Gilbert 	}
9649b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
9659b760fd8SDouglas Gilbert }
9669b760fd8SDouglas Gilbert 
96719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
96819c8ead7SEwan D. Milne {
96919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
97019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
97119c8ead7SEwan D. Milne 
97219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
97319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
97419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
97519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
97619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
97719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
97819c8ead7SEwan D. Milne 		}
97919c8ead7SEwan D. Milne 	}
98019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
98119c8ead7SEwan D. Milne }
98219c8ead7SEwan D. Milne 
983f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
9841da177e4SLinus Torvalds {
985cbf67842SDouglas Gilbert 	int k;
986cbf67842SDouglas Gilbert 
987cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
988cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
989cbf67842SDouglas Gilbert 		const char *cp = NULL;
990cbf67842SDouglas Gilbert 
991cbf67842SDouglas Gilbert 		switch (k) {
992cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
993f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
994f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
995773642d9SDouglas Gilbert 			if (sdebug_verbose)
996cbf67842SDouglas Gilbert 				cp = "power on reset";
997cbf67842SDouglas Gilbert 			break;
998cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
999f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1000f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
1001773642d9SDouglas Gilbert 			if (sdebug_verbose)
1002cbf67842SDouglas Gilbert 				cp = "bus reset";
1003cbf67842SDouglas Gilbert 			break;
1004cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
1005f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1006f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
1007773642d9SDouglas Gilbert 			if (sdebug_verbose)
1008cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
1009cbf67842SDouglas Gilbert 			break;
10100d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
1011f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1012f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
1013773642d9SDouglas Gilbert 			if (sdebug_verbose)
10140d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
1015f49accf1SEwan D. Milne 			break;
1016acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
1017f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1018b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
1019b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
1020773642d9SDouglas Gilbert 			if (sdebug_verbose)
1021acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
1022acafd0b9SEwan D. Milne 			break;
1023acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
1024f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
1025acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
1026acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
1027773642d9SDouglas Gilbert 			if (sdebug_verbose)
1028acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
1029acafd0b9SEwan D. Milne 			break;
103019c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
103119c8ead7SEwan D. Milne 			/*
103219c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
103319c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
103419c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
103519c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
1036773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
103719c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
103819c8ead7SEwan D. Milne 			 */
1039773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
104019c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
1041f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
104219c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
104319c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
1044773642d9SDouglas Gilbert 			if (sdebug_verbose)
104519c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
104619c8ead7SEwan D. Milne 			break;
1047cbf67842SDouglas Gilbert 		default:
1048773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
1049773642d9SDouglas Gilbert 			if (sdebug_verbose)
1050cbf67842SDouglas Gilbert 				cp = "unknown";
1051cbf67842SDouglas Gilbert 			break;
1052cbf67842SDouglas Gilbert 		}
1053cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
1054773642d9SDouglas Gilbert 		if (sdebug_verbose)
1055f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1056cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1057cbf67842SDouglas Gilbert 				   my_name, cp);
10581da177e4SLinus Torvalds 		return check_condition_result;
10591da177e4SLinus Torvalds 	}
10601da177e4SLinus Torvalds 	return 0;
10611da177e4SLinus Torvalds }
10621da177e4SLinus Torvalds 
1063fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
10641da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
10651da177e4SLinus Torvalds 				int arr_len)
10661da177e4SLinus Torvalds {
106721a61829SFUJITA Tomonori 	int act_len;
1068ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
10691da177e4SLinus Torvalds 
1070072d0bb3SFUJITA Tomonori 	if (!sdb->length)
10711da177e4SLinus Torvalds 		return 0;
1072ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1073773642d9SDouglas Gilbert 		return DID_ERROR << 16;
107421a61829SFUJITA Tomonori 
107521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
107621a61829SFUJITA Tomonori 				      arr, arr_len);
107742d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
107821a61829SFUJITA Tomonori 
10791da177e4SLinus Torvalds 	return 0;
10801da177e4SLinus Torvalds }
10811da177e4SLinus Torvalds 
1082fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1083fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1084fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1085fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1086fb0cc8d1SDouglas Gilbert  */
1087fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1088fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1089fb0cc8d1SDouglas Gilbert {
10909237f04eSDamien Le Moal 	unsigned int act_len, n;
1091ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1092fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1093fb0cc8d1SDouglas Gilbert 
1094fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1095fb0cc8d1SDouglas Gilbert 		return 0;
1096ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1097fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1098fb0cc8d1SDouglas Gilbert 
1099fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1100fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1101fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
110242d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
110342d387beSBart Van Assche 		 scsi_get_resid(scp));
11049237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
110587c715dcSDouglas Gilbert 	scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
1106fb0cc8d1SDouglas Gilbert 	return 0;
1107fb0cc8d1SDouglas Gilbert }
1108fb0cc8d1SDouglas Gilbert 
1109fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1110fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1111fb0cc8d1SDouglas Gilbert  */
11121da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
111321a61829SFUJITA Tomonori 			       int arr_len)
11141da177e4SLinus Torvalds {
111521a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
11161da177e4SLinus Torvalds 		return 0;
1117ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
11181da177e4SLinus Torvalds 		return -1;
111921a61829SFUJITA Tomonori 
112021a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
11211da177e4SLinus Torvalds }
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds 
1124e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1125e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
11269b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
11271b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
11281b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
11291b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
11301b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
11311da177e4SLinus Torvalds 
1132cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1133760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
11345a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
113509ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1136bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
11371da177e4SLinus Torvalds {
1138c65b1445SDouglas Gilbert 	int num, port_a;
1139c65b1445SDouglas Gilbert 	char b[32];
11401da177e4SLinus Torvalds 
1141c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
11421da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
11431da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
11441da177e4SLinus Torvalds 	arr[1] = 0x1;
11451da177e4SLinus Torvalds 	arr[2] = 0x0;
1146e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1147e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
11481da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
11491da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
11501da177e4SLinus Torvalds 	arr[3] = num;
11511da177e4SLinus Torvalds 	num += 4;
1152c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
115309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
115409ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
115509ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
115609ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
115709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
115809ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
115909ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
116009ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
116109ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
116209ba24c1SDouglas Gilbert 			num += 16;
116309ba24c1SDouglas Gilbert 		} else {
11641b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1165c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1166c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1167c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1168c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
11691b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1170773642d9SDouglas Gilbert 			num += 8;
117109ba24c1SDouglas Gilbert 		}
1172c65b1445SDouglas Gilbert 		/* Target relative port number */
1173c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1174c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1175c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1176c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1177c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1178c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1179c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1180c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1181c65b1445SDouglas Gilbert 	}
11821b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1183c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1184c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1185c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1186c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11871b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1188773642d9SDouglas Gilbert 	num += 8;
11891b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
11905a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11915a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11925a09e398SHannes Reinecke 	arr[num++] = 0x0;
11935a09e398SHannes Reinecke 	arr[num++] = 0x4;
11945a09e398SHannes Reinecke 	arr[num++] = 0;
11955a09e398SHannes Reinecke 	arr[num++] = 0;
1196773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1197773642d9SDouglas Gilbert 	num += 2;
11981b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1199c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1200c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1201c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1202c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
12031b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1204773642d9SDouglas Gilbert 	num += 8;
1205c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1206c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1207c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1208c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1209c65b1445SDouglas Gilbert 	arr[num++] = 24;
12101b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1211c65b1445SDouglas Gilbert 	num += 12;
1212c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1213c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1214c65b1445SDouglas Gilbert 	num += 8;
1215c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1216c65b1445SDouglas Gilbert 	num += 4;
1217c65b1445SDouglas Gilbert 	return num;
1218c65b1445SDouglas Gilbert }
1219c65b1445SDouglas Gilbert 
1220c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1221c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1222c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1223c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1224c65b1445SDouglas Gilbert };
1225c65b1445SDouglas Gilbert 
1226cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1227760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1228c65b1445SDouglas Gilbert {
1229c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1230c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1231c65b1445SDouglas Gilbert }
1232c65b1445SDouglas Gilbert 
1233cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1234760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1235c65b1445SDouglas Gilbert {
1236c65b1445SDouglas Gilbert 	int num = 0;
1237c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1238c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1239c65b1445SDouglas Gilbert 	int plen, olen;
1240c65b1445SDouglas Gilbert 
1241c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1242c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1243c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1244c65b1445SDouglas Gilbert 	olen = strlen(na1);
1245c65b1445SDouglas Gilbert 	plen = olen + 1;
1246c65b1445SDouglas Gilbert 	if (plen % 4)
1247c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1248c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1249c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1250c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1251c65b1445SDouglas Gilbert 	num += plen;
1252c65b1445SDouglas Gilbert 
1253c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1254c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1255c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1256c65b1445SDouglas Gilbert 	olen = strlen(na2);
1257c65b1445SDouglas Gilbert 	plen = olen + 1;
1258c65b1445SDouglas Gilbert 	if (plen % 4)
1259c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1260c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1261c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1262c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1263c65b1445SDouglas Gilbert 	num += plen;
1264c65b1445SDouglas Gilbert 
1265c65b1445SDouglas Gilbert 	return num;
1266c65b1445SDouglas Gilbert }
1267c65b1445SDouglas Gilbert 
1268c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1269760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1270c65b1445SDouglas Gilbert {
1271c65b1445SDouglas Gilbert 	int num = 0;
1272c65b1445SDouglas Gilbert 	int port_a, port_b;
1273c65b1445SDouglas Gilbert 
1274c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1275c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1276c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1277c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1278c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1279c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1280c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1281c65b1445SDouglas Gilbert 	num += 6;
1282c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1283c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1284c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1285c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1286c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1287c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1288c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12891b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1290773642d9SDouglas Gilbert 	num += 8;
1291c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1292c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1293c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1294c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1295c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1296c65b1445SDouglas Gilbert 	num += 6;
1297c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1298c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1299c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1300c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1301c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1302c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1303c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
13041b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1305773642d9SDouglas Gilbert 	num += 8;
1306c65b1445SDouglas Gilbert 
1307c65b1445SDouglas Gilbert 	return num;
1308c65b1445SDouglas Gilbert }
1309c65b1445SDouglas Gilbert 
1310c65b1445SDouglas Gilbert 
1311c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1312c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1313c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1314c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1315c65b1445SDouglas Gilbert '1','2','3','4',
1316c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1317c65b1445SDouglas Gilbert 0xec,0,0,0,
1318c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1319c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1320c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1321c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1322c65b1445SDouglas Gilbert 0x53,0x41,
1323c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1324c65b1445SDouglas Gilbert 0x20,0x20,
1325c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1326c65b1445SDouglas Gilbert 0x10,0x80,
1327c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1328c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1329c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1330c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1331c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1332c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1333c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1334c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1335c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1336c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1337c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1338c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1339c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1340c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1341c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1342c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1343c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1344c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1345c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1346c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1347c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1348c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1349c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1350c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1351c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1352c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1353c65b1445SDouglas Gilbert };
1354c65b1445SDouglas Gilbert 
1355cbf67842SDouglas Gilbert /* ATA Information VPD page */
1356760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1357c65b1445SDouglas Gilbert {
1358c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1359c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1360c65b1445SDouglas Gilbert }
1361c65b1445SDouglas Gilbert 
1362c65b1445SDouglas Gilbert 
1363c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
13641e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
13651e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13661e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13671e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1368c65b1445SDouglas Gilbert };
1369c65b1445SDouglas Gilbert 
1370cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1371760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1372c65b1445SDouglas Gilbert {
1373ea61fca5SMartin K. Petersen 	unsigned int gran;
1374ea61fca5SMartin K. Petersen 
1375c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1376e308b3d1SMartin K. Petersen 
1377e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
137886e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
137986e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
138086e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
138186e6828aSLukas Herbolt 	else
1382773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1383773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1384e308b3d1SMartin K. Petersen 
1385e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1386773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1387773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
138844d92694SMartin K. Petersen 
1389e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1390773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1391e308b3d1SMartin K. Petersen 
1392773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1393e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1394773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1395e308b3d1SMartin K. Petersen 
1396e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1397773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
139844d92694SMartin K. Petersen 	}
139944d92694SMartin K. Petersen 
1400e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1401773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1402773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
140344d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
140444d92694SMartin K. Petersen 	}
140544d92694SMartin K. Petersen 
1406e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1407773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14086014759cSMartin K. Petersen 
14095b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1410773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
14115b94e232SMartin K. Petersen 
14125b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
141344d92694SMartin K. Petersen 
1414c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
14151da177e4SLinus Torvalds }
14161da177e4SLinus Torvalds 
14171e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1418760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1419eac6e8e4SMatthew Wilcox {
1420eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1421eac6e8e4SMatthew Wilcox 	arr[0] = 0;
14221e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
14231e49f785SDouglas Gilbert 	arr[2] = 0;
14241e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1425eac6e8e4SMatthew Wilcox 
1426eac6e8e4SMatthew Wilcox 	return 0x3c;
1427eac6e8e4SMatthew Wilcox }
14281da177e4SLinus Torvalds 
1429760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1430760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
14316014759cSMartin K. Petersen {
14323f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
14336014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1434773642d9SDouglas Gilbert 	if (sdebug_lbpu)
14356014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1436773642d9SDouglas Gilbert 	if (sdebug_lbpws)
14376014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1438773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
14395b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1440760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1441760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1442760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1443760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1444760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
14453f0bc3b3SMartin K. Petersen 	return 0x4;
14466014759cSMartin K. Petersen }
14476014759cSMartin K. Petersen 
14481da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1449c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
14501da177e4SLinus Torvalds 
1451c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
14521da177e4SLinus Torvalds {
14531da177e4SLinus Torvalds 	unsigned char pq_pdt;
14545a09e398SHannes Reinecke 	unsigned char *arr;
145501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
14565a09e398SHannes Reinecke 	int alloc_len, n, ret;
1457760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
14581da177e4SLinus Torvalds 
1459773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
14606f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
14616f3cbf55SDouglas Gilbert 	if (! arr)
14626f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1463760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1464b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1465c2248fc9SDouglas Gilbert 	if (have_wlun)
1466b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1467b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1468b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1469c65b1445SDouglas Gilbert 	else
1470773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
14711da177e4SLinus Torvalds 	arr[0] = pq_pdt;
14721da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
147322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
14745a09e398SHannes Reinecke 		kfree(arr);
14751da177e4SLinus Torvalds 		return check_condition_result;
14761da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
14775a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1478c65b1445SDouglas Gilbert 		char lu_id_str[6];
1479c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
14801da177e4SLinus Torvalds 
14815a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
14825a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1483b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
148423183910SDouglas Gilbert 			host_no = 0;
1485c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1486c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1487c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1488c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1489c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
14901da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1491c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1492c65b1445SDouglas Gilbert 			n = 4;
1493c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1494c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1495c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1496c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1497c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1498c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1499c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1500c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1501760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1502c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1503760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1504760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1505760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1506760f3b03SDouglas Gilbert 			}
1507c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
15081da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1509c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
15101da177e4SLinus Torvalds 			arr[3] = len;
1511c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
15121da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1513c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1514760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
15155a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
151609ba24c1SDouglas Gilbert 						lu_id_str, len,
151709ba24c1SDouglas Gilbert 						&devip->lu_name);
1518c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1519c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1520760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1521c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1522c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1523760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1524c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1525c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1526c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
15278475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1528c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1529760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1530c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1531c6a44287SMartin K. Petersen 			else
1532c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1533c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1534c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1535c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1536c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1537c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1538c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1539c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1540c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1541c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1542c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1543760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1544760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1545c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1546760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1547773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1548760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1549c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1550760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1551760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1552eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1553760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1554760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
15556014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1556760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
15571da177e4SLinus Torvalds 		} else {
155822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
15595a09e398SHannes Reinecke 			kfree(arr);
15601da177e4SLinus Torvalds 			return check_condition_result;
15611da177e4SLinus Torvalds 		}
1562773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
15635a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1564c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
15655a09e398SHannes Reinecke 		kfree(arr);
15665a09e398SHannes Reinecke 		return ret;
15671da177e4SLinus Torvalds 	}
15681da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1569773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1570773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
15711da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
15721da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1573f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1574b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
157570bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1576c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
15771da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1578c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1579e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1580e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1581e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
15829b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
15839b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
15841da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1585760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1586760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1587c65b1445SDouglas Gilbert 	n = 62;
1588760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1589760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1590760f3b03SDouglas Gilbert 		n += 2;
1591760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1592760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1593760f3b03SDouglas Gilbert 		n += 2;
15941da177e4SLinus Torvalds 	}
1595760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15965a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
159787c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
15985a09e398SHannes Reinecke 	kfree(arr);
15995a09e398SHannes Reinecke 	return ret;
16001da177e4SLinus Torvalds }
16011da177e4SLinus Torvalds 
1602fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1603fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1604fd32119bSDouglas Gilbert 
16051da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
16061da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
16071da177e4SLinus Torvalds {
16081da177e4SLinus Torvalds 	unsigned char *sbuff;
160901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1610cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
16112492fc09STomas Winkler 	bool dsense;
16121da177e4SLinus Torvalds 	int len = 18;
16131da177e4SLinus Torvalds 
1614c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1615c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1616cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1617c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1618c2248fc9SDouglas Gilbert 		if (dsense) {
1619c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1620c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1621c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1622c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1623c2248fc9SDouglas Gilbert 			len = 8;
1624c65b1445SDouglas Gilbert 		} else {
1625c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1626c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1627c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1628c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1629c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1630c65b1445SDouglas Gilbert 		}
1631c65b1445SDouglas Gilbert 	} else {
1632cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1633773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1634c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1635c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1636c2248fc9SDouglas Gilbert 			if (dsense) {
1637c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1638c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1639c2248fc9SDouglas Gilbert 				len = 8;
1640c2248fc9SDouglas Gilbert 			} else {
1641c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1642c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1643c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1644c2248fc9SDouglas Gilbert 			}
1645c2248fc9SDouglas Gilbert 		} else if (dsense) {
1646c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
16471da177e4SLinus Torvalds 			arr[0] = 0x72;
16481da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
16491da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
16501da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
16511da177e4SLinus Torvalds 			len = 8;
1652c2248fc9SDouglas Gilbert 		} else {
1653c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1654c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1655c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1656c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1657c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1658c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1659c65b1445SDouglas Gilbert 		}
1660c2248fc9SDouglas Gilbert 
1661c65b1445SDouglas Gilbert 	}
1662cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
16631da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
16641da177e4SLinus Torvalds }
16651da177e4SLinus Torvalds 
1666c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1667c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1668c65b1445SDouglas Gilbert {
166901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1670c4837394SDouglas Gilbert 	int power_cond, stop;
16714f2c8bf6SDouglas Gilbert 	bool changing;
1672c65b1445SDouglas Gilbert 
1673c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1674c65b1445SDouglas Gilbert 	if (power_cond) {
167522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1676c65b1445SDouglas Gilbert 		return check_condition_result;
1677c65b1445SDouglas Gilbert 	}
1678c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
16794f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1680c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
16814f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
16824f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
16834f2c8bf6SDouglas Gilbert 	else
16844f2c8bf6SDouglas Gilbert 		return 0;
1685c65b1445SDouglas Gilbert }
1686c65b1445SDouglas Gilbert 
168728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
168828898873SFUJITA Tomonori {
1689773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1690773642d9SDouglas Gilbert 
1691773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1692773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1693773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
169428898873SFUJITA Tomonori 	else
169528898873SFUJITA Tomonori 		return sdebug_store_sectors;
169628898873SFUJITA Tomonori }
169728898873SFUJITA Tomonori 
16981da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16991da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
17001da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
17011da177e4SLinus Torvalds {
17021da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1703c65b1445SDouglas Gilbert 	unsigned int capac;
17041da177e4SLinus Torvalds 
1705c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
170628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
17071da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1708c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1709c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1710773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1711773642d9SDouglas Gilbert 	} else
1712773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1713773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
17141da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
17151da177e4SLinus Torvalds }
17161da177e4SLinus Torvalds 
1717c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1718c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1719c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1720c65b1445SDouglas Gilbert {
172101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1722c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1723773642d9SDouglas Gilbert 	int alloc_len;
1724c65b1445SDouglas Gilbert 
1725773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1726c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
172728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1728c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1729773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1730773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1731773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1732773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
173344d92694SMartin K. Petersen 
1734be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
17355b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1736760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1737760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1738760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1739760f3b03SDouglas Gilbert 		 */
1740760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1741760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1742be1dd78dSEric Sandeen 	}
174344d92694SMartin K. Petersen 
1744773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1745c6a44287SMartin K. Petersen 
1746760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1747773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1748c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1749c6a44287SMartin K. Petersen 	}
1750c6a44287SMartin K. Petersen 
1751c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
175287c715dcSDouglas Gilbert 			    min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
1753c65b1445SDouglas Gilbert }
1754c65b1445SDouglas Gilbert 
17555a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
17565a09e398SHannes Reinecke 
17575a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
17585a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
17595a09e398SHannes Reinecke {
176001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
17615a09e398SHannes Reinecke 	unsigned char *arr;
17625a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
17635a09e398SHannes Reinecke 	int n, ret, alen, rlen;
17645a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
17655a09e398SHannes Reinecke 
1766773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
17676f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
17686f3cbf55SDouglas Gilbert 	if (! arr)
17696f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
17705a09e398SHannes Reinecke 	/*
17715a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
17725a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
17735a09e398SHannes Reinecke 	 * So we create two port groups with one port each
17745a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
17755a09e398SHannes Reinecke 	 */
17765a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
17775a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
17785a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
17795a09e398SHannes Reinecke 			(devip->channel & 0x7f);
17805a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
17815a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
17825a09e398SHannes Reinecke 
17835a09e398SHannes Reinecke 	/*
17845a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
17855a09e398SHannes Reinecke 	 */
17865a09e398SHannes Reinecke 	n = 4;
1787b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
17885a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
17895a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
17905a09e398SHannes Reinecke 	} else {
17915a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1792773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
17935a09e398SHannes Reinecke 	}
1794773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1795773642d9SDouglas Gilbert 	n += 2;
17965a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17975a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17985a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17995a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
18005a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
18015a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1802773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1803773642d9SDouglas Gilbert 	n += 2;
18045a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
18055a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1806773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1807773642d9SDouglas Gilbert 	n += 2;
18085a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
18095a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
18105a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
18115a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
18125a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
18135a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1814773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1815773642d9SDouglas Gilbert 	n += 2;
18165a09e398SHannes Reinecke 
18175a09e398SHannes Reinecke 	rlen = n - 4;
1818773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
18195a09e398SHannes Reinecke 
18205a09e398SHannes Reinecke 	/*
18215a09e398SHannes Reinecke 	 * Return the smallest value of either
18225a09e398SHannes Reinecke 	 * - The allocated length
18235a09e398SHannes Reinecke 	 * - The constructed command length
18245a09e398SHannes Reinecke 	 * - The maximum array size
18255a09e398SHannes Reinecke 	 */
182687c715dcSDouglas Gilbert 	rlen = min_t(int, alen, n);
18275a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
182887c715dcSDouglas Gilbert 			   min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
18295a09e398SHannes Reinecke 	kfree(arr);
18305a09e398SHannes Reinecke 	return ret;
18315a09e398SHannes Reinecke }
18325a09e398SHannes Reinecke 
1833fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1834fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
183538d5c833SDouglas Gilbert {
183638d5c833SDouglas Gilbert 	bool rctd;
183738d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
183838d5c833SDouglas Gilbert 	u16 req_sa, u;
183938d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
184038d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
184138d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
184238d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
184338d5c833SDouglas Gilbert 	u8 *arr;
184438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
184538d5c833SDouglas Gilbert 
184638d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
184738d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
184838d5c833SDouglas Gilbert 	req_opcode = cmd[3];
184938d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
185038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
18516d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
185238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
185338d5c833SDouglas Gilbert 		return check_condition_result;
185438d5c833SDouglas Gilbert 	}
185538d5c833SDouglas Gilbert 	if (alloc_len > 8192)
185638d5c833SDouglas Gilbert 		a_len = 8192;
185738d5c833SDouglas Gilbert 	else
185838d5c833SDouglas Gilbert 		a_len = alloc_len;
185999531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
186038d5c833SDouglas Gilbert 	if (NULL == arr) {
186138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
186238d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
186338d5c833SDouglas Gilbert 		return check_condition_result;
186438d5c833SDouglas Gilbert 	}
186538d5c833SDouglas Gilbert 	switch (reporting_opts) {
186638d5c833SDouglas Gilbert 	case 0:	/* all commands */
186738d5c833SDouglas Gilbert 		/* count number of commands */
186838d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
186938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
187038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
187138d5c833SDouglas Gilbert 				continue;
187238d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
187338d5c833SDouglas Gilbert 		}
187438d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
187538d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
187638d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
187738d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
187838d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
187938d5c833SDouglas Gilbert 				continue;
188038d5c833SDouglas Gilbert 			na = oip->num_attached;
188138d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
188238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
188338d5c833SDouglas Gilbert 			if (rctd)
188438d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
188538d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
188638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
188738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
188838d5c833SDouglas Gilbert 			if (rctd)
188938d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
189038d5c833SDouglas Gilbert 			r_oip = oip;
189138d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
189238d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
189338d5c833SDouglas Gilbert 					continue;
189438d5c833SDouglas Gilbert 				offset += bump;
189538d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
189638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
189738d5c833SDouglas Gilbert 				if (rctd)
189838d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
189938d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
190038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
190138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
190238d5c833SDouglas Gilbert 						   arr + offset + 6);
190338d5c833SDouglas Gilbert 				if (rctd)
190438d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
190538d5c833SDouglas Gilbert 							   arr + offset + 8);
190638d5c833SDouglas Gilbert 			}
190738d5c833SDouglas Gilbert 			oip = r_oip;
190838d5c833SDouglas Gilbert 			offset += bump;
190938d5c833SDouglas Gilbert 		}
191038d5c833SDouglas Gilbert 		break;
191138d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
191238d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
191338d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
191438d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
191538d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
191638d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
191738d5c833SDouglas Gilbert 			supp = 1;
191838d5c833SDouglas Gilbert 			offset = 4;
191938d5c833SDouglas Gilbert 		} else {
192038d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
192138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
192238d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
192338d5c833SDouglas Gilbert 							     2, 2);
192438d5c833SDouglas Gilbert 					kfree(arr);
192538d5c833SDouglas Gilbert 					return check_condition_result;
192638d5c833SDouglas Gilbert 				}
192738d5c833SDouglas Gilbert 				req_sa = 0;
192838d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
192938d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
193038d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
193138d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
193238d5c833SDouglas Gilbert 				return check_condition_result;
193338d5c833SDouglas Gilbert 			}
193438d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
193538d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
193638d5c833SDouglas Gilbert 				supp = 3;
193738d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
193838d5c833SDouglas Gilbert 				na = oip->num_attached;
193938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
194038d5c833SDouglas Gilbert 				     ++k, ++oip) {
194138d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
194238d5c833SDouglas Gilbert 						break;
194338d5c833SDouglas Gilbert 				}
194438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
194538d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
194638d5c833SDouglas Gilbert 				na = oip->num_attached;
194738d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
194838d5c833SDouglas Gilbert 				     ++k, ++oip) {
194938d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
195038d5c833SDouglas Gilbert 						break;
195138d5c833SDouglas Gilbert 				}
195238d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
195338d5c833SDouglas Gilbert 			} else
195438d5c833SDouglas Gilbert 				supp = 3;
195538d5c833SDouglas Gilbert 			if (3 == supp) {
195638d5c833SDouglas Gilbert 				u = oip->len_mask[0];
195738d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
195838d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
195938d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
196038d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
196138d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
196238d5c833SDouglas Gilbert 				offset = 4 + u;
196338d5c833SDouglas Gilbert 			} else
196438d5c833SDouglas Gilbert 				offset = 4;
196538d5c833SDouglas Gilbert 		}
196638d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
196738d5c833SDouglas Gilbert 		if (rctd) {
196838d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
196938d5c833SDouglas Gilbert 			offset += 12;
197038d5c833SDouglas Gilbert 		}
197138d5c833SDouglas Gilbert 		break;
197238d5c833SDouglas Gilbert 	default:
197338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
197438d5c833SDouglas Gilbert 		kfree(arr);
197538d5c833SDouglas Gilbert 		return check_condition_result;
197638d5c833SDouglas Gilbert 	}
197738d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
197838d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
197938d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
198038d5c833SDouglas Gilbert 	kfree(arr);
198138d5c833SDouglas Gilbert 	return errsts;
198238d5c833SDouglas Gilbert }
198338d5c833SDouglas Gilbert 
1984fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1985fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
198638d5c833SDouglas Gilbert {
198738d5c833SDouglas Gilbert 	bool repd;
198838d5c833SDouglas Gilbert 	u32 alloc_len, len;
198938d5c833SDouglas Gilbert 	u8 arr[16];
199038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
199138d5c833SDouglas Gilbert 
199238d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
199338d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
199438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
199538d5c833SDouglas Gilbert 	if (alloc_len < 4) {
199638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
199738d5c833SDouglas Gilbert 		return check_condition_result;
199838d5c833SDouglas Gilbert 	}
199938d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
200038d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
200138d5c833SDouglas Gilbert 	if (repd) {
200238d5c833SDouglas Gilbert 		arr[3] = 0xc;
200338d5c833SDouglas Gilbert 		len = 16;
200438d5c833SDouglas Gilbert 	} else
200538d5c833SDouglas Gilbert 		len = 4;
200638d5c833SDouglas Gilbert 
200738d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
200838d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
200938d5c833SDouglas Gilbert }
201038d5c833SDouglas Gilbert 
20111da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
20121da177e4SLinus Torvalds 
20131da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
20141da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
20151da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
20161da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
20191da177e4SLinus Torvalds 	if (1 == pcontrol)
20201da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
20211da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
20221da177e4SLinus Torvalds }
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
20251da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
20261da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
20271da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
20281da177e4SLinus Torvalds 
20291da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
20301da177e4SLinus Torvalds 	if (1 == pcontrol)
20311da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
20321da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
20331da177e4SLinus Torvalds }
20341da177e4SLinus Torvalds 
20351da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
20361da177e4SLinus Torvalds {       /* Format device page for mode_sense */
20371da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
20381da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
20391da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
2042773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
2043773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
2044773642d9SDouglas Gilbert 	if (sdebug_removable)
20451da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
20461da177e4SLinus Torvalds 	if (1 == pcontrol)
20471da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
20481da177e4SLinus Torvalds 	return sizeof(format_pg);
20491da177e4SLinus Torvalds }
20501da177e4SLinus Torvalds 
2051fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2052fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2053fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
2054fd32119bSDouglas Gilbert 
20551da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
20561da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2057cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2058cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2059cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
20601da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
20611da177e4SLinus Torvalds 
2062773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2063cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
20641da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
20651da177e4SLinus Torvalds 	if (1 == pcontrol)
2066cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2067cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2068cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
20691da177e4SLinus Torvalds 	return sizeof(caching_pg);
20701da177e4SLinus Torvalds }
20711da177e4SLinus Torvalds 
2072fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2073fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2074fd32119bSDouglas Gilbert 
20751da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
20761da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2077c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2078c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2079c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
20801da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
20811da177e4SLinus Torvalds 
2082773642d9SDouglas Gilbert 	if (sdebug_dsense)
20831da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2084c65b1445SDouglas Gilbert 	else
2085c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2086c6a44287SMartin K. Petersen 
2087773642d9SDouglas Gilbert 	if (sdebug_ato)
2088c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2089c6a44287SMartin K. Petersen 
20901da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
20911da177e4SLinus Torvalds 	if (1 == pcontrol)
2092c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2093c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2094c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
20951da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20961da177e4SLinus Torvalds }
20971da177e4SLinus Torvalds 
2098c65b1445SDouglas Gilbert 
20991da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
21001da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2101c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
21021da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2103c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2104c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2105c65b1445SDouglas Gilbert 
21061da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
21071da177e4SLinus Torvalds 	if (1 == pcontrol)
2108c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2109c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2110c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
21111da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
21121da177e4SLinus Torvalds }
21131da177e4SLinus Torvalds 
2114c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2115c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2116c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2117c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2118c65b1445SDouglas Gilbert 
2119c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2120c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2121c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2122c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2123c65b1445SDouglas Gilbert }
2124c65b1445SDouglas Gilbert 
2125c65b1445SDouglas Gilbert 
2126c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2127c65b1445SDouglas Gilbert 			      int target_dev_id)
2128c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2129c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2130c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2131773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2132773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2133c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2134c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2135c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2136c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2137773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2138773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2139c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2140c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2141c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2142c65b1445SDouglas Gilbert 		};
2143c65b1445SDouglas Gilbert 	int port_a, port_b;
2144c65b1445SDouglas Gilbert 
21451b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
21461b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
21471b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
21481b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2149c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2150c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2151c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2152773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2153773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2154c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2155c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2156c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2157c65b1445SDouglas Gilbert }
2158c65b1445SDouglas Gilbert 
2159c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2160c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2161c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2162c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2163c65b1445SDouglas Gilbert 		};
2164c65b1445SDouglas Gilbert 
2165c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2166c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2167c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2168c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2169c65b1445SDouglas Gilbert }
2170c65b1445SDouglas Gilbert 
21711da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
21721da177e4SLinus Torvalds 
2173fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2174fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
21751da177e4SLinus Torvalds {
217623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
21771da177e4SLinus Torvalds 	unsigned char dev_spec;
2178760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2179c2248fc9SDouglas Gilbert 	int target = scp->device->id;
21801da177e4SLinus Torvalds 	unsigned char *ap;
21811da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
218201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2183760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
21841da177e4SLinus Torvalds 
2185760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
21861da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
21871da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
21881da177e4SLinus Torvalds 	subpcode = cmd[3];
21891da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2190760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2191760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2192760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
219323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
219423183910SDouglas Gilbert 	else
219523183910SDouglas Gilbert 		bd_len = 0;
2196773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21971da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21981da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2199cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
22001da177e4SLinus Torvalds 		return check_condition_result;
22011da177e4SLinus Torvalds 	}
2202c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2203c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2204b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
22059447b6ceSMartin K. Petersen 	if (is_disk) {
2206b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
22079447b6ceSMartin K. Petersen 		if (sdebug_wp)
22089447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
22099447b6ceSMartin K. Petersen 	} else
221023183910SDouglas Gilbert 		dev_spec = 0x0;
22111da177e4SLinus Torvalds 	if (msense_6) {
22121da177e4SLinus Torvalds 		arr[2] = dev_spec;
221323183910SDouglas Gilbert 		arr[3] = bd_len;
22141da177e4SLinus Torvalds 		offset = 4;
22151da177e4SLinus Torvalds 	} else {
22161da177e4SLinus Torvalds 		arr[3] = dev_spec;
221723183910SDouglas Gilbert 		if (16 == bd_len)
221823183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
221923183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
22201da177e4SLinus Torvalds 		offset = 8;
22211da177e4SLinus Torvalds 	}
22221da177e4SLinus Torvalds 	ap = arr + offset;
222328898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
222428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
222528898873SFUJITA Tomonori 
222623183910SDouglas Gilbert 	if (8 == bd_len) {
2227773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2228773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2229773642d9SDouglas Gilbert 		else
2230773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2231773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
223223183910SDouglas Gilbert 		offset += bd_len;
223323183910SDouglas Gilbert 		ap = arr + offset;
223423183910SDouglas Gilbert 	} else if (16 == bd_len) {
2235773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2236773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
223723183910SDouglas Gilbert 		offset += bd_len;
223823183910SDouglas Gilbert 		ap = arr + offset;
223923183910SDouglas Gilbert 	}
22401da177e4SLinus Torvalds 
2241c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2242c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
224322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
22441da177e4SLinus Torvalds 		return check_condition_result;
22451da177e4SLinus Torvalds 	}
2246760f3b03SDouglas Gilbert 	bad_pcode = false;
2247760f3b03SDouglas Gilbert 
22481da177e4SLinus Torvalds 	switch (pcode) {
22491da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
22501da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
22511da177e4SLinus Torvalds 		offset += len;
22521da177e4SLinus Torvalds 		break;
22531da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
22541da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
22551da177e4SLinus Torvalds 		offset += len;
22561da177e4SLinus Torvalds 		break;
22571da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2258760f3b03SDouglas Gilbert 		if (is_disk) {
22591da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
22601da177e4SLinus Torvalds 			offset += len;
2261760f3b03SDouglas Gilbert 		} else
2262760f3b03SDouglas Gilbert 			bad_pcode = true;
22631da177e4SLinus Torvalds 		break;
22641da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2265760f3b03SDouglas Gilbert 		if (is_disk) {
22661da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
22671da177e4SLinus Torvalds 			offset += len;
2268760f3b03SDouglas Gilbert 		} else
2269760f3b03SDouglas Gilbert 			bad_pcode = true;
22701da177e4SLinus Torvalds 		break;
22711da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
22721da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
22731da177e4SLinus Torvalds 		offset += len;
22741da177e4SLinus Torvalds 		break;
2275c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2276c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
227722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2278c65b1445SDouglas Gilbert 			return check_condition_result;
2279c65b1445SDouglas Gilbert 		}
2280c65b1445SDouglas Gilbert 		len = 0;
2281c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2282c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2283c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2284c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2285c65b1445SDouglas Gilbert 						  target_dev_id);
2286c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2287c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2288c65b1445SDouglas Gilbert 		offset += len;
2289c65b1445SDouglas Gilbert 		break;
22901da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
22911da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
22921da177e4SLinus Torvalds 		offset += len;
22931da177e4SLinus Torvalds 		break;
22941da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2295c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
22961da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
22971da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2298760f3b03SDouglas Gilbert 			if (is_disk) {
2299760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2300760f3b03SDouglas Gilbert 						      target);
2301760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2302760f3b03SDouglas Gilbert 						       target);
2303760f3b03SDouglas Gilbert 			}
23041da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2305c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2306c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2307c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2308c65b1445SDouglas Gilbert 						  target, target_dev_id);
2309c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2310c65b1445SDouglas Gilbert 			}
23111da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2312760f3b03SDouglas Gilbert 			offset += len;
2313c65b1445SDouglas Gilbert 		} else {
231422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2315c65b1445SDouglas Gilbert 			return check_condition_result;
2316c65b1445SDouglas Gilbert 		}
23171da177e4SLinus Torvalds 		break;
23181da177e4SLinus Torvalds 	default:
2319760f3b03SDouglas Gilbert 		bad_pcode = true;
2320760f3b03SDouglas Gilbert 		break;
2321760f3b03SDouglas Gilbert 	}
2322760f3b03SDouglas Gilbert 	if (bad_pcode) {
232322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
23241da177e4SLinus Torvalds 		return check_condition_result;
23251da177e4SLinus Torvalds 	}
23261da177e4SLinus Torvalds 	if (msense_6)
23271da177e4SLinus Torvalds 		arr[0] = offset - 1;
2328773642d9SDouglas Gilbert 	else
2329773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
233087c715dcSDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
23311da177e4SLinus Torvalds }
23321da177e4SLinus Torvalds 
2333c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2334c65b1445SDouglas Gilbert 
2335fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2336fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2337c65b1445SDouglas Gilbert {
2338c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2339c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2340c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
234101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2342c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2343c65b1445SDouglas Gilbert 
2344c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2345c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2346c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2347773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2348c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
234922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2350c65b1445SDouglas Gilbert 		return check_condition_result;
2351c65b1445SDouglas Gilbert 	}
2352c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2353c65b1445SDouglas Gilbert 	if (-1 == res)
2354773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2355773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2356cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2357cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2358cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2359773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2360773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
236123183910SDouglas Gilbert 	if (md_len > 2) {
236222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2363c65b1445SDouglas Gilbert 		return check_condition_result;
2364c65b1445SDouglas Gilbert 	}
2365c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2366c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2367c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2368c65b1445SDouglas Gilbert 	if (ps) {
236922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2370c65b1445SDouglas Gilbert 		return check_condition_result;
2371c65b1445SDouglas Gilbert 	}
2372c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2373773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2374c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2375c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2376cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2377c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2378c65b1445SDouglas Gilbert 		return check_condition_result;
2379c65b1445SDouglas Gilbert 	}
2380c65b1445SDouglas Gilbert 	switch (mpage) {
2381cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2382cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2383cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2384cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2385cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2386cbf67842SDouglas Gilbert 		}
2387cbf67842SDouglas Gilbert 		break;
2388c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2389c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2390c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2391c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
23929447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
23939447b6ceSMartin K. Petersen 				sdebug_wp = true;
23949447b6ceSMartin K. Petersen 			else
23959447b6ceSMartin K. Petersen 				sdebug_wp = false;
2396773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2397cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2398c65b1445SDouglas Gilbert 		}
2399c65b1445SDouglas Gilbert 		break;
2400c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2401c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2402c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2403c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2404cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2405c65b1445SDouglas Gilbert 		}
2406c65b1445SDouglas Gilbert 		break;
2407c65b1445SDouglas Gilbert 	default:
2408c65b1445SDouglas Gilbert 		break;
2409c65b1445SDouglas Gilbert 	}
241022017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2411c65b1445SDouglas Gilbert 	return check_condition_result;
2412cbf67842SDouglas Gilbert set_mode_changed_ua:
2413cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2414cbf67842SDouglas Gilbert 	return 0;
2415c65b1445SDouglas Gilbert }
2416c65b1445SDouglas Gilbert 
2417c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2418c65b1445SDouglas Gilbert {
2419c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2420c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2421c65b1445SDouglas Gilbert 		};
2422c65b1445SDouglas Gilbert 
2423c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2424c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2425c65b1445SDouglas Gilbert }
2426c65b1445SDouglas Gilbert 
2427c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2428c65b1445SDouglas Gilbert {
2429c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2430c65b1445SDouglas Gilbert 		};
2431c65b1445SDouglas Gilbert 
2432c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2433c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2434c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2435c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2436c65b1445SDouglas Gilbert 	}
2437c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2438c65b1445SDouglas Gilbert }
2439c65b1445SDouglas Gilbert 
2440c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2441c65b1445SDouglas Gilbert 
2442c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2443c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2444c65b1445SDouglas Gilbert {
2445ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2446c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
244701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2448c65b1445SDouglas Gilbert 
2449c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2450c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2451c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2452c65b1445SDouglas Gilbert 	if (ppc || sp) {
245322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2454c65b1445SDouglas Gilbert 		return check_condition_result;
2455c65b1445SDouglas Gilbert 	}
2456c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
245723183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2458773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2459c65b1445SDouglas Gilbert 	arr[0] = pcode;
246023183910SDouglas Gilbert 	if (0 == subpcode) {
2461c65b1445SDouglas Gilbert 		switch (pcode) {
2462c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2463c65b1445SDouglas Gilbert 			n = 4;
2464c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2465c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2466c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2467c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2468c65b1445SDouglas Gilbert 			break;
2469c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2470c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2471c65b1445SDouglas Gilbert 			break;
2472c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2473c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2474c65b1445SDouglas Gilbert 			break;
2475c65b1445SDouglas Gilbert 		default:
247622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2477c65b1445SDouglas Gilbert 			return check_condition_result;
2478c65b1445SDouglas Gilbert 		}
247923183910SDouglas Gilbert 	} else if (0xff == subpcode) {
248023183910SDouglas Gilbert 		arr[0] |= 0x40;
248123183910SDouglas Gilbert 		arr[1] = subpcode;
248223183910SDouglas Gilbert 		switch (pcode) {
248323183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
248423183910SDouglas Gilbert 			n = 4;
248523183910SDouglas Gilbert 			arr[n++] = 0x0;
248623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
248723183910SDouglas Gilbert 			arr[n++] = 0x0;
248823183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
248923183910SDouglas Gilbert 			arr[n++] = 0xd;
249023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
249123183910SDouglas Gilbert 			arr[n++] = 0x2f;
249223183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
249323183910SDouglas Gilbert 			arr[3] = n - 4;
249423183910SDouglas Gilbert 			break;
249523183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
249623183910SDouglas Gilbert 			n = 4;
249723183910SDouglas Gilbert 			arr[n++] = 0xd;
249823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
249923183910SDouglas Gilbert 			arr[3] = n - 4;
250023183910SDouglas Gilbert 			break;
250123183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
250223183910SDouglas Gilbert 			n = 4;
250323183910SDouglas Gilbert 			arr[n++] = 0x2f;
250423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
250523183910SDouglas Gilbert 			arr[3] = n - 4;
250623183910SDouglas Gilbert 			break;
250723183910SDouglas Gilbert 		default:
250822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
250923183910SDouglas Gilbert 			return check_condition_result;
251023183910SDouglas Gilbert 		}
251123183910SDouglas Gilbert 	} else {
251222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
251323183910SDouglas Gilbert 		return check_condition_result;
251423183910SDouglas Gilbert 	}
251587c715dcSDouglas Gilbert 	len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
2516c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
251787c715dcSDouglas Gilbert 		    min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
2518c65b1445SDouglas Gilbert }
2519c65b1445SDouglas Gilbert 
25209447b6ceSMartin K. Petersen static inline int check_device_access_params(struct scsi_cmnd *scp,
25219447b6ceSMartin K. Petersen 	unsigned long long lba, unsigned int num, bool write)
25221da177e4SLinus Torvalds {
2523c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
252422017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
25251da177e4SLinus Torvalds 		return check_condition_result;
25261da177e4SLinus Torvalds 	}
2527c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2528c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
252922017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2530cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2531c65b1445SDouglas Gilbert 		return check_condition_result;
2532c65b1445SDouglas Gilbert 	}
25339447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
25349447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
25359447b6ceSMartin K. Petersen 		return check_condition_result;
25369447b6ceSMartin K. Petersen 	}
253719789100SFUJITA Tomonori 	return 0;
253819789100SFUJITA Tomonori }
253919789100SFUJITA Tomonori 
254087c715dcSDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip)
254187c715dcSDouglas Gilbert {
254287c715dcSDouglas Gilbert 	return sdebug_fake_rw ?
254387c715dcSDouglas Gilbert 			NULL : xa_load(per_store_ap, devip->sdbg_host->si_idx);
254487c715dcSDouglas Gilbert }
254587c715dcSDouglas Gilbert 
2546a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
254787c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
254887c715dcSDouglas Gilbert 			    u32 sg_skip, u64 lba, u32 num, bool do_write)
254919789100SFUJITA Tomonori {
255019789100SFUJITA Tomonori 	int ret;
2551c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2552a4517511SAkinobu Mita 	enum dma_data_direction dir;
255387c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
255487c715dcSDouglas Gilbert 	u8 *fsp;
255519789100SFUJITA Tomonori 
2556c2248fc9SDouglas Gilbert 	if (do_write) {
2557a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
25584f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2559a4517511SAkinobu Mita 	} else {
2560a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2561a4517511SAkinobu Mita 	}
2562a4517511SAkinobu Mita 
256387c715dcSDouglas Gilbert 	if (!sdb->length || !sip)
2564a4517511SAkinobu Mita 		return 0;
256587c715dcSDouglas Gilbert 	if (scp->sc_data_direction != dir)
2566a4517511SAkinobu Mita 		return -1;
256787c715dcSDouglas Gilbert 	fsp = sip->storep;
256819789100SFUJITA Tomonori 
256919789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
257019789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
257119789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
257219789100SFUJITA Tomonori 
2573386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
257487c715dcSDouglas Gilbert 		   fsp + (block * sdebug_sector_size),
25750a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2576773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2577a4517511SAkinobu Mita 		return ret;
2578a4517511SAkinobu Mita 
2579a4517511SAkinobu Mita 	if (rest) {
2580386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
258187c715dcSDouglas Gilbert 			    fsp, rest * sdebug_sector_size,
25820a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
25830a7e69c7SDouglas Gilbert 			    do_write);
2584a4517511SAkinobu Mita 	}
258519789100SFUJITA Tomonori 
258619789100SFUJITA Tomonori 	return ret;
258719789100SFUJITA Tomonori }
258819789100SFUJITA Tomonori 
258987c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */
259087c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
259187c715dcSDouglas Gilbert {
259287c715dcSDouglas Gilbert 	struct scsi_data_buffer *sdb = &scp->sdb;
259387c715dcSDouglas Gilbert 
259487c715dcSDouglas Gilbert 	if (!sdb->length)
259587c715dcSDouglas Gilbert 		return 0;
259687c715dcSDouglas Gilbert 	if (scp->sc_data_direction != DMA_TO_DEVICE)
259787c715dcSDouglas Gilbert 		return -1;
259887c715dcSDouglas Gilbert 	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
259987c715dcSDouglas Gilbert 			      num * sdebug_sector_size, 0, true);
260087c715dcSDouglas Gilbert }
260187c715dcSDouglas Gilbert 
260287c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of
260387c715dcSDouglas Gilbert  * arr into sip->storep+lba and return true. If comparison fails then
260438d5c833SDouglas Gilbert  * return false. */
260587c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
2606c3e2fe92SDouglas Gilbert 			      const u8 *arr, bool compare_only)
260738d5c833SDouglas Gilbert {
260838d5c833SDouglas Gilbert 	bool res;
260938d5c833SDouglas Gilbert 	u64 block, rest = 0;
261038d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2611773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
261287c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
261338d5c833SDouglas Gilbert 
261438d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
261538d5c833SDouglas Gilbert 	if (block + num > store_blks)
261638d5c833SDouglas Gilbert 		rest = block + num - store_blks;
261738d5c833SDouglas Gilbert 
261887c715dcSDouglas Gilbert 	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
261938d5c833SDouglas Gilbert 	if (!res)
262038d5c833SDouglas Gilbert 		return res;
262138d5c833SDouglas Gilbert 	if (rest)
262287c715dcSDouglas Gilbert 		res = memcmp(fsp, arr + ((num - rest) * lb_size),
262338d5c833SDouglas Gilbert 			     rest * lb_size);
262438d5c833SDouglas Gilbert 	if (!res)
262538d5c833SDouglas Gilbert 		return res;
2626c3e2fe92SDouglas Gilbert 	if (compare_only)
2627c3e2fe92SDouglas Gilbert 		return true;
262838d5c833SDouglas Gilbert 	arr += num * lb_size;
262987c715dcSDouglas Gilbert 	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
263038d5c833SDouglas Gilbert 	if (rest)
263187c715dcSDouglas Gilbert 		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
263238d5c833SDouglas Gilbert 	return res;
263338d5c833SDouglas Gilbert }
263438d5c833SDouglas Gilbert 
263551d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2636beb40ea4SAkinobu Mita {
263751d648afSAkinobu Mita 	__be16 csum;
2638beb40ea4SAkinobu Mita 
2639773642d9SDouglas Gilbert 	if (sdebug_guard)
264051d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
264151d648afSAkinobu Mita 	else
2642beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
264351d648afSAkinobu Mita 
2644beb40ea4SAkinobu Mita 	return csum;
2645beb40ea4SAkinobu Mita }
2646beb40ea4SAkinobu Mita 
26476ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2648beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2649beb40ea4SAkinobu Mita {
2650773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2651beb40ea4SAkinobu Mita 
2652beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2653c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2654beb40ea4SAkinobu Mita 			(unsigned long)sector,
2655beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2656beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2657beb40ea4SAkinobu Mita 		return 0x01;
2658beb40ea4SAkinobu Mita 	}
26598475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2660beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2661c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2662c1287970STomas Winkler 			(unsigned long)sector);
2663beb40ea4SAkinobu Mita 		return 0x03;
2664beb40ea4SAkinobu Mita 	}
26658475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2666beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2667c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2668c1287970STomas Winkler 			(unsigned long)sector);
2669beb40ea4SAkinobu Mita 		return 0x03;
2670beb40ea4SAkinobu Mita 	}
2671beb40ea4SAkinobu Mita 	return 0;
2672beb40ea4SAkinobu Mita }
2673beb40ea4SAkinobu Mita 
267487c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
267565f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2676c6a44287SMartin K. Petersen {
2677be4e11beSAkinobu Mita 	size_t resid;
2678c6a44287SMartin K. Petersen 	void *paddr;
267987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
268087c715dcSDouglas Gilbert 						scp->device->hostdata);
268187c715dcSDouglas Gilbert 	struct t10_pi_tuple *dif_storep = sip->dif_storep;
268214faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2683be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2684c6a44287SMartin K. Petersen 
2685e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2686e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2687c6a44287SMartin K. Petersen 
268887c715dcSDouglas Gilbert 	sg_miter_start(&miter, scsi_prot_sglist(scp),
268987c715dcSDouglas Gilbert 		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
2690be4e11beSAkinobu Mita 		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2691be4e11beSAkinobu Mita 
2692be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
269387c715dcSDouglas Gilbert 		size_t len = min_t(size_t, miter.length, resid);
269487c715dcSDouglas Gilbert 		void *start = dif_store(sip, sector);
2695be4e11beSAkinobu Mita 		size_t rest = 0;
269614faa944SAkinobu Mita 
269714faa944SAkinobu Mita 		if (dif_store_end < start + len)
269814faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2699c6a44287SMartin K. Petersen 
2700be4e11beSAkinobu Mita 		paddr = miter.addr;
270114faa944SAkinobu Mita 
270265f72f2aSAkinobu Mita 		if (read)
270365f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
270465f72f2aSAkinobu Mita 		else
270565f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
270665f72f2aSAkinobu Mita 
270765f72f2aSAkinobu Mita 		if (rest) {
270865f72f2aSAkinobu Mita 			if (read)
270914faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
271065f72f2aSAkinobu Mita 			else
271165f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
271265f72f2aSAkinobu Mita 		}
2713c6a44287SMartin K. Petersen 
2714e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2715c6a44287SMartin K. Petersen 		resid -= len;
2716c6a44287SMartin K. Petersen 	}
2717be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2718bb8c063cSAkinobu Mita }
2719c6a44287SMartin K. Petersen 
272087c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
2721bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2722bb8c063cSAkinobu Mita {
2723bb8c063cSAkinobu Mita 	unsigned int i;
2724bb8c063cSAkinobu Mita 	sector_t sector;
272587c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
272687c715dcSDouglas Gilbert 						scp->device->hostdata);
272787c715dcSDouglas Gilbert 	struct t10_pi_tuple *sdt;
2728bb8c063cSAkinobu Mita 
2729c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2730bb8c063cSAkinobu Mita 		int ret;
2731bb8c063cSAkinobu Mita 
2732bb8c063cSAkinobu Mita 		sector = start_sec + i;
273387c715dcSDouglas Gilbert 		sdt = dif_store(sip, sector);
2734bb8c063cSAkinobu Mita 
273551d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2736bb8c063cSAkinobu Mita 			continue;
2737bb8c063cSAkinobu Mita 
273887c715dcSDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
273987c715dcSDouglas Gilbert 				 ei_lba);
2740bb8c063cSAkinobu Mita 		if (ret) {
2741bb8c063cSAkinobu Mita 			dif_errors++;
2742bb8c063cSAkinobu Mita 			return ret;
2743bb8c063cSAkinobu Mita 		}
2744bb8c063cSAkinobu Mita 	}
2745bb8c063cSAkinobu Mita 
274687c715dcSDouglas Gilbert 	dif_copy_prot(scp, start_sec, sectors, true);
2747c6a44287SMartin K. Petersen 	dix_reads++;
2748c6a44287SMartin K. Petersen 
2749c6a44287SMartin K. Petersen 	return 0;
2750c6a44287SMartin K. Petersen }
2751c6a44287SMartin K. Petersen 
2752fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
275319789100SFUJITA Tomonori {
275487c715dcSDouglas Gilbert 	bool check_prot;
2755c2248fc9SDouglas Gilbert 	u32 num;
2756c2248fc9SDouglas Gilbert 	u32 ei_lba;
275719789100SFUJITA Tomonori 	int ret;
275887c715dcSDouglas Gilbert 	u64 lba;
275987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
276087c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
276187c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
276287c715dcSDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
276319789100SFUJITA Tomonori 
2764c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2765c2248fc9SDouglas Gilbert 	case READ_16:
2766c2248fc9SDouglas Gilbert 		ei_lba = 0;
2767c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2768c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2769c2248fc9SDouglas Gilbert 		check_prot = true;
2770c2248fc9SDouglas Gilbert 		break;
2771c2248fc9SDouglas Gilbert 	case READ_10:
2772c2248fc9SDouglas Gilbert 		ei_lba = 0;
2773c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2774c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2775c2248fc9SDouglas Gilbert 		check_prot = true;
2776c2248fc9SDouglas Gilbert 		break;
2777c2248fc9SDouglas Gilbert 	case READ_6:
2778c2248fc9SDouglas Gilbert 		ei_lba = 0;
2779c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2780c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2781c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2782c2248fc9SDouglas Gilbert 		check_prot = true;
2783c2248fc9SDouglas Gilbert 		break;
2784c2248fc9SDouglas Gilbert 	case READ_12:
2785c2248fc9SDouglas Gilbert 		ei_lba = 0;
2786c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2787c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2788c2248fc9SDouglas Gilbert 		check_prot = true;
2789c2248fc9SDouglas Gilbert 		break;
2790c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2791c2248fc9SDouglas Gilbert 		ei_lba = 0;
2792c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2793c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2794c2248fc9SDouglas Gilbert 		check_prot = false;
2795c2248fc9SDouglas Gilbert 		break;
2796c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2797c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2798c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2799c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2800c2248fc9SDouglas Gilbert 		check_prot = false;
2801c2248fc9SDouglas Gilbert 		break;
2802c2248fc9SDouglas Gilbert 	}
2803f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
28048475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2805c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2806c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2807c2248fc9SDouglas Gilbert 			return check_condition_result;
2808c2248fc9SDouglas Gilbert 		}
28098475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
28108475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2811c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2812c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2813c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2814c2248fc9SDouglas Gilbert 	}
2815f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2816c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2817c2248fc9SDouglas Gilbert 
2818c4837394SDouglas Gilbert 		if (sqcp) {
2819c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2820c2248fc9SDouglas Gilbert 				num /= 2;
2821c2248fc9SDouglas Gilbert 		}
2822c4837394SDouglas Gilbert 	} else
2823c4837394SDouglas Gilbert 		sqcp = NULL;
2824c2248fc9SDouglas Gilbert 
28259447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
28269447b6ceSMartin K. Petersen 	if (ret)
28279447b6ceSMartin K. Petersen 		return ret;
2828f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2829d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2830d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
2831c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2832c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2833c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2834c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2835c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
283632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
283732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2838c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2839c65b1445SDouglas Gilbert 		}
2840c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
28411da177e4SLinus Torvalds 		return check_condition_result;
28421da177e4SLinus Torvalds 	}
2843c6a44287SMartin K. Petersen 
284467da413fSDouglas Gilbert 	read_lock(macc_lckp);
28456c78cc06SAkinobu Mita 
2846c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2847f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2848c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2849c6a44287SMartin K. Petersen 
2850c6a44287SMartin K. Petersen 		if (prot_ret) {
285167da413fSDouglas Gilbert 			read_unlock(macc_lckp);
2852c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2853c6a44287SMartin K. Petersen 			return illegal_condition_result;
2854c6a44287SMartin K. Petersen 		}
2855c6a44287SMartin K. Petersen 	}
2856c6a44287SMartin K. Petersen 
285787c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, false);
285867da413fSDouglas Gilbert 	read_unlock(macc_lckp);
2859f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2860a4517511SAkinobu Mita 		return DID_ERROR << 16;
2861a4517511SAkinobu Mita 
286242d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
2863a4517511SAkinobu Mita 
2864c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2865c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2866c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2867c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2868c2248fc9SDouglas Gilbert 			return check_condition_result;
2869c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2870c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2871c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2872c2248fc9SDouglas Gilbert 			return check_condition_result;
2873c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2874c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2875c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2876c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2877c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2878c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2879c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2880c2248fc9SDouglas Gilbert 		}
2881c2248fc9SDouglas Gilbert 	}
2882a4517511SAkinobu Mita 	return 0;
28831da177e4SLinus Torvalds }
28841da177e4SLinus Torvalds 
288558a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2886c6a44287SMartin K. Petersen {
2887cbf67842SDouglas Gilbert 	int i, j, n;
2888c6a44287SMartin K. Petersen 
2889cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2890c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2891cbf67842SDouglas Gilbert 		char b[128];
2892c6a44287SMartin K. Petersen 
2893cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2894c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2895c6a44287SMartin K. Petersen 
2896cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2897cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2898cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2899cbf67842SDouglas Gilbert 			else
2900cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2901cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2902cbf67842SDouglas Gilbert 		}
2903cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2904c6a44287SMartin K. Petersen 	}
2905c6a44287SMartin K. Petersen }
2906c6a44287SMartin K. Petersen 
2907c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2908395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2909c6a44287SMartin K. Petersen {
2910be4e11beSAkinobu Mita 	int ret;
29116ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2912be4e11beSAkinobu Mita 	void *daddr;
291365f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2914c6a44287SMartin K. Petersen 	int ppage_offset;
2915be4e11beSAkinobu Mita 	int dpage_offset;
2916be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2917be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2918c6a44287SMartin K. Petersen 
2919c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2920c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2921c6a44287SMartin K. Petersen 
2922be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2923be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2924be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2925be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2926be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2927c6a44287SMartin K. Petersen 
2928be4e11beSAkinobu Mita 	/* For each protection page */
2929be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2930be4e11beSAkinobu Mita 		dpage_offset = 0;
2931be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2932be4e11beSAkinobu Mita 			ret = 0x01;
2933be4e11beSAkinobu Mita 			goto out;
2934c6a44287SMartin K. Petersen 		}
2935c6a44287SMartin K. Petersen 
2936be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
29376ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2938be4e11beSAkinobu Mita 			/* If we're at the end of the current
2939be4e11beSAkinobu Mita 			 * data page advance to the next one
2940be4e11beSAkinobu Mita 			 */
2941be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2942be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2943be4e11beSAkinobu Mita 					ret = 0x01;
2944be4e11beSAkinobu Mita 					goto out;
2945be4e11beSAkinobu Mita 				}
2946be4e11beSAkinobu Mita 				dpage_offset = 0;
2947be4e11beSAkinobu Mita 			}
2948c6a44287SMartin K. Petersen 
2949be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2950be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2951be4e11beSAkinobu Mita 
2952be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2953beb40ea4SAkinobu Mita 			if (ret) {
2954773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2955395cef03SMartin K. Petersen 				goto out;
2956395cef03SMartin K. Petersen 			}
2957395cef03SMartin K. Petersen 
2958c6a44287SMartin K. Petersen 			sector++;
2959395cef03SMartin K. Petersen 			ei_lba++;
2960773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2961c6a44287SMartin K. Petersen 		}
2962be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2963be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2964c6a44287SMartin K. Petersen 	}
2965be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2966c6a44287SMartin K. Petersen 
296765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2968c6a44287SMartin K. Petersen 	dix_writes++;
2969c6a44287SMartin K. Petersen 
2970c6a44287SMartin K. Petersen 	return 0;
2971c6a44287SMartin K. Petersen 
2972c6a44287SMartin K. Petersen out:
2973c6a44287SMartin K. Petersen 	dif_errors++;
2974be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2975be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2976c6a44287SMartin K. Petersen 	return ret;
2977c6a44287SMartin K. Petersen }
2978c6a44287SMartin K. Petersen 
2979b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2980b90ebc3dSAkinobu Mita {
2981773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2982773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2983773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2984b90ebc3dSAkinobu Mita 	return lba;
2985b90ebc3dSAkinobu Mita }
2986b90ebc3dSAkinobu Mita 
2987b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2988b90ebc3dSAkinobu Mita {
2989773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2990a027b5b9SAkinobu Mita 
2991773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2992773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2993a027b5b9SAkinobu Mita 	return lba;
2994a027b5b9SAkinobu Mita }
2995a027b5b9SAkinobu Mita 
299687c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
299787c715dcSDouglas Gilbert 			      unsigned int *num)
299844d92694SMartin K. Petersen {
2999b90ebc3dSAkinobu Mita 	sector_t end;
3000b90ebc3dSAkinobu Mita 	unsigned int mapped;
3001b90ebc3dSAkinobu Mita 	unsigned long index;
3002b90ebc3dSAkinobu Mita 	unsigned long next;
300344d92694SMartin K. Petersen 
3004b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
300587c715dcSDouglas Gilbert 	mapped = test_bit(index, sip->map_storep);
300644d92694SMartin K. Petersen 
300744d92694SMartin K. Petersen 	if (mapped)
300887c715dcSDouglas Gilbert 		next = find_next_zero_bit(sip->map_storep, map_size, index);
300944d92694SMartin K. Petersen 	else
301087c715dcSDouglas Gilbert 		next = find_next_bit(sip->map_storep, map_size, index);
301144d92694SMartin K. Petersen 
3012b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
301344d92694SMartin K. Petersen 	*num = end - lba;
301444d92694SMartin K. Petersen 	return mapped;
301544d92694SMartin K. Petersen }
301644d92694SMartin K. Petersen 
301787c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba,
301887c715dcSDouglas Gilbert 		       unsigned int len)
301944d92694SMartin K. Petersen {
302044d92694SMartin K. Petersen 	sector_t end = lba + len;
302144d92694SMartin K. Petersen 
302244d92694SMartin K. Petersen 	while (lba < end) {
3023b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
302444d92694SMartin K. Petersen 
3025b90ebc3dSAkinobu Mita 		if (index < map_size)
302687c715dcSDouglas Gilbert 			set_bit(index, sip->map_storep);
302744d92694SMartin K. Petersen 
3028b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
302944d92694SMartin K. Petersen 	}
303044d92694SMartin K. Petersen }
303144d92694SMartin K. Petersen 
303287c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
303387c715dcSDouglas Gilbert 			 unsigned int len)
303444d92694SMartin K. Petersen {
303544d92694SMartin K. Petersen 	sector_t end = lba + len;
303687c715dcSDouglas Gilbert 	u8 *fsp = sip->storep;
303744d92694SMartin K. Petersen 
303844d92694SMartin K. Petersen 	while (lba < end) {
3039b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
304044d92694SMartin K. Petersen 
3041b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
3042773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
3043b90ebc3dSAkinobu Mita 		    index < map_size) {
304487c715dcSDouglas Gilbert 			clear_bit(index, sip->map_storep);
3045760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
304687c715dcSDouglas Gilbert 				memset(fsp + lba * sdebug_sector_size,
3047760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
3048773642d9SDouglas Gilbert 				       sdebug_sector_size *
3049773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3050be1dd78dSEric Sandeen 			}
305187c715dcSDouglas Gilbert 			if (sip->dif_storep) {
305287c715dcSDouglas Gilbert 				memset(sip->dif_storep + lba, 0xff,
305387c715dcSDouglas Gilbert 				       sizeof(*sip->dif_storep) *
3054773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
3055e9926b43SAkinobu Mita 			}
3056b90ebc3dSAkinobu Mita 		}
3057b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
305844d92694SMartin K. Petersen 	}
305944d92694SMartin K. Petersen }
306044d92694SMartin K. Petersen 
3061fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
30621da177e4SLinus Torvalds {
306387c715dcSDouglas Gilbert 	bool check_prot;
3064c2248fc9SDouglas Gilbert 	u32 num;
3065c2248fc9SDouglas Gilbert 	u32 ei_lba;
306619789100SFUJITA Tomonori 	int ret;
306787c715dcSDouglas Gilbert 	u64 lba;
306887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
306987c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
307087c715dcSDouglas Gilbert 	u8 *cmd = scp->cmnd;
30711da177e4SLinus Torvalds 
3072c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
3073c2248fc9SDouglas Gilbert 	case WRITE_16:
3074c2248fc9SDouglas Gilbert 		ei_lba = 0;
3075c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3076c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
3077c2248fc9SDouglas Gilbert 		check_prot = true;
3078c2248fc9SDouglas Gilbert 		break;
3079c2248fc9SDouglas Gilbert 	case WRITE_10:
3080c2248fc9SDouglas Gilbert 		ei_lba = 0;
3081c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3082c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3083c2248fc9SDouglas Gilbert 		check_prot = true;
3084c2248fc9SDouglas Gilbert 		break;
3085c2248fc9SDouglas Gilbert 	case WRITE_6:
3086c2248fc9SDouglas Gilbert 		ei_lba = 0;
3087c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3088c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3089c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3090c2248fc9SDouglas Gilbert 		check_prot = true;
3091c2248fc9SDouglas Gilbert 		break;
3092c2248fc9SDouglas Gilbert 	case WRITE_12:
3093c2248fc9SDouglas Gilbert 		ei_lba = 0;
3094c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3095c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3096c2248fc9SDouglas Gilbert 		check_prot = true;
3097c2248fc9SDouglas Gilbert 		break;
3098c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3099c2248fc9SDouglas Gilbert 		ei_lba = 0;
3100c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3101c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3102c2248fc9SDouglas Gilbert 		check_prot = false;
3103c2248fc9SDouglas Gilbert 		break;
3104c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3105c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3106c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3107c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3108c2248fc9SDouglas Gilbert 		check_prot = false;
3109c2248fc9SDouglas Gilbert 		break;
3110c2248fc9SDouglas Gilbert 	}
3111f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
31128475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3113c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3114c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3115c2248fc9SDouglas Gilbert 			return check_condition_result;
3116c2248fc9SDouglas Gilbert 		}
31178475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31188475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3119c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3120c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3121c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3122c2248fc9SDouglas Gilbert 	}
31239447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, true);
31249447b6ceSMartin K. Petersen 	if (ret)
31259447b6ceSMartin K. Petersen 		return ret;
312667da413fSDouglas Gilbert 	write_lock(macc_lckp);
31276c78cc06SAkinobu Mita 
3128c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3129f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3130c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3131c6a44287SMartin K. Petersen 
3132c6a44287SMartin K. Petersen 		if (prot_ret) {
313367da413fSDouglas Gilbert 			write_unlock(macc_lckp);
3134c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3135c6a44287SMartin K. Petersen 			return illegal_condition_result;
3136c6a44287SMartin K. Petersen 		}
3137c6a44287SMartin K. Petersen 	}
3138c6a44287SMartin K. Petersen 
313987c715dcSDouglas Gilbert 	ret = do_device_access(sip, scp, 0, lba, num, true);
3140f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
314187c715dcSDouglas Gilbert 		map_region(sip, lba, num);
314267da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3143f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3144773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3145c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3146c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3147c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3148cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3149773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
315044d92694SMartin K. Petersen 
3151f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3152c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3153c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3154c2248fc9SDouglas Gilbert 
3155c4837394SDouglas Gilbert 		if (sqcp) {
3156c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3157c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3158c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3159c2248fc9SDouglas Gilbert 				return check_condition_result;
3160c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3161c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3162c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3163c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3164c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3165c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3166c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3167c2248fc9SDouglas Gilbert 			}
3168c2248fc9SDouglas Gilbert 		}
3169c4837394SDouglas Gilbert 	}
31701da177e4SLinus Torvalds 	return 0;
31711da177e4SLinus Torvalds }
31721da177e4SLinus Torvalds 
3173481b5e5cSDouglas Gilbert /*
3174481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3175481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3176481b5e5cSDouglas Gilbert  */
3177481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3178481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3179481b5e5cSDouglas Gilbert {
3180481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3181481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3182481b5e5cSDouglas Gilbert 	u8 *up;
318387c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
318487c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3185481b5e5cSDouglas Gilbert 	u8 wrprotect;
3186481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3187481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3188481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3189481b5e5cSDouglas Gilbert 	u32 ei_lba;
3190481b5e5cSDouglas Gilbert 	u64 lba;
3191481b5e5cSDouglas Gilbert 	int ret, res;
3192481b5e5cSDouglas Gilbert 	bool is_16;
3193481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3194481b5e5cSDouglas Gilbert 
3195481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3196481b5e5cSDouglas Gilbert 		is_16 = false;
3197481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3198481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3199481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3200481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3201481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3202481b5e5cSDouglas Gilbert 		is_16 = true;
3203481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3204481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3205481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3206481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3207481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3208481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3209481b5e5cSDouglas Gilbert 			    wrprotect) {
3210481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3211481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3212481b5e5cSDouglas Gilbert 			}
3213481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3214481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3215481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3216481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3217481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3218481b5e5cSDouglas Gilbert 		}
3219481b5e5cSDouglas Gilbert 	}
3220481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3221481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3222481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3223481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3224481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3225481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3226481b5e5cSDouglas Gilbert 				my_name, __func__);
3227481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3228481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3229481b5e5cSDouglas Gilbert 	}
3230481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3231481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3232481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3233481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3234481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3235481b5e5cSDouglas Gilbert 				my_name, __func__);
3236481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3237481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3238481b5e5cSDouglas Gilbert 	}
3239481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3240481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3241481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3242481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3243481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3244481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3245481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3246481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3247481b5e5cSDouglas Gilbert 	if (res == -1) {
3248481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3249481b5e5cSDouglas Gilbert 		goto err_out;
3250481b5e5cSDouglas Gilbert 	}
3251481b5e5cSDouglas Gilbert 
325267da413fSDouglas Gilbert 	write_lock(macc_lckp);
3253481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3254481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3255481b5e5cSDouglas Gilbert 	cum_lb = 0;
3256481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3257481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3258481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3259481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3260481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3261481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3262481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3263481b5e5cSDouglas Gilbert 		if (num == 0)
3264481b5e5cSDouglas Gilbert 			continue;
32659447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3266481b5e5cSDouglas Gilbert 		if (ret)
3267481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3268481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3269481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3270481b5e5cSDouglas Gilbert 
3271481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3272481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3273481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3274481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3275481b5e5cSDouglas Gilbert 				    my_name, __func__);
3276481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3277481b5e5cSDouglas Gilbert 					0);
3278481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3279481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3280481b5e5cSDouglas Gilbert 		}
3281481b5e5cSDouglas Gilbert 
3282481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3283481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3284481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3285481b5e5cSDouglas Gilbert 							 ei_lba);
3286481b5e5cSDouglas Gilbert 
3287481b5e5cSDouglas Gilbert 			if (prot_ret) {
3288481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3289481b5e5cSDouglas Gilbert 						prot_ret);
3290481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3291481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3292481b5e5cSDouglas Gilbert 			}
3293481b5e5cSDouglas Gilbert 		}
3294481b5e5cSDouglas Gilbert 
329587c715dcSDouglas Gilbert 		ret = do_device_access(sip, scp, sg_off, lba, num, true);
3296481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
329787c715dcSDouglas Gilbert 			map_region(sip, lba, num);
3298481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3299481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3300481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3301481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3302481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3303481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3304481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3305481b5e5cSDouglas Gilbert 
3306481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3307481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3308481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3309481b5e5cSDouglas Gilbert 
3310481b5e5cSDouglas Gilbert 			if (sqcp) {
3311481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3312481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3313481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3314481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3315481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3316481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3317481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3318481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3319481b5e5cSDouglas Gilbert 							0x10, 1);
3320481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3321481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3322481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3323481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3324481b5e5cSDouglas Gilbert 							0x10, 1);
3325481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3326481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3327481b5e5cSDouglas Gilbert 				}
3328481b5e5cSDouglas Gilbert 			}
3329481b5e5cSDouglas Gilbert 		}
3330481b5e5cSDouglas Gilbert 		sg_off += num_by;
3331481b5e5cSDouglas Gilbert 		cum_lb += num;
3332481b5e5cSDouglas Gilbert 	}
3333481b5e5cSDouglas Gilbert 	ret = 0;
3334481b5e5cSDouglas Gilbert err_out_unlock:
333567da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3336481b5e5cSDouglas Gilbert err_out:
3337481b5e5cSDouglas Gilbert 	kfree(lrdp);
3338481b5e5cSDouglas Gilbert 	return ret;
3339481b5e5cSDouglas Gilbert }
3340481b5e5cSDouglas Gilbert 
3341fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3342fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
334344d92694SMartin K. Petersen {
334444d92694SMartin K. Petersen 	unsigned long long i;
334540d07b52SDouglas Gilbert 	u64 block, lbaa;
334687c715dcSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
334787c715dcSDouglas Gilbert 	int ret;
334887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
334987c715dcSDouglas Gilbert 						scp->device->hostdata);
335087c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
335140d07b52SDouglas Gilbert 	u8 *fs1p;
335287c715dcSDouglas Gilbert 	u8 *fsp;
335344d92694SMartin K. Petersen 
33549447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, true);
335544d92694SMartin K. Petersen 	if (ret)
335644d92694SMartin K. Petersen 		return ret;
335744d92694SMartin K. Petersen 
335867da413fSDouglas Gilbert 	write_lock(macc_lckp);
335944d92694SMartin K. Petersen 
33609ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
336187c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
336244d92694SMartin K. Petersen 		goto out;
336344d92694SMartin K. Petersen 	}
336440d07b52SDouglas Gilbert 	lbaa = lba;
336540d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3366c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
336787c715dcSDouglas Gilbert 	fsp = sip->storep;
336887c715dcSDouglas Gilbert 	fs1p = fsp + (block * lb_size);
3369c2248fc9SDouglas Gilbert 	if (ndob) {
337040d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3371c2248fc9SDouglas Gilbert 		ret = 0;
3372c2248fc9SDouglas Gilbert 	} else
337340d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
337444d92694SMartin K. Petersen 
337544d92694SMartin K. Petersen 	if (-1 == ret) {
337667da413fSDouglas Gilbert 		write_unlock(&sip->macc_lck);
3377773642d9SDouglas Gilbert 		return DID_ERROR << 16;
337840d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3379c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3380e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
338140d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
338244d92694SMartin K. Petersen 
338344d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
338440d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
338540d07b52SDouglas Gilbert 		lbaa = lba + i;
338640d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
338787c715dcSDouglas Gilbert 		memmove(fsp + (block * lb_size), fs1p, lb_size);
338840d07b52SDouglas Gilbert 	}
33899ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
339087c715dcSDouglas Gilbert 		map_region(sip, lba, num);
339144d92694SMartin K. Petersen out:
339267da413fSDouglas Gilbert 	write_unlock(macc_lckp);
339344d92694SMartin K. Petersen 
339444d92694SMartin K. Petersen 	return 0;
339544d92694SMartin K. Petersen }
339644d92694SMartin K. Petersen 
3397fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3398fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3399c2248fc9SDouglas Gilbert {
3400c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3401c2248fc9SDouglas Gilbert 	u32 lba;
3402c2248fc9SDouglas Gilbert 	u16 num;
3403c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3404c2248fc9SDouglas Gilbert 	bool unmap = false;
3405c2248fc9SDouglas Gilbert 
3406c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3407773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3408c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3409c2248fc9SDouglas Gilbert 			return check_condition_result;
3410c2248fc9SDouglas Gilbert 		} else
3411c2248fc9SDouglas Gilbert 			unmap = true;
3412c2248fc9SDouglas Gilbert 	}
3413c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3414c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3415773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3416c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3417c2248fc9SDouglas Gilbert 		return check_condition_result;
3418c2248fc9SDouglas Gilbert 	}
3419c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3420c2248fc9SDouglas Gilbert }
3421c2248fc9SDouglas Gilbert 
3422fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3423fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3424c2248fc9SDouglas Gilbert {
3425c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3426c2248fc9SDouglas Gilbert 	u64 lba;
3427c2248fc9SDouglas Gilbert 	u32 num;
3428c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3429c2248fc9SDouglas Gilbert 	bool unmap = false;
3430c2248fc9SDouglas Gilbert 	bool ndob = false;
3431c2248fc9SDouglas Gilbert 
3432c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3433773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3434c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3435c2248fc9SDouglas Gilbert 			return check_condition_result;
3436c2248fc9SDouglas Gilbert 		} else
3437c2248fc9SDouglas Gilbert 			unmap = true;
3438c2248fc9SDouglas Gilbert 	}
3439c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3440c2248fc9SDouglas Gilbert 		ndob = true;
3441c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3442c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3443773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3444c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3445c2248fc9SDouglas Gilbert 		return check_condition_result;
3446c2248fc9SDouglas Gilbert 	}
3447c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3448c2248fc9SDouglas Gilbert }
3449c2248fc9SDouglas Gilbert 
3450acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3451acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3452acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3453fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3454fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3455acafd0b9SEwan D. Milne {
3456acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3457acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3458acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3459acafd0b9SEwan D. Milne 	u8 mode;
3460acafd0b9SEwan D. Milne 
3461acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3462acafd0b9SEwan D. Milne 	switch (mode) {
3463acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3464acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3465acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3466acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3467acafd0b9SEwan D. Milne 		break;
3468acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3469acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3470acafd0b9SEwan D. Milne 		break;
3471acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3472acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3473acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3474acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3475acafd0b9SEwan D. Milne 				    dev_list)
3476acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3477acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3478acafd0b9SEwan D. Milne 				if (devip != dp)
3479acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3480acafd0b9SEwan D. Milne 						dp->uas_bm);
3481acafd0b9SEwan D. Milne 			}
3482acafd0b9SEwan D. Milne 		break;
3483acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3484acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3485acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3486acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3487acafd0b9SEwan D. Milne 				    dev_list)
3488acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3489acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3490acafd0b9SEwan D. Milne 					dp->uas_bm);
3491acafd0b9SEwan D. Milne 		break;
3492acafd0b9SEwan D. Milne 	default:
3493acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3494acafd0b9SEwan D. Milne 		break;
3495acafd0b9SEwan D. Milne 	}
3496acafd0b9SEwan D. Milne 	return 0;
3497acafd0b9SEwan D. Milne }
3498acafd0b9SEwan D. Milne 
3499fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3500fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
350138d5c833SDouglas Gilbert {
350238d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
350338d5c833SDouglas Gilbert 	u8 *arr;
350487c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
350587c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
350638d5c833SDouglas Gilbert 	u64 lba;
350738d5c833SDouglas Gilbert 	u32 dnum;
3508773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
350938d5c833SDouglas Gilbert 	u8 num;
351038d5c833SDouglas Gilbert 	int ret;
3511d467d31fSDouglas Gilbert 	int retval = 0;
351238d5c833SDouglas Gilbert 
3513d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
351438d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
351538d5c833SDouglas Gilbert 	if (0 == num)
351638d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
35178475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
351838d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
351938d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
352038d5c833SDouglas Gilbert 		return check_condition_result;
352138d5c833SDouglas Gilbert 	}
35228475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
35238475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
352438d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
352538d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
352638d5c833SDouglas Gilbert 			    "to DIF device\n");
35279447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
35289447b6ceSMartin K. Petersen 	if (ret)
35299447b6ceSMartin K. Petersen 		return ret;
3530d467d31fSDouglas Gilbert 	dnum = 2 * num;
35316396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3532d467d31fSDouglas Gilbert 	if (NULL == arr) {
3533d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3534d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3535d467d31fSDouglas Gilbert 		return check_condition_result;
3536d467d31fSDouglas Gilbert 	}
353738d5c833SDouglas Gilbert 
353867da413fSDouglas Gilbert 	write_lock(macc_lckp);
353938d5c833SDouglas Gilbert 
354087c715dcSDouglas Gilbert 	ret = do_dout_fetch(scp, dnum, arr);
354138d5c833SDouglas Gilbert 	if (ret == -1) {
3542d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3543d467d31fSDouglas Gilbert 		goto cleanup;
3544773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
354538d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
354638d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
354738d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
3548c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, num, arr, false)) {
354938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3550d467d31fSDouglas Gilbert 		retval = check_condition_result;
3551d467d31fSDouglas Gilbert 		goto cleanup;
355238d5c833SDouglas Gilbert 	}
355338d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
355487c715dcSDouglas Gilbert 		map_region(sip, lba, num);
3555d467d31fSDouglas Gilbert cleanup:
355667da413fSDouglas Gilbert 	write_unlock(macc_lckp);
3557d467d31fSDouglas Gilbert 	kfree(arr);
3558d467d31fSDouglas Gilbert 	return retval;
355938d5c833SDouglas Gilbert }
356038d5c833SDouglas Gilbert 
356144d92694SMartin K. Petersen struct unmap_block_desc {
356244d92694SMartin K. Petersen 	__be64	lba;
356344d92694SMartin K. Petersen 	__be32	blocks;
356444d92694SMartin K. Petersen 	__be32	__reserved;
356544d92694SMartin K. Petersen };
356644d92694SMartin K. Petersen 
3567fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
356844d92694SMartin K. Petersen {
356944d92694SMartin K. Petersen 	unsigned char *buf;
357044d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
357187c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
357287c715dcSDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
357344d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
357444d92694SMartin K. Petersen 	int ret;
357544d92694SMartin K. Petersen 
3576c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3577c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3578c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3579c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
358044d92694SMartin K. Petersen 
358144d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3582773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3583c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
358444d92694SMartin K. Petersen 		return check_condition_result;
3585c2248fc9SDouglas Gilbert 	}
358644d92694SMartin K. Petersen 
3587b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3588c2248fc9SDouglas Gilbert 	if (!buf) {
3589c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3590c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3591c2248fc9SDouglas Gilbert 		return check_condition_result;
3592c2248fc9SDouglas Gilbert 	}
3593c2248fc9SDouglas Gilbert 
3594c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
359544d92694SMartin K. Petersen 
359644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
359744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
359844d92694SMartin K. Petersen 
359944d92694SMartin K. Petersen 	desc = (void *)&buf[8];
360044d92694SMartin K. Petersen 
360167da413fSDouglas Gilbert 	write_lock(macc_lckp);
36026c78cc06SAkinobu Mita 
360344d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
360444d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
360544d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
360644d92694SMartin K. Petersen 
36079447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
360844d92694SMartin K. Petersen 		if (ret)
360944d92694SMartin K. Petersen 			goto out;
361044d92694SMartin K. Petersen 
361187c715dcSDouglas Gilbert 		unmap_region(sip, lba, num);
361244d92694SMartin K. Petersen 	}
361344d92694SMartin K. Petersen 
361444d92694SMartin K. Petersen 	ret = 0;
361544d92694SMartin K. Petersen 
361644d92694SMartin K. Petersen out:
361767da413fSDouglas Gilbert 	write_unlock(macc_lckp);
361844d92694SMartin K. Petersen 	kfree(buf);
361944d92694SMartin K. Petersen 
362044d92694SMartin K. Petersen 	return ret;
362144d92694SMartin K. Petersen }
362244d92694SMartin K. Petersen 
362344d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
362444d92694SMartin K. Petersen 
3625fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3626fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
362744d92694SMartin K. Petersen {
3628c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
362987c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
3630c2248fc9SDouglas Gilbert 	u64 lba;
3631c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
363244d92694SMartin K. Petersen 	int ret;
363387c715dcSDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
363444d92694SMartin K. Petersen 
3635c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3636c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
363744d92694SMartin K. Petersen 
363844d92694SMartin K. Petersen 	if (alloc_len < 24)
363944d92694SMartin K. Petersen 		return 0;
364044d92694SMartin K. Petersen 
36419447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
364244d92694SMartin K. Petersen 	if (ret)
364344d92694SMartin K. Petersen 		return ret;
364444d92694SMartin K. Petersen 
3645c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
364687c715dcSDouglas Gilbert 		mapped = map_state(sip, lba, &num);
3647c2248fc9SDouglas Gilbert 	else {
3648c2248fc9SDouglas Gilbert 		mapped = 1;
3649c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3650c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3651c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3652c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3653c2248fc9SDouglas Gilbert 		else
3654c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3655c2248fc9SDouglas Gilbert 	}
365644d92694SMartin K. Petersen 
365744d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3658c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3659c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3660c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3661c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
366244d92694SMartin K. Petersen 
3663c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
366444d92694SMartin K. Petersen }
366544d92694SMartin K. Petersen 
366680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
366780c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
366880c49563SDouglas Gilbert {
36694f2c8bf6SDouglas Gilbert 	int res = 0;
367080c49563SDouglas Gilbert 	u64 lba;
367180c49563SDouglas Gilbert 	u32 num_blocks;
367280c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
367380c49563SDouglas Gilbert 
367480c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
367580c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
367680c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
367780c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
367880c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
367980c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
368080c49563SDouglas Gilbert 	}
368180c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
368280c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
368380c49563SDouglas Gilbert 		return check_condition_result;
368480c49563SDouglas Gilbert 	}
36854f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
36864f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
36874f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
36884f2c8bf6SDouglas Gilbert 		write_since_sync = false;
36894f2c8bf6SDouglas Gilbert 	return res;
369080c49563SDouglas Gilbert }
369180c49563SDouglas Gilbert 
3692ed9f3e25SDouglas Gilbert /*
3693ed9f3e25SDouglas Gilbert  * Assuming the LBA+num_blocks is not out-of-range, this function will return
3694ed9f3e25SDouglas Gilbert  * CONDITION MET if the specified blocks will/have fitted in the cache, and
3695ed9f3e25SDouglas Gilbert  * a GOOD status otherwise. Model a disk with a big cache and yield
3696ed9f3e25SDouglas Gilbert  * CONDITION MET. Actually tries to bring range in main memory into the
3697ed9f3e25SDouglas Gilbert  * cache associated with the CPU(s).
3698ed9f3e25SDouglas Gilbert  */
3699ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp,
3700ed9f3e25SDouglas Gilbert 			  struct sdebug_dev_info *devip)
3701ed9f3e25SDouglas Gilbert {
3702ed9f3e25SDouglas Gilbert 	int res = 0;
3703ed9f3e25SDouglas Gilbert 	u64 lba;
3704ed9f3e25SDouglas Gilbert 	u64 block, rest = 0;
3705ed9f3e25SDouglas Gilbert 	u32 nblks;
3706ed9f3e25SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3707ed9f3e25SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
3708ed9f3e25SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3709ed9f3e25SDouglas Gilbert 	u8 *fsp = sip ? sip->storep : NULL;
3710ed9f3e25SDouglas Gilbert 
3711ed9f3e25SDouglas Gilbert 	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
3712ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3713ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be16(cmd + 7);
3714ed9f3e25SDouglas Gilbert 	} else {			/* PRE-FETCH(16) */
3715ed9f3e25SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3716ed9f3e25SDouglas Gilbert 		nblks = get_unaligned_be32(cmd + 10);
3717ed9f3e25SDouglas Gilbert 	}
3718ed9f3e25SDouglas Gilbert 	if (lba + nblks > sdebug_capacity) {
3719ed9f3e25SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3720ed9f3e25SDouglas Gilbert 		return check_condition_result;
3721ed9f3e25SDouglas Gilbert 	}
3722ed9f3e25SDouglas Gilbert 	if (!fsp)
3723ed9f3e25SDouglas Gilbert 		goto fini;
3724ed9f3e25SDouglas Gilbert 	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
3725ed9f3e25SDouglas Gilbert 	block = do_div(lba, sdebug_store_sectors);
3726ed9f3e25SDouglas Gilbert 	if (block + nblks > sdebug_store_sectors)
3727ed9f3e25SDouglas Gilbert 		rest = block + nblks - sdebug_store_sectors;
3728ed9f3e25SDouglas Gilbert 
3729ed9f3e25SDouglas Gilbert 	/* Try to bring the PRE-FETCH range into CPU's cache */
3730ed9f3e25SDouglas Gilbert 	read_lock(macc_lckp);
3731ed9f3e25SDouglas Gilbert 	prefetch_range(fsp + (sdebug_sector_size * block),
3732ed9f3e25SDouglas Gilbert 		       (nblks - rest) * sdebug_sector_size);
3733ed9f3e25SDouglas Gilbert 	if (rest)
3734ed9f3e25SDouglas Gilbert 		prefetch_range(fsp, rest * sdebug_sector_size);
3735ed9f3e25SDouglas Gilbert 	read_unlock(macc_lckp);
3736ed9f3e25SDouglas Gilbert fini:
3737ed9f3e25SDouglas Gilbert 	if (cmd[1] & 0x2)
3738ed9f3e25SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
3739ed9f3e25SDouglas Gilbert 	return res | condition_met_result;
3740ed9f3e25SDouglas Gilbert }
3741ed9f3e25SDouglas Gilbert 
3742fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3743fb0cc8d1SDouglas Gilbert 
37448d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
37458d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
37468d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
37478d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
37488d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
37498d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
37508d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
37518d039e22SDouglas Gilbert  */
37521da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
37531da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
37541da177e4SLinus Torvalds {
375501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
37568d039e22SDouglas Gilbert 	unsigned int alloc_len;
37578d039e22SDouglas Gilbert 	unsigned char select_report;
37588d039e22SDouglas Gilbert 	u64 lun;
37598d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3760fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
37618d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
37628d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
37638d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
37648d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3765fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3766fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3767fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
37681da177e4SLinus Torvalds 
376919c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
37708d039e22SDouglas Gilbert 
37718d039e22SDouglas Gilbert 	select_report = cmd[2];
37728d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
37738d039e22SDouglas Gilbert 
37748d039e22SDouglas Gilbert 	if (alloc_len < 4) {
37758d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
37768d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
37771da177e4SLinus Torvalds 		return check_condition_result;
37781da177e4SLinus Torvalds 	}
37798d039e22SDouglas Gilbert 
37808d039e22SDouglas Gilbert 	switch (select_report) {
37818d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3782773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
37838d039e22SDouglas Gilbert 		wlun_cnt = 0;
37848d039e22SDouglas Gilbert 		break;
37858d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3786c65b1445SDouglas Gilbert 		lun_cnt = 0;
37878d039e22SDouglas Gilbert 		wlun_cnt = 1;
37888d039e22SDouglas Gilbert 		break;
37898d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
37908d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
37918d039e22SDouglas Gilbert 		wlun_cnt = 1;
37928d039e22SDouglas Gilbert 		break;
37938d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
37948d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
37958d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
37968d039e22SDouglas Gilbert 	default:
37978d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
37988d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
37998d039e22SDouglas Gilbert 		return check_condition_result;
38008d039e22SDouglas Gilbert 	}
38018d039e22SDouglas Gilbert 
38028d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3803c65b1445SDouglas Gilbert 		--lun_cnt;
38048d039e22SDouglas Gilbert 
38058d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3806fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3807fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
38088d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
38098d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
38108d039e22SDouglas Gilbert 
3811fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
38128d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3813fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3814fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3815fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3816fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3817fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3818fb0cc8d1SDouglas Gilbert 			++lun_p;
3819fb0cc8d1SDouglas Gilbert 			j = 1;
3820fb0cc8d1SDouglas Gilbert 		}
3821fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3822fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3823fb0cc8d1SDouglas Gilbert 				break;
3824fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3825fb0cc8d1SDouglas Gilbert 		}
3826fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3827fb0cc8d1SDouglas Gilbert 			break;
3828fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3829fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3830fb0cc8d1SDouglas Gilbert 		if (res)
3831fb0cc8d1SDouglas Gilbert 			return res;
3832fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3833fb0cc8d1SDouglas Gilbert 	}
3834fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3835fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3836fb0cc8d1SDouglas Gilbert 		++j;
3837fb0cc8d1SDouglas Gilbert 	}
3838fb0cc8d1SDouglas Gilbert 	if (j > 0)
3839fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
38408d039e22SDouglas Gilbert 	return res;
38411da177e4SLinus Torvalds }
38421da177e4SLinus Torvalds 
3843c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3844c3e2fe92SDouglas Gilbert {
3845c3e2fe92SDouglas Gilbert 	bool is_bytchk3 = false;
3846c3e2fe92SDouglas Gilbert 	u8 bytchk;
3847c3e2fe92SDouglas Gilbert 	int ret, j;
3848c3e2fe92SDouglas Gilbert 	u32 vnum, a_num, off;
3849c3e2fe92SDouglas Gilbert 	const u32 lb_size = sdebug_sector_size;
3850c3e2fe92SDouglas Gilbert 	u64 lba;
3851c3e2fe92SDouglas Gilbert 	u8 *arr;
3852c3e2fe92SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3853c3e2fe92SDouglas Gilbert 	struct sdeb_store_info *sip = devip2sip(devip);
3854c3e2fe92SDouglas Gilbert 	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3855c3e2fe92SDouglas Gilbert 
3856c3e2fe92SDouglas Gilbert 	bytchk = (cmd[1] >> 1) & 0x3;
3857c3e2fe92SDouglas Gilbert 	if (bytchk == 0) {
3858c3e2fe92SDouglas Gilbert 		return 0;	/* always claim internal verify okay */
3859c3e2fe92SDouglas Gilbert 	} else if (bytchk == 2) {
3860c3e2fe92SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
3861c3e2fe92SDouglas Gilbert 		return check_condition_result;
3862c3e2fe92SDouglas Gilbert 	} else if (bytchk == 3) {
3863c3e2fe92SDouglas Gilbert 		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
3864c3e2fe92SDouglas Gilbert 	}
3865c3e2fe92SDouglas Gilbert 	switch (cmd[0]) {
3866c3e2fe92SDouglas Gilbert 	case VERIFY_16:
3867c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
3868c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be32(cmd + 10);
3869c3e2fe92SDouglas Gilbert 		break;
3870c3e2fe92SDouglas Gilbert 	case VERIFY:		/* is VERIFY(10) */
3871c3e2fe92SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3872c3e2fe92SDouglas Gilbert 		vnum = get_unaligned_be16(cmd + 7);
3873c3e2fe92SDouglas Gilbert 		break;
3874c3e2fe92SDouglas Gilbert 	default:
3875c3e2fe92SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
3876c3e2fe92SDouglas Gilbert 		return check_condition_result;
3877c3e2fe92SDouglas Gilbert 	}
3878c3e2fe92SDouglas Gilbert 	a_num = is_bytchk3 ? 1 : vnum;
3879c3e2fe92SDouglas Gilbert 	/* Treat following check like one for read (i.e. no write) access */
3880c3e2fe92SDouglas Gilbert 	ret = check_device_access_params(scp, lba, a_num, false);
3881c3e2fe92SDouglas Gilbert 	if (ret)
3882c3e2fe92SDouglas Gilbert 		return ret;
3883c3e2fe92SDouglas Gilbert 
3884c3e2fe92SDouglas Gilbert 	arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
3885c3e2fe92SDouglas Gilbert 	if (!arr) {
3886c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3887c3e2fe92SDouglas Gilbert 				INSUFF_RES_ASCQ);
3888c3e2fe92SDouglas Gilbert 		return check_condition_result;
3889c3e2fe92SDouglas Gilbert 	}
3890c3e2fe92SDouglas Gilbert 	/* Not changing store, so only need read access */
389167da413fSDouglas Gilbert 	read_lock(macc_lckp);
3892c3e2fe92SDouglas Gilbert 
3893c3e2fe92SDouglas Gilbert 	ret = do_dout_fetch(scp, a_num, arr);
3894c3e2fe92SDouglas Gilbert 	if (ret == -1) {
3895c3e2fe92SDouglas Gilbert 		ret = DID_ERROR << 16;
3896c3e2fe92SDouglas Gilbert 		goto cleanup;
3897c3e2fe92SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
3898c3e2fe92SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3899c3e2fe92SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
3900c3e2fe92SDouglas Gilbert 			    my_name, __func__, a_num * lb_size, ret);
3901c3e2fe92SDouglas Gilbert 	}
3902c3e2fe92SDouglas Gilbert 	if (is_bytchk3) {
3903c3e2fe92SDouglas Gilbert 		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
3904c3e2fe92SDouglas Gilbert 			memcpy(arr + off, arr, lb_size);
3905c3e2fe92SDouglas Gilbert 	}
3906c3e2fe92SDouglas Gilbert 	ret = 0;
3907c3e2fe92SDouglas Gilbert 	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
3908c3e2fe92SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3909c3e2fe92SDouglas Gilbert 		ret = check_condition_result;
3910c3e2fe92SDouglas Gilbert 		goto cleanup;
3911c3e2fe92SDouglas Gilbert 	}
3912c3e2fe92SDouglas Gilbert cleanup:
391367da413fSDouglas Gilbert 	read_unlock(macc_lckp);
3914c3e2fe92SDouglas Gilbert 	kfree(arr);
3915c3e2fe92SDouglas Gilbert 	return ret;
3916c3e2fe92SDouglas Gilbert }
3917c3e2fe92SDouglas Gilbert 
3918c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3919c4837394SDouglas Gilbert {
3920c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
3921c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3922c4837394SDouglas Gilbert 
3923458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3924458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
3925458df78bSBart Van Assche 		hwq = 0;
3926458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
3927c4837394SDouglas Gilbert }
3928c4837394SDouglas Gilbert 
3929c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3930fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
39311da177e4SLinus Torvalds {
39327382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
3933c4837394SDouglas Gilbert 	int qc_idx;
3934cbf67842SDouglas Gilbert 	int retiring = 0;
39351da177e4SLinus Torvalds 	unsigned long iflags;
3936c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3937cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3938cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3939cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
39401da177e4SLinus Torvalds 
394110bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
39427382f9d8SDouglas Gilbert 	if (unlikely(aborted))
39437382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
3944c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3945c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3946c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3947cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3948c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3949c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3950c4837394SDouglas Gilbert 	}
3951c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3952c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
39531da177e4SLinus Torvalds 		return;
39541da177e4SLinus Torvalds 	}
3955c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3956c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3957cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3958b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3959c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3960c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3961c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
39621da177e4SLinus Torvalds 		return;
39631da177e4SLinus Torvalds 	}
3964cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3965f46eb0e9SDouglas Gilbert 	if (likely(devip))
3966cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3967cbf67842SDouglas Gilbert 	else
3968c1287970STomas Winkler 		pr_err("devip=NULL\n");
3969f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3970cbf67842SDouglas Gilbert 		retiring = 1;
3971cbf67842SDouglas Gilbert 
3972cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3973c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3974c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3975c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3976cbf67842SDouglas Gilbert 		return;
39771da177e4SLinus Torvalds 	}
39781da177e4SLinus Torvalds 
3979cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3980cbf67842SDouglas Gilbert 		int k, retval;
3981cbf67842SDouglas Gilbert 
3982cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3983c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3984c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3985c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3986cbf67842SDouglas Gilbert 			return;
3987cbf67842SDouglas Gilbert 		}
3988c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3989773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3990cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3991cbf67842SDouglas Gilbert 		else
3992cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3993cbf67842SDouglas Gilbert 	}
3994c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
39957382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
39967382f9d8SDouglas Gilbert 		if (sdebug_verbose)
39977382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
39987382f9d8SDouglas Gilbert 		return;
39997382f9d8SDouglas Gilbert 	}
4000cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
4001cbf67842SDouglas Gilbert }
4002cbf67842SDouglas Gilbert 
4003cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
4004fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
4005cbf67842SDouglas Gilbert {
4006a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4007a10bc12aSDouglas Gilbert 						  hrt);
4008a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4009cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
4010cbf67842SDouglas Gilbert }
40111da177e4SLinus Torvalds 
4012a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
4013fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
4014a10bc12aSDouglas Gilbert {
4015a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4016a10bc12aSDouglas Gilbert 						  ew.work);
4017a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
4018a10bc12aSDouglas Gilbert }
4019a10bc12aSDouglas Gilbert 
402009ba24c1SDouglas Gilbert static bool got_shared_uuid;
4021bf476433SChristoph Hellwig static uuid_t shared_uuid;
402209ba24c1SDouglas Gilbert 
4023fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
4024fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
40255cb2fc06SFUJITA Tomonori {
40265cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
40275cb2fc06SFUJITA Tomonori 
40285cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
40295cb2fc06SFUJITA Tomonori 	if (devip) {
403009ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
4031bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
403209ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
403309ba24c1SDouglas Gilbert 			if (got_shared_uuid)
403409ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
403509ba24c1SDouglas Gilbert 			else {
4036bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
403709ba24c1SDouglas Gilbert 				got_shared_uuid = true;
403809ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
403909ba24c1SDouglas Gilbert 			}
404009ba24c1SDouglas Gilbert 		}
40415cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
40425cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
40435cb2fc06SFUJITA Tomonori 	}
40445cb2fc06SFUJITA Tomonori 	return devip;
40455cb2fc06SFUJITA Tomonori }
40465cb2fc06SFUJITA Tomonori 
4047f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
40481da177e4SLinus Torvalds {
40491da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
40501da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
4051f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
40521da177e4SLinus Torvalds 
4053d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
40541da177e4SLinus Torvalds 	if (!sdbg_host) {
4055c1287970STomas Winkler 		pr_err("Host info NULL\n");
40561da177e4SLinus Torvalds 		return NULL;
40571da177e4SLinus Torvalds 	}
40581da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
40591da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
40601da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
40611da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
40621da177e4SLinus Torvalds 			return devip;
40631da177e4SLinus Torvalds 		else {
40641da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
40651da177e4SLinus Torvalds 				open_devip = devip;
40661da177e4SLinus Torvalds 		}
40671da177e4SLinus Torvalds 	}
40685cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
40695cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
40705cb2fc06SFUJITA Tomonori 		if (!open_devip) {
4071c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
40721da177e4SLinus Torvalds 			return NULL;
40731da177e4SLinus Torvalds 		}
40741da177e4SLinus Torvalds 	}
4075a75869d1SFUJITA Tomonori 
40761da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
40771da177e4SLinus Torvalds 	open_devip->target = sdev->id;
40781da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
40791da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
4080cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
4081cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
4082c2248fc9SDouglas Gilbert 	open_devip->used = true;
40831da177e4SLinus Torvalds 	return open_devip;
40841da177e4SLinus Torvalds }
40851da177e4SLinus Torvalds 
40868dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
40871da177e4SLinus Torvalds {
4088773642d9SDouglas Gilbert 	if (sdebug_verbose)
4089c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
40908dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
40918dea0d02SFUJITA Tomonori 	return 0;
40928dea0d02SFUJITA Tomonori }
40931da177e4SLinus Torvalds 
40948dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
40958dea0d02SFUJITA Tomonori {
4096f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
4097f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
4098a34c4e98SFUJITA Tomonori 
4099773642d9SDouglas Gilbert 	if (sdebug_verbose)
4100c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
41018dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
4102b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4103b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4104b01f6f83SDouglas Gilbert 	if (devip == NULL) {
4105f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
4106b01f6f83SDouglas Gilbert 		if (devip == NULL)
41078dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
4108f46eb0e9SDouglas Gilbert 	}
4109c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
4110773642d9SDouglas Gilbert 	if (sdebug_no_uld)
411178d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
41129b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
41138dea0d02SFUJITA Tomonori 	return 0;
41148dea0d02SFUJITA Tomonori }
41158dea0d02SFUJITA Tomonori 
41168dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
41178dea0d02SFUJITA Tomonori {
41188dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
41198dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
41208dea0d02SFUJITA Tomonori 
4121773642d9SDouglas Gilbert 	if (sdebug_verbose)
4122c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
41238dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
41248dea0d02SFUJITA Tomonori 	if (devip) {
412525985edcSLucas De Marchi 		/* make this slot available for re-use */
4126c2248fc9SDouglas Gilbert 		devip->used = false;
41278dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
41288dea0d02SFUJITA Tomonori 	}
41298dea0d02SFUJITA Tomonori }
41308dea0d02SFUJITA Tomonori 
413110bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
413210bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
4133c4837394SDouglas Gilbert {
4134c4837394SDouglas Gilbert 	if (!sd_dp)
4135c4837394SDouglas Gilbert 		return;
413610bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
4137c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
413810bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
4139c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
4140c4837394SDouglas Gilbert }
4141c4837394SDouglas Gilbert 
4142a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
4143a10bc12aSDouglas Gilbert    returns false */
4144a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
41458dea0d02SFUJITA Tomonori {
41468dea0d02SFUJITA Tomonori 	unsigned long iflags;
4147c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
414810bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4149c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
41508dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4151cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4152a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
41538dea0d02SFUJITA Tomonori 
4154c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4155c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4156773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
4157cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
4158cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
4159cbf67842SDouglas Gilbert 			qmax = r_qmax;
4160cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
4161c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4162c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4163a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
4164a10bc12aSDouglas Gilbert 					continue;
4165c4837394SDouglas Gilbert 				/* found */
4166db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4167db525fceSDouglas Gilbert 						cmnd->device->hostdata;
4168db525fceSDouglas Gilbert 				if (devip)
4169db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4170db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4171a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
417210bde980SDouglas Gilbert 				if (sd_dp) {
417310bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
417410bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
417510bde980SDouglas Gilbert 				} else
417610bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4177c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
417810bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4179c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4180a10bc12aSDouglas Gilbert 				return true;
41818dea0d02SFUJITA Tomonori 			}
4182cbf67842SDouglas Gilbert 		}
4183c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4184c4837394SDouglas Gilbert 	}
4185a10bc12aSDouglas Gilbert 	return false;
41868dea0d02SFUJITA Tomonori }
41878dea0d02SFUJITA Tomonori 
4188a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
41898dea0d02SFUJITA Tomonori static void stop_all_queued(void)
41908dea0d02SFUJITA Tomonori {
41918dea0d02SFUJITA Tomonori 	unsigned long iflags;
4192c4837394SDouglas Gilbert 	int j, k;
419310bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4194c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
41958dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4196cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4197a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
41988dea0d02SFUJITA Tomonori 
4199c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4200c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4201c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4202c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4203c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4204c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
4205a10bc12aSDouglas Gilbert 					continue;
4206db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4207db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
4208db525fceSDouglas Gilbert 				if (devip)
4209db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4210db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4211a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
421210bde980SDouglas Gilbert 				if (sd_dp) {
421310bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
421410bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
421510bde980SDouglas Gilbert 				} else
421610bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4217c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
421810bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4219c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4220c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
42218dea0d02SFUJITA Tomonori 			}
42228dea0d02SFUJITA Tomonori 		}
4223c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4224c4837394SDouglas Gilbert 	}
4225cbf67842SDouglas Gilbert }
4226cbf67842SDouglas Gilbert 
4227cbf67842SDouglas Gilbert /* Free queued command memory on heap */
4228cbf67842SDouglas Gilbert static void free_all_queued(void)
4229cbf67842SDouglas Gilbert {
4230c4837394SDouglas Gilbert 	int j, k;
4231c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4232cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4233cbf67842SDouglas Gilbert 
4234c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4235c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4236c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
4237a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
4238a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
4239cbf67842SDouglas Gilbert 		}
42401da177e4SLinus Torvalds 	}
4241c4837394SDouglas Gilbert }
42421da177e4SLinus Torvalds 
42431da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
42441da177e4SLinus Torvalds {
4245a10bc12aSDouglas Gilbert 	bool ok;
4246a10bc12aSDouglas Gilbert 
42471da177e4SLinus Torvalds 	++num_aborts;
4248cbf67842SDouglas Gilbert 	if (SCpnt) {
4249a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
4250a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4251a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4252a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
4253a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
4254cbf67842SDouglas Gilbert 	}
42551da177e4SLinus Torvalds 	return SUCCESS;
42561da177e4SLinus Torvalds }
42571da177e4SLinus Torvalds 
42581da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
42591da177e4SLinus Torvalds {
42601da177e4SLinus Torvalds 	++num_dev_resets;
4261cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
4262cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
4263f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
4264f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
4265cbf67842SDouglas Gilbert 
4266773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4267cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
42681da177e4SLinus Torvalds 		if (devip)
4269cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
42701da177e4SLinus Torvalds 	}
42711da177e4SLinus Torvalds 	return SUCCESS;
42721da177e4SLinus Torvalds }
42731da177e4SLinus Torvalds 
4274cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4275cbf67842SDouglas Gilbert {
4276cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
4277cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4278cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
4279cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
4280cbf67842SDouglas Gilbert 	int k = 0;
4281cbf67842SDouglas Gilbert 
4282cbf67842SDouglas Gilbert 	++num_target_resets;
4283cbf67842SDouglas Gilbert 	if (!SCpnt)
4284cbf67842SDouglas Gilbert 		goto lie;
4285cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4286cbf67842SDouglas Gilbert 	if (!sdp)
4287cbf67842SDouglas Gilbert 		goto lie;
4288773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4289cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4290cbf67842SDouglas Gilbert 	hp = sdp->host;
4291cbf67842SDouglas Gilbert 	if (!hp)
4292cbf67842SDouglas Gilbert 		goto lie;
4293cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4294cbf67842SDouglas Gilbert 	if (sdbg_host) {
4295cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
4296cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
4297cbf67842SDouglas Gilbert 				    dev_list)
4298cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
4299cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4300cbf67842SDouglas Gilbert 				++k;
4301cbf67842SDouglas Gilbert 			}
4302cbf67842SDouglas Gilbert 	}
4303773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4304cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4305cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
4306cbf67842SDouglas Gilbert lie:
4307cbf67842SDouglas Gilbert 	return SUCCESS;
4308cbf67842SDouglas Gilbert }
4309cbf67842SDouglas Gilbert 
43101da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
43111da177e4SLinus Torvalds {
43121da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4313cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
43141da177e4SLinus Torvalds 	struct scsi_device *sdp;
43151da177e4SLinus Torvalds 	struct Scsi_Host *hp;
4316cbf67842SDouglas Gilbert 	int k = 0;
43171da177e4SLinus Torvalds 
43181da177e4SLinus Torvalds 	++num_bus_resets;
4319cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
4320cbf67842SDouglas Gilbert 		goto lie;
4321cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4322773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4323cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4324cbf67842SDouglas Gilbert 	hp = sdp->host;
4325cbf67842SDouglas Gilbert 	if (hp) {
4326d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
43271da177e4SLinus Torvalds 		if (sdbg_host) {
4328cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
43291da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
4330cbf67842SDouglas Gilbert 					    dev_list) {
4331cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4332cbf67842SDouglas Gilbert 				++k;
43331da177e4SLinus Torvalds 			}
43341da177e4SLinus Torvalds 		}
4335cbf67842SDouglas Gilbert 	}
4336773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4337cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4338cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
4339cbf67842SDouglas Gilbert lie:
43401da177e4SLinus Torvalds 	return SUCCESS;
43411da177e4SLinus Torvalds }
43421da177e4SLinus Torvalds 
43431da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
43441da177e4SLinus Torvalds {
43451da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4346cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4347cbf67842SDouglas Gilbert 	int k = 0;
43481da177e4SLinus Torvalds 
43491da177e4SLinus Torvalds 	++num_host_resets;
4350773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4351cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
43521da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
43531da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
4354cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
4355cbf67842SDouglas Gilbert 				    dev_list) {
4356cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4357cbf67842SDouglas Gilbert 			++k;
4358cbf67842SDouglas Gilbert 		}
43591da177e4SLinus Torvalds 	}
43601da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
43611da177e4SLinus Torvalds 	stop_all_queued();
4362773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4363cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
4364cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
43651da177e4SLinus Torvalds 	return SUCCESS;
43661da177e4SLinus Torvalds }
43671da177e4SLinus Torvalds 
436887c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
43691da177e4SLinus Torvalds {
43701442f76dSChristoph Hellwig 	struct msdos_partition *pp;
43711da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
43721da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
43731da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
43741da177e4SLinus Torvalds 
43751da177e4SLinus Torvalds 	/* assume partition table already zeroed */
4376773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
43771da177e4SLinus Torvalds 		return;
4378773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4379773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
4380c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
43811da177e4SLinus Torvalds 	}
4382c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
43831da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4384773642d9SDouglas Gilbert 			   / sdebug_num_parts;
43851da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
43861da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4387773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
43881da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
43891da177e4SLinus Torvalds 			    * heads_by_sects;
4390773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4391773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
43921da177e4SLinus Torvalds 
43931da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
43941da177e4SLinus Torvalds 	ramp[511] = 0xAA;
43951442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
43961da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
43971da177e4SLinus Torvalds 		start_sec = starts[k];
43981da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
43991da177e4SLinus Torvalds 		pp->boot_ind = 0;
44001da177e4SLinus Torvalds 
44011da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
44021da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
44031da177e4SLinus Torvalds 			   / sdebug_sectors_per;
44041da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
44051da177e4SLinus Torvalds 
44061da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
44071da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
44081da177e4SLinus Torvalds 			       / sdebug_sectors_per;
44091da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
44101da177e4SLinus Torvalds 
4411150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4412150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
44131da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
44141da177e4SLinus Torvalds 	}
44151da177e4SLinus Torvalds }
44161da177e4SLinus Torvalds 
4417c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4418c4837394SDouglas Gilbert {
4419c4837394SDouglas Gilbert 	int j;
4420c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4421c4837394SDouglas Gilbert 
4422c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4423c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4424c4837394SDouglas Gilbert }
4425c4837394SDouglas Gilbert 
4426c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4427c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4428c4837394SDouglas Gilbert  */
4429c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4430c4837394SDouglas Gilbert {
4431c4837394SDouglas Gilbert 	int count, modulo;
4432c4837394SDouglas Gilbert 
4433c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4434c4837394SDouglas Gilbert 	if (modulo < 2)
4435c4837394SDouglas Gilbert 		return;
4436c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4437c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4438c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4439c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4440c4837394SDouglas Gilbert }
4441c4837394SDouglas Gilbert 
4442c4837394SDouglas Gilbert static void clear_queue_stats(void)
4443c4837394SDouglas Gilbert {
4444c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4445c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4446c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4447c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4448c4837394SDouglas Gilbert }
4449c4837394SDouglas Gilbert 
4450c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4451c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4452c4837394SDouglas Gilbert {
4453f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4454f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
4455f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
4456f9ba7af8SMartin Wilck 				= sqcp->inj_dif
44577382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
44587382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
4459c4837394SDouglas Gilbert 		return;
4460f9ba7af8SMartin Wilck 	}
4461c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4462c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4463c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4464c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4465c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
44667ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
44677382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
4468c4837394SDouglas Gilbert }
4469c4837394SDouglas Gilbert 
4470a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
4471a2aede97SDouglas Gilbert 
4472c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4473c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4474c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4475c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4476c4837394SDouglas Gilbert  */
4477fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4478f66b8517SMartin Wilck 			 int scsi_result,
4479f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
4480f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
4481f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
44821da177e4SLinus Torvalds {
4483a2aede97SDouglas Gilbert 	bool new_sd_dp;
4484cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4485a2aede97SDouglas Gilbert 	unsigned long iflags;
4486a2aede97SDouglas Gilbert 	u64 ns_from_boot = 0;
4487c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4488c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4489299b6c07STomas Winkler 	struct scsi_device *sdp;
4490a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
44911da177e4SLinus Torvalds 
4492b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4493b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4494f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4495f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
44961da177e4SLinus Torvalds 	}
4497299b6c07STomas Winkler 	sdp = cmnd->device;
4498299b6c07STomas Winkler 
4499cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4500cd62b7daSDouglas Gilbert 		goto respond_in_thread;
45011da177e4SLinus Torvalds 
4502c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4503c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4504c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4505c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4506c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4507c4837394SDouglas Gilbert 	}
4508cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4509cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4510cbf67842SDouglas Gilbert 	inject = 0;
4511f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4512cd62b7daSDouglas Gilbert 		if (scsi_result) {
4513c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4514cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4515cd62b7daSDouglas Gilbert 		} else
4516cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4517c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4518773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4519f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4520cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4521cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4522773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4523cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4524cbf67842SDouglas Gilbert 			inject = 1;
4525cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
45261da177e4SLinus Torvalds 		}
4527cbf67842SDouglas Gilbert 	}
4528cbf67842SDouglas Gilbert 
4529c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4530f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4531c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4532cd62b7daSDouglas Gilbert 		if (scsi_result)
4533cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4534773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4535cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4536773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4537cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4538cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4539773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4540cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4541cbf67842SDouglas Gilbert 						    "report: host busy"));
4542cd62b7daSDouglas Gilbert 		if (scsi_result)
4543cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4544cd62b7daSDouglas Gilbert 		else
4545cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
45461da177e4SLinus Torvalds 	}
4547c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4548cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4549c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
45501da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4551c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4552a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4553c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4554c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4555c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
455610bde980SDouglas Gilbert 	if (sd_dp == NULL) {
455710bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
455810bde980SDouglas Gilbert 		if (sd_dp == NULL)
455910bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
4560a2aede97SDouglas Gilbert 		new_sd_dp = true;
4561a2aede97SDouglas Gilbert 	} else {
4562a2aede97SDouglas Gilbert 		new_sd_dp = false;
456310bde980SDouglas Gilbert 	}
4564f66b8517SMartin Wilck 
4565a2aede97SDouglas Gilbert 	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
4566a2aede97SDouglas Gilbert 		ns_from_boot = ktime_get_boottime_ns();
4567a2aede97SDouglas Gilbert 
4568a2aede97SDouglas Gilbert 	/* one of the resp_*() response functions is called here */
4569f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4570f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
4571f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
4572f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
4573f66b8517SMartin Wilck 	}
4574f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4575f66b8517SMartin Wilck 		cmnd->result = scsi_result;
4576f66b8517SMartin Wilck 
4577f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
4578f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4579f66b8517SMartin Wilck 			    __func__, cmnd->result);
4580f66b8517SMartin Wilck 
458110bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
4582b333a819SDouglas Gilbert 		ktime_t kt;
4583cbf67842SDouglas Gilbert 
4584b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
45850c4bc91dSDouglas Gilbert 			u64 ns = jiffies_to_nsecs(delta_jiff);
45860c4bc91dSDouglas Gilbert 
45870c4bc91dSDouglas Gilbert 			if (sdebug_random && ns < U32_MAX) {
45880c4bc91dSDouglas Gilbert 				ns = prandom_u32_max((u32)ns);
45890c4bc91dSDouglas Gilbert 			} else if (sdebug_random) {
45900c4bc91dSDouglas Gilbert 				ns >>= 12;	/* scale to 4 usec precision */
45910c4bc91dSDouglas Gilbert 				if (ns < U32_MAX)	/* over 4 hours max */
45920c4bc91dSDouglas Gilbert 					ns = prandom_u32_max((u32)ns);
45930c4bc91dSDouglas Gilbert 				ns <<= 12;
45940c4bc91dSDouglas Gilbert 			}
45950c4bc91dSDouglas Gilbert 			kt = ns_to_ktime(ns);
45960c4bc91dSDouglas Gilbert 		} else {	/* ndelay has a 4.2 second max */
45970c4bc91dSDouglas Gilbert 			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
45980c4bc91dSDouglas Gilbert 					     (u32)ndelay;
4599a2aede97SDouglas Gilbert 			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
4600a2aede97SDouglas Gilbert 				u64 d = ktime_get_boottime_ns() - ns_from_boot;
4601a2aede97SDouglas Gilbert 
4602a2aede97SDouglas Gilbert 				if (kt <= d) {	/* elapsed duration >= kt */
4603a2aede97SDouglas Gilbert 					sqcp->a_cmnd = NULL;
4604a2aede97SDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4605a2aede97SDouglas Gilbert 					clear_bit(k, sqp->in_use_bm);
4606a2aede97SDouglas Gilbert 					if (new_sd_dp)
4607a2aede97SDouglas Gilbert 						kfree(sd_dp);
4608a2aede97SDouglas Gilbert 					/* call scsi_done() from this thread */
4609a2aede97SDouglas Gilbert 					cmnd->scsi_done(cmnd);
4610a2aede97SDouglas Gilbert 					return 0;
4611a2aede97SDouglas Gilbert 				}
4612a2aede97SDouglas Gilbert 				/* otherwise reduce kt by elapsed time */
4613a2aede97SDouglas Gilbert 				kt -= d;
4614a2aede97SDouglas Gilbert 			}
46150c4bc91dSDouglas Gilbert 		}
461610bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
461710bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
4618a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4619a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4620c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4621a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4622c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4623c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4624cbf67842SDouglas Gilbert 		}
4625c4837394SDouglas Gilbert 		if (sdebug_statistics)
4626c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
462710bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
4628a2aede97SDouglas Gilbert 		/* schedule the invocation of scsi_done() for a later time */
4629c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4630c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
463110bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
463210bde980SDouglas Gilbert 			sd_dp->init_wq = true;
4633a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4634c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4635c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4636a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4637cbf67842SDouglas Gilbert 		}
4638c4837394SDouglas Gilbert 		if (sdebug_statistics)
4639c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
464010bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
46417382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
46427382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
4643a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
46447382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
46457382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
46467382f9d8SDouglas Gilbert 				    cmnd->request->tag);
46477382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
46487382f9d8SDouglas Gilbert 		}
4649cbf67842SDouglas Gilbert 	}
4650f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4651f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4652cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4653cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4654cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4655cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
46561da177e4SLinus Torvalds 	return 0;
4657cd62b7daSDouglas Gilbert 
4658cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4659f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4660f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
4661f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4662cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
4663cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4664cd62b7daSDouglas Gilbert 	return 0;
46651da177e4SLinus Torvalds }
4666cbf67842SDouglas Gilbert 
466723183910SDouglas Gilbert /* Note: The following macros create attribute files in the
466823183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
466923183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
467023183910SDouglas Gilbert    as it can when the corresponding attribute in the
467123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
467223183910SDouglas Gilbert  */
4673773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4674773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
46759b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4676773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4677c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4678773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4679773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4680773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4681773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4682773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4683773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4684773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4685773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4686e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4687e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4688e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4689e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4690e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4691e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4692773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4693773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4694773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4695773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4696773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4697773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4698773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4699d9da891aSLaurence Oberman module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4700d9da891aSLaurence Oberman module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
4701773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4702773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4703773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4704773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4705773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4706773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4707773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
470887c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool,
470987c715dcSDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4710773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
471186e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4712773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
47130c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
4714773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4715773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4716773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4717c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4718773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4719c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4720773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4721773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4722773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4723773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4724773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
472509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4726773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
472723183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
47289447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
4729773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
47305b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
47311da177e4SLinus Torvalds 
47321da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
47331da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
47341da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4735b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
47361da177e4SLinus Torvalds 
47371da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
47385b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
47399b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
47400759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4741cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4742c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
47435b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
47445b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4745c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4746beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
474723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
47485b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4749185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4750e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4751e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
47529b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
47539b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
47545b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
47555b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
47565b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4757760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4758760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
47595b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4760c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4761cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4762d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4763d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
4764cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4765c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
476678d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
47671da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4768c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
476932c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
47706f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
477187c715dcSDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store");
47725b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
477386e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
47741da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
47750c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
4776d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4777760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4778ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4779c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4780c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4781c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
47825b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
47835b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
47846014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
47856014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
478609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
478709ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4788c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
47895b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
47909447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
47915b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
47921da177e4SLinus Torvalds 
4793760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4794760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
47951da177e4SLinus Torvalds 
47961da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
47971da177e4SLinus Torvalds {
4798c4837394SDouglas Gilbert 	int k;
4799c4837394SDouglas Gilbert 
4800760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4801760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4802760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4803c4837394SDouglas Gilbert 		return sdebug_info;
4804760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4805760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4806760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4807760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
48081da177e4SLinus Torvalds 	return sdebug_info;
48091da177e4SLinus Torvalds }
48101da177e4SLinus Torvalds 
4811cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4812fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4813fd32119bSDouglas Gilbert 				 int length)
48141da177e4SLinus Torvalds {
48151da177e4SLinus Torvalds 	char arr[16];
4816c8ed555aSAl Viro 	int opts;
48171da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
48181da177e4SLinus Torvalds 
48191da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
48201da177e4SLinus Torvalds 		return -EACCES;
48211da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
48221da177e4SLinus Torvalds 	arr[minLen] = '\0';
4823c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
48241da177e4SLinus Torvalds 		return -EINVAL;
4825773642d9SDouglas Gilbert 	sdebug_opts = opts;
4826773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4827773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4828773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4829c4837394SDouglas Gilbert 		tweak_cmnd_count();
48301da177e4SLinus Torvalds 	return length;
48311da177e4SLinus Torvalds }
4832c8ed555aSAl Viro 
4833cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4834cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4835cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4836c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4837c8ed555aSAl Viro {
4838c4837394SDouglas Gilbert 	int f, j, l;
4839c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
484087c715dcSDouglas Gilbert 	struct sdebug_host_info *sdhp;
4841cbf67842SDouglas Gilbert 
4842c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4843c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4844c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4845c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4846c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4847c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4848c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4849c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4850c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4851c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4852c4837394SDouglas Gilbert 		   num_aborts);
4853c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4854c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4855c4837394SDouglas Gilbert 		   num_host_resets);
4856c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4857c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4858458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4859458df78bSBart Van Assche 		   sdebug_statistics);
4860c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4861c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4862c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4863c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4864c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4865cbf67842SDouglas Gilbert 
4866c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4867c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4868c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4869c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4870773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4871c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4872c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4873c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4874c4837394SDouglas Gilbert 		}
4875cbf67842SDouglas Gilbert 	}
487687c715dcSDouglas Gilbert 
487787c715dcSDouglas Gilbert 	seq_printf(m, "this host_no=%d\n", host->host_no);
487887c715dcSDouglas Gilbert 	if (!xa_empty(per_store_ap)) {
487987c715dcSDouglas Gilbert 		bool niu;
488087c715dcSDouglas Gilbert 		int idx;
488187c715dcSDouglas Gilbert 		unsigned long l_idx;
488287c715dcSDouglas Gilbert 		struct sdeb_store_info *sip;
488387c715dcSDouglas Gilbert 
488487c715dcSDouglas Gilbert 		seq_puts(m, "\nhost list:\n");
488587c715dcSDouglas Gilbert 		j = 0;
488687c715dcSDouglas Gilbert 		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
488787c715dcSDouglas Gilbert 			idx = sdhp->si_idx;
488887c715dcSDouglas Gilbert 			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
488987c715dcSDouglas Gilbert 				   sdhp->shost->host_no, idx);
489087c715dcSDouglas Gilbert 			++j;
489187c715dcSDouglas Gilbert 		}
489287c715dcSDouglas Gilbert 		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
489387c715dcSDouglas Gilbert 			   sdeb_most_recent_idx);
489487c715dcSDouglas Gilbert 		j = 0;
489587c715dcSDouglas Gilbert 		xa_for_each(per_store_ap, l_idx, sip) {
489687c715dcSDouglas Gilbert 			niu = xa_get_mark(per_store_ap, l_idx,
489787c715dcSDouglas Gilbert 					  SDEB_XA_NOT_IN_USE);
489887c715dcSDouglas Gilbert 			idx = (int)l_idx;
489987c715dcSDouglas Gilbert 			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
490087c715dcSDouglas Gilbert 				   (niu ? "  not_in_use" : ""));
490187c715dcSDouglas Gilbert 			++j;
490287c715dcSDouglas Gilbert 		}
490387c715dcSDouglas Gilbert 	}
4904c8ed555aSAl Viro 	return 0;
49051da177e4SLinus Torvalds }
49061da177e4SLinus Torvalds 
490782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
49081da177e4SLinus Torvalds {
4909c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
49101da177e4SLinus Torvalds }
4911c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4912c4837394SDouglas Gilbert  * of delay is jiffies.
4913c4837394SDouglas Gilbert  */
491482069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
491582069379SAkinobu Mita 			   size_t count)
49161da177e4SLinus Torvalds {
4917c2206098SDouglas Gilbert 	int jdelay, res;
49181da177e4SLinus Torvalds 
4919b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4920cbf67842SDouglas Gilbert 		res = count;
4921c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4922c4837394SDouglas Gilbert 			int j, k;
4923c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4924cbf67842SDouglas Gilbert 
4925c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4926c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4927c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4928c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4929c4837394SDouglas Gilbert 						   sdebug_max_queue);
4930c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4931c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4932c4837394SDouglas Gilbert 					break;
4933c4837394SDouglas Gilbert 				}
4934c4837394SDouglas Gilbert 			}
4935c4837394SDouglas Gilbert 			if (res > 0) {
4936c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4937773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
49381da177e4SLinus Torvalds 			}
4939c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4940cbf67842SDouglas Gilbert 		}
4941cbf67842SDouglas Gilbert 		return res;
49421da177e4SLinus Torvalds 	}
49431da177e4SLinus Torvalds 	return -EINVAL;
49441da177e4SLinus Torvalds }
494582069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
49461da177e4SLinus Torvalds 
4947cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4948cbf67842SDouglas Gilbert {
4949773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4950cbf67842SDouglas Gilbert }
4951cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4952c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4953cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4954cbf67842SDouglas Gilbert 			    size_t count)
4955cbf67842SDouglas Gilbert {
4956c4837394SDouglas Gilbert 	int ndelay, res;
4957cbf67842SDouglas Gilbert 
4958cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4959c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4960cbf67842SDouglas Gilbert 		res = count;
4961773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4962c4837394SDouglas Gilbert 			int j, k;
4963c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4964c4837394SDouglas Gilbert 
4965c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4966c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4967c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4968c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4969c4837394SDouglas Gilbert 						   sdebug_max_queue);
4970c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4971c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4972c4837394SDouglas Gilbert 					break;
4973c4837394SDouglas Gilbert 				}
4974c4837394SDouglas Gilbert 			}
4975c4837394SDouglas Gilbert 			if (res > 0) {
4976773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4977c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4978c2206098SDouglas Gilbert 							: DEF_JDELAY;
4979cbf67842SDouglas Gilbert 			}
4980c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4981cbf67842SDouglas Gilbert 		}
4982cbf67842SDouglas Gilbert 		return res;
4983cbf67842SDouglas Gilbert 	}
4984cbf67842SDouglas Gilbert 	return -EINVAL;
4985cbf67842SDouglas Gilbert }
4986cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4987cbf67842SDouglas Gilbert 
498882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
49891da177e4SLinus Torvalds {
4990773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
49911da177e4SLinus Torvalds }
49921da177e4SLinus Torvalds 
499382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
499482069379SAkinobu Mita 			  size_t count)
49951da177e4SLinus Torvalds {
49961da177e4SLinus Torvalds 	int opts;
49971da177e4SLinus Torvalds 	char work[20];
49981da177e4SLinus Torvalds 
49999a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
50009a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
50019a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
50021da177e4SLinus Torvalds 				goto opts_done;
50031da177e4SLinus Torvalds 		} else {
50049a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
50051da177e4SLinus Torvalds 				goto opts_done;
50061da177e4SLinus Torvalds 		}
50071da177e4SLinus Torvalds 	}
50081da177e4SLinus Torvalds 	return -EINVAL;
50091da177e4SLinus Torvalds opts_done:
5010773642d9SDouglas Gilbert 	sdebug_opts = opts;
5011773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5012773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5013c4837394SDouglas Gilbert 	tweak_cmnd_count();
50141da177e4SLinus Torvalds 	return count;
50151da177e4SLinus Torvalds }
501682069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
50171da177e4SLinus Torvalds 
501882069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
50191da177e4SLinus Torvalds {
5020773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
50211da177e4SLinus Torvalds }
502282069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
502382069379SAkinobu Mita 			   size_t count)
50241da177e4SLinus Torvalds {
50251da177e4SLinus Torvalds 	int n;
50261da177e4SLinus Torvalds 
50271da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5028773642d9SDouglas Gilbert 		sdebug_ptype = n;
50291da177e4SLinus Torvalds 		return count;
50301da177e4SLinus Torvalds 	}
50311da177e4SLinus Torvalds 	return -EINVAL;
50321da177e4SLinus Torvalds }
503382069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
50341da177e4SLinus Torvalds 
503582069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
50361da177e4SLinus Torvalds {
5037773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
50381da177e4SLinus Torvalds }
503982069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
504082069379SAkinobu Mita 			    size_t count)
50411da177e4SLinus Torvalds {
50421da177e4SLinus Torvalds 	int n;
50431da177e4SLinus Torvalds 
50441da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5045773642d9SDouglas Gilbert 		sdebug_dsense = n;
50461da177e4SLinus Torvalds 		return count;
50471da177e4SLinus Torvalds 	}
50481da177e4SLinus Torvalds 	return -EINVAL;
50491da177e4SLinus Torvalds }
505082069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
50511da177e4SLinus Torvalds 
505282069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
505323183910SDouglas Gilbert {
5054773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
505523183910SDouglas Gilbert }
505682069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
505782069379SAkinobu Mita 			     size_t count)
505823183910SDouglas Gilbert {
505987c715dcSDouglas Gilbert 	int n, idx;
506023183910SDouglas Gilbert 
506123183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
506287c715dcSDouglas Gilbert 		bool want_store = (n == 0);
506387c715dcSDouglas Gilbert 		struct sdebug_host_info *sdhp;
506487c715dcSDouglas Gilbert 
5065cbf67842SDouglas Gilbert 		n = (n > 0);
5066773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
506787c715dcSDouglas Gilbert 		if (sdebug_fake_rw == n)
506887c715dcSDouglas Gilbert 			return count;	/* not transitioning so do nothing */
5069cbf67842SDouglas Gilbert 
507087c715dcSDouglas Gilbert 		if (want_store) {	/* 1 --> 0 transition, set up store */
507187c715dcSDouglas Gilbert 			if (sdeb_first_idx < 0) {
507287c715dcSDouglas Gilbert 				idx = sdebug_add_store();
507387c715dcSDouglas Gilbert 				if (idx < 0)
507487c715dcSDouglas Gilbert 					return idx;
507587c715dcSDouglas Gilbert 			} else {
507687c715dcSDouglas Gilbert 				idx = sdeb_first_idx;
507787c715dcSDouglas Gilbert 				xa_clear_mark(per_store_ap, idx,
507887c715dcSDouglas Gilbert 					      SDEB_XA_NOT_IN_USE);
5079cbf67842SDouglas Gilbert 			}
508087c715dcSDouglas Gilbert 			/* make all hosts use same store */
508187c715dcSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
508287c715dcSDouglas Gilbert 					    host_list) {
508387c715dcSDouglas Gilbert 				if (sdhp->si_idx != idx) {
508487c715dcSDouglas Gilbert 					xa_set_mark(per_store_ap, sdhp->si_idx,
508587c715dcSDouglas Gilbert 						    SDEB_XA_NOT_IN_USE);
508687c715dcSDouglas Gilbert 					sdhp->si_idx = idx;
508787c715dcSDouglas Gilbert 				}
508887c715dcSDouglas Gilbert 			}
508987c715dcSDouglas Gilbert 			sdeb_most_recent_idx = idx;
509087c715dcSDouglas Gilbert 		} else {	/* 0 --> 1 transition is trigger for shrink */
509187c715dcSDouglas Gilbert 			sdebug_erase_all_stores(true /* apart from first */);
5092cbf67842SDouglas Gilbert 		}
5093773642d9SDouglas Gilbert 		sdebug_fake_rw = n;
509423183910SDouglas Gilbert 		return count;
509523183910SDouglas Gilbert 	}
509623183910SDouglas Gilbert 	return -EINVAL;
509723183910SDouglas Gilbert }
509882069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
509923183910SDouglas Gilbert 
510082069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
5101c65b1445SDouglas Gilbert {
5102773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
5103c65b1445SDouglas Gilbert }
510482069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
510582069379SAkinobu Mita 			      size_t count)
5106c65b1445SDouglas Gilbert {
5107c65b1445SDouglas Gilbert 	int n;
5108c65b1445SDouglas Gilbert 
5109c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5110773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
5111c65b1445SDouglas Gilbert 		return count;
5112c65b1445SDouglas Gilbert 	}
5113c65b1445SDouglas Gilbert 	return -EINVAL;
5114c65b1445SDouglas Gilbert }
511582069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
5116c65b1445SDouglas Gilbert 
511782069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
51181da177e4SLinus Torvalds {
5119773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
51201da177e4SLinus Torvalds }
512182069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
512282069379SAkinobu Mita 			      size_t count)
51231da177e4SLinus Torvalds {
51241da177e4SLinus Torvalds 	int n;
51251da177e4SLinus Torvalds 
51261da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5127773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
51281da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
51291da177e4SLinus Torvalds 		return count;
51301da177e4SLinus Torvalds 	}
51311da177e4SLinus Torvalds 	return -EINVAL;
51321da177e4SLinus Torvalds }
513382069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
51341da177e4SLinus Torvalds 
513582069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
51361da177e4SLinus Torvalds {
5137773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
51381da177e4SLinus Torvalds }
513982069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
51401da177e4SLinus Torvalds 
514187c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
514287c715dcSDouglas Gilbert {
514387c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
514487c715dcSDouglas Gilbert }
514587c715dcSDouglas Gilbert 
514687c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
514787c715dcSDouglas Gilbert 				    size_t count)
514887c715dcSDouglas Gilbert {
514987c715dcSDouglas Gilbert 	bool v;
515087c715dcSDouglas Gilbert 
515187c715dcSDouglas Gilbert 	if (kstrtobool(buf, &v))
515287c715dcSDouglas Gilbert 		return -EINVAL;
515387c715dcSDouglas Gilbert 
515487c715dcSDouglas Gilbert 	sdebug_per_host_store = v;
515587c715dcSDouglas Gilbert 	return count;
515687c715dcSDouglas Gilbert }
515787c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store);
515887c715dcSDouglas Gilbert 
515982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
51601da177e4SLinus Torvalds {
5161773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
51621da177e4SLinus Torvalds }
516382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
51641da177e4SLinus Torvalds 
516582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
51661da177e4SLinus Torvalds {
5167773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
51681da177e4SLinus Torvalds }
516982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
517082069379SAkinobu Mita 			       size_t count)
51711da177e4SLinus Torvalds {
51721da177e4SLinus Torvalds 	int nth;
51731da177e4SLinus Torvalds 
51741da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
5175773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
5176c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
5177c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
5178c4837394SDouglas Gilbert 			sdebug_statistics = true;
5179c4837394SDouglas Gilbert 		}
5180c4837394SDouglas Gilbert 		tweak_cmnd_count();
51811da177e4SLinus Torvalds 		return count;
51821da177e4SLinus Torvalds 	}
51831da177e4SLinus Torvalds 	return -EINVAL;
51841da177e4SLinus Torvalds }
518582069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
51861da177e4SLinus Torvalds 
518782069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
51881da177e4SLinus Torvalds {
5189773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
51901da177e4SLinus Torvalds }
519182069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
519282069379SAkinobu Mita 			      size_t count)
51931da177e4SLinus Torvalds {
51941da177e4SLinus Torvalds 	int n;
519519c8ead7SEwan D. Milne 	bool changed;
51961da177e4SLinus Torvalds 
51971da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
51988d039e22SDouglas Gilbert 		if (n > 256) {
51998d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
52008d039e22SDouglas Gilbert 			return -EINVAL;
52018d039e22SDouglas Gilbert 		}
5202773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
5203773642d9SDouglas Gilbert 		sdebug_max_luns = n;
52041da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
5205773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
520619c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
520719c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
520819c8ead7SEwan D. Milne 
520919c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
521019c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
521119c8ead7SEwan D. Milne 					    host_list) {
521219c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
521319c8ead7SEwan D. Milne 						    dev_list) {
521419c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
521519c8ead7SEwan D. Milne 						dp->uas_bm);
521619c8ead7SEwan D. Milne 				}
521719c8ead7SEwan D. Milne 			}
521819c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
521919c8ead7SEwan D. Milne 		}
52201da177e4SLinus Torvalds 		return count;
52211da177e4SLinus Torvalds 	}
52221da177e4SLinus Torvalds 	return -EINVAL;
52231da177e4SLinus Torvalds }
522482069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
52251da177e4SLinus Torvalds 
522682069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
522778d4e5a0SDouglas Gilbert {
5228773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
522978d4e5a0SDouglas Gilbert }
5230cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
5231cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
523282069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
523382069379SAkinobu Mita 			       size_t count)
523478d4e5a0SDouglas Gilbert {
5235c4837394SDouglas Gilbert 	int j, n, k, a;
5236c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
523778d4e5a0SDouglas Gilbert 
523878d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
5239c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
5240c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
5241c4837394SDouglas Gilbert 		k = 0;
5242c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5243c4837394SDouglas Gilbert 		     ++j, ++sqp) {
5244c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
5245c4837394SDouglas Gilbert 			if (a > k)
5246c4837394SDouglas Gilbert 				k = a;
5247c4837394SDouglas Gilbert 		}
5248773642d9SDouglas Gilbert 		sdebug_max_queue = n;
5249c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
5250cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
5251cbf67842SDouglas Gilbert 		else if (k >= n)
5252cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
5253cbf67842SDouglas Gilbert 		else
5254cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
5255c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
525678d4e5a0SDouglas Gilbert 		return count;
525778d4e5a0SDouglas Gilbert 	}
525878d4e5a0SDouglas Gilbert 	return -EINVAL;
525978d4e5a0SDouglas Gilbert }
526082069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
526178d4e5a0SDouglas Gilbert 
526282069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
526378d4e5a0SDouglas Gilbert {
5264773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
526578d4e5a0SDouglas Gilbert }
526682069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
526778d4e5a0SDouglas Gilbert 
526882069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
52691da177e4SLinus Torvalds {
5270773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
52711da177e4SLinus Torvalds }
527282069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
52731da177e4SLinus Torvalds 
527482069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
5275c65b1445SDouglas Gilbert {
5276773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
5277c65b1445SDouglas Gilbert }
527882069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
527982069379SAkinobu Mita 				size_t count)
5280c65b1445SDouglas Gilbert {
5281c65b1445SDouglas Gilbert 	int n;
52820d01c5dfSDouglas Gilbert 	bool changed;
5283c65b1445SDouglas Gilbert 
5284c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5285773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
5286773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
528728898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
52880d01c5dfSDouglas Gilbert 		if (changed) {
52890d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
52900d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
529128898873SFUJITA Tomonori 
52924bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
52930d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
52940d01c5dfSDouglas Gilbert 					    host_list) {
52950d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
52960d01c5dfSDouglas Gilbert 						    dev_list) {
52970d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
52980d01c5dfSDouglas Gilbert 						dp->uas_bm);
52990d01c5dfSDouglas Gilbert 				}
53000d01c5dfSDouglas Gilbert 			}
53014bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
53020d01c5dfSDouglas Gilbert 		}
5303c65b1445SDouglas Gilbert 		return count;
5304c65b1445SDouglas Gilbert 	}
5305c65b1445SDouglas Gilbert 	return -EINVAL;
5306c65b1445SDouglas Gilbert }
530782069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
5308c65b1445SDouglas Gilbert 
530982069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
53101da177e4SLinus Torvalds {
531187c715dcSDouglas Gilbert 	/* absolute number of hosts currently active is what is shown */
531287c715dcSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
53131da177e4SLinus Torvalds }
53141da177e4SLinus Torvalds 
531582069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
531682069379SAkinobu Mita 			      size_t count)
53171da177e4SLinus Torvalds {
531887c715dcSDouglas Gilbert 	bool found;
531987c715dcSDouglas Gilbert 	unsigned long idx;
532087c715dcSDouglas Gilbert 	struct sdeb_store_info *sip;
532187c715dcSDouglas Gilbert 	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
53221da177e4SLinus Torvalds 	int delta_hosts;
53231da177e4SLinus Torvalds 
5324f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
53251da177e4SLinus Torvalds 		return -EINVAL;
53261da177e4SLinus Torvalds 	if (delta_hosts > 0) {
53271da177e4SLinus Torvalds 		do {
532887c715dcSDouglas Gilbert 			found = false;
532987c715dcSDouglas Gilbert 			if (want_phs) {
533087c715dcSDouglas Gilbert 				xa_for_each_marked(per_store_ap, idx, sip,
533187c715dcSDouglas Gilbert 						   SDEB_XA_NOT_IN_USE) {
533287c715dcSDouglas Gilbert 					sdeb_most_recent_idx = (int)idx;
533387c715dcSDouglas Gilbert 					found = true;
533487c715dcSDouglas Gilbert 					break;
533587c715dcSDouglas Gilbert 				}
533687c715dcSDouglas Gilbert 				if (found)	/* re-use case */
533787c715dcSDouglas Gilbert 					sdebug_add_host_helper((int)idx);
533887c715dcSDouglas Gilbert 				else
533987c715dcSDouglas Gilbert 					sdebug_do_add_host(true);
534087c715dcSDouglas Gilbert 			} else {
534187c715dcSDouglas Gilbert 				sdebug_do_add_host(false);
534287c715dcSDouglas Gilbert 			}
53431da177e4SLinus Torvalds 		} while (--delta_hosts);
53441da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
53451da177e4SLinus Torvalds 		do {
534687c715dcSDouglas Gilbert 			sdebug_do_remove_host(false);
53471da177e4SLinus Torvalds 		} while (++delta_hosts);
53481da177e4SLinus Torvalds 	}
53491da177e4SLinus Torvalds 	return count;
53501da177e4SLinus Torvalds }
535182069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
53521da177e4SLinus Torvalds 
535382069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
535423183910SDouglas Gilbert {
5355773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
535623183910SDouglas Gilbert }
535782069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
535882069379SAkinobu Mita 				    size_t count)
535923183910SDouglas Gilbert {
536023183910SDouglas Gilbert 	int n;
536123183910SDouglas Gilbert 
536223183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5363773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
536423183910SDouglas Gilbert 		return count;
536523183910SDouglas Gilbert 	}
536623183910SDouglas Gilbert 	return -EINVAL;
536723183910SDouglas Gilbert }
536882069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
536923183910SDouglas Gilbert 
5370c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5371c4837394SDouglas Gilbert {
5372c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5373c4837394SDouglas Gilbert }
5374c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5375c4837394SDouglas Gilbert 				size_t count)
5376c4837394SDouglas Gilbert {
5377c4837394SDouglas Gilbert 	int n;
5378c4837394SDouglas Gilbert 
5379c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5380c4837394SDouglas Gilbert 		if (n > 0)
5381c4837394SDouglas Gilbert 			sdebug_statistics = true;
5382c4837394SDouglas Gilbert 		else {
5383c4837394SDouglas Gilbert 			clear_queue_stats();
5384c4837394SDouglas Gilbert 			sdebug_statistics = false;
5385c4837394SDouglas Gilbert 		}
5386c4837394SDouglas Gilbert 		return count;
5387c4837394SDouglas Gilbert 	}
5388c4837394SDouglas Gilbert 	return -EINVAL;
5389c4837394SDouglas Gilbert }
5390c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
5391c4837394SDouglas Gilbert 
539282069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
5393597136abSMartin K. Petersen {
5394773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
5395597136abSMartin K. Petersen }
539682069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
5397597136abSMartin K. Petersen 
5398c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5399c4837394SDouglas Gilbert {
5400c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5401c4837394SDouglas Gilbert }
5402c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
5403c4837394SDouglas Gilbert 
540482069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
5405c6a44287SMartin K. Petersen {
5406773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
5407c6a44287SMartin K. Petersen }
540882069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
5409c6a44287SMartin K. Petersen 
541082069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
5411c6a44287SMartin K. Petersen {
5412773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
5413c6a44287SMartin K. Petersen }
541482069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
5415c6a44287SMartin K. Petersen 
541682069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
5417c6a44287SMartin K. Petersen {
5418773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
5419c6a44287SMartin K. Petersen }
542082069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
5421c6a44287SMartin K. Petersen 
542282069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
5423c6a44287SMartin K. Petersen {
5424773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
5425c6a44287SMartin K. Petersen }
542682069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
5427c6a44287SMartin K. Petersen 
542882069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
542944d92694SMartin K. Petersen {
543087c715dcSDouglas Gilbert 	ssize_t count = 0;
543144d92694SMartin K. Petersen 
54325b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
543344d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
543444d92694SMartin K. Petersen 				 sdebug_store_sectors);
543544d92694SMartin K. Petersen 
543687c715dcSDouglas Gilbert 	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
543787c715dcSDouglas Gilbert 		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
543887c715dcSDouglas Gilbert 
543987c715dcSDouglas Gilbert 		if (sip)
5440c7badc90STejun Heo 			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
544187c715dcSDouglas Gilbert 					  (int)map_size, sip->map_storep);
544287c715dcSDouglas Gilbert 	}
544344d92694SMartin K. Petersen 	buf[count++] = '\n';
5444c7badc90STejun Heo 	buf[count] = '\0';
544544d92694SMartin K. Petersen 
544644d92694SMartin K. Petersen 	return count;
544744d92694SMartin K. Petersen }
544882069379SAkinobu Mita static DRIVER_ATTR_RO(map);
544944d92694SMartin K. Petersen 
54500c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf)
54510c4bc91dSDouglas Gilbert {
54520c4bc91dSDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
54530c4bc91dSDouglas Gilbert }
54540c4bc91dSDouglas Gilbert 
54550c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf,
54560c4bc91dSDouglas Gilbert 			    size_t count)
54570c4bc91dSDouglas Gilbert {
54580c4bc91dSDouglas Gilbert 	bool v;
54590c4bc91dSDouglas Gilbert 
54600c4bc91dSDouglas Gilbert 	if (kstrtobool(buf, &v))
54610c4bc91dSDouglas Gilbert 		return -EINVAL;
54620c4bc91dSDouglas Gilbert 
54630c4bc91dSDouglas Gilbert 	sdebug_random = v;
54640c4bc91dSDouglas Gilbert 	return count;
54650c4bc91dSDouglas Gilbert }
54660c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random);
54670c4bc91dSDouglas Gilbert 
546882069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
5469d986788bSMartin Pitt {
5470773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
5471d986788bSMartin Pitt }
547282069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
547382069379SAkinobu Mita 			       size_t count)
5474d986788bSMartin Pitt {
5475d986788bSMartin Pitt 	int n;
5476d986788bSMartin Pitt 
5477d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5478773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
5479d986788bSMartin Pitt 		return count;
5480d986788bSMartin Pitt 	}
5481d986788bSMartin Pitt 	return -EINVAL;
5482d986788bSMartin Pitt }
548382069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
5484d986788bSMartin Pitt 
5485cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5486cbf67842SDouglas Gilbert {
5487773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
5488cbf67842SDouglas Gilbert }
5489185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
5490cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5491cbf67842SDouglas Gilbert 			       size_t count)
5492cbf67842SDouglas Gilbert {
5493185dd232SDouglas Gilbert 	int n;
5494cbf67842SDouglas Gilbert 
5495cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5496185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
5497185dd232SDouglas Gilbert 		return count;
5498cbf67842SDouglas Gilbert 	}
5499cbf67842SDouglas Gilbert 	return -EINVAL;
5500cbf67842SDouglas Gilbert }
5501cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
5502cbf67842SDouglas Gilbert 
5503c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
5504c2248fc9SDouglas Gilbert {
5505773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
5506c2248fc9SDouglas Gilbert }
5507c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5508c2248fc9SDouglas Gilbert 			    size_t count)
5509c2248fc9SDouglas Gilbert {
5510c2248fc9SDouglas Gilbert 	int n;
5511c2248fc9SDouglas Gilbert 
5512c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5513773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
5514c2248fc9SDouglas Gilbert 		return count;
5515c2248fc9SDouglas Gilbert 	}
5516c2248fc9SDouglas Gilbert 	return -EINVAL;
5517c2248fc9SDouglas Gilbert }
5518c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
5519c2248fc9SDouglas Gilbert 
552009ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
552109ba24c1SDouglas Gilbert {
552209ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
552309ba24c1SDouglas Gilbert }
552409ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
552509ba24c1SDouglas Gilbert 
55269b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
55279b760fd8SDouglas Gilbert {
55289b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
55299b760fd8SDouglas Gilbert }
55309b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
55319b760fd8SDouglas Gilbert 			     size_t count)
55329b760fd8SDouglas Gilbert {
55339b760fd8SDouglas Gilbert 	int ret, n;
55349b760fd8SDouglas Gilbert 
55359b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
55369b760fd8SDouglas Gilbert 	if (ret)
55379b760fd8SDouglas Gilbert 		return ret;
55389b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
55399b760fd8SDouglas Gilbert 	all_config_cdb_len();
55409b760fd8SDouglas Gilbert 	return count;
55419b760fd8SDouglas Gilbert }
55429b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
55439b760fd8SDouglas Gilbert 
5544cbf67842SDouglas Gilbert 
554582069379SAkinobu Mita /* Note: The following array creates attribute files in the
554623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
554723183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
554823183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
554987c715dcSDouglas Gilbert    is changed. For example see: add_host_store() above.
555023183910SDouglas Gilbert  */
55516ecaff7fSRandy Dunlap 
555282069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
555382069379SAkinobu Mita 	&driver_attr_delay.attr,
555482069379SAkinobu Mita 	&driver_attr_opts.attr,
555582069379SAkinobu Mita 	&driver_attr_ptype.attr,
555682069379SAkinobu Mita 	&driver_attr_dsense.attr,
555782069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
555882069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
555982069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
556082069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
556182069379SAkinobu Mita 	&driver_attr_num_parts.attr,
556282069379SAkinobu Mita 	&driver_attr_every_nth.attr,
556382069379SAkinobu Mita 	&driver_attr_max_luns.attr,
556482069379SAkinobu Mita 	&driver_attr_max_queue.attr,
556582069379SAkinobu Mita 	&driver_attr_no_uld.attr,
556682069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
556782069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
556882069379SAkinobu Mita 	&driver_attr_add_host.attr,
556987c715dcSDouglas Gilbert 	&driver_attr_per_host_store.attr,
557082069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
557182069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5572c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5573c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
557482069379SAkinobu Mita 	&driver_attr_dix.attr,
557582069379SAkinobu Mita 	&driver_attr_dif.attr,
557682069379SAkinobu Mita 	&driver_attr_guard.attr,
557782069379SAkinobu Mita 	&driver_attr_ato.attr,
557882069379SAkinobu Mita 	&driver_attr_map.attr,
55790c4bc91dSDouglas Gilbert 	&driver_attr_random.attr,
558082069379SAkinobu Mita 	&driver_attr_removable.attr,
5581cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5582cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5583c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
558409ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
55859b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
558682069379SAkinobu Mita 	NULL,
558782069379SAkinobu Mita };
558882069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
55891da177e4SLinus Torvalds 
559011ddcecaSAkinobu Mita static struct device *pseudo_primary;
55918dea0d02SFUJITA Tomonori 
55921da177e4SLinus Torvalds static int __init scsi_debug_init(void)
55931da177e4SLinus Torvalds {
559487c715dcSDouglas Gilbert 	bool want_store = (sdebug_fake_rw == 0);
55955f2578e5SFUJITA Tomonori 	unsigned long sz;
559687c715dcSDouglas Gilbert 	int k, ret, hosts_to_add;
559787c715dcSDouglas Gilbert 	int idx = -1;
55981da177e4SLinus Torvalds 
559987c715dcSDouglas Gilbert 	ramdisk_lck_a[0] = &atomic_rw;
560087c715dcSDouglas Gilbert 	ramdisk_lck_a[1] = &atomic_rw2;
5601cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5602cbf67842SDouglas Gilbert 
5603773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5604c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5605773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5606773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5607c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5608cbf67842SDouglas Gilbert 
5609773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5610597136abSMartin K. Petersen 	case  512:
5611597136abSMartin K. Petersen 	case 1024:
5612597136abSMartin K. Petersen 	case 2048:
5613597136abSMartin K. Petersen 	case 4096:
5614597136abSMartin K. Petersen 		break;
5615597136abSMartin K. Petersen 	default:
5616773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5617597136abSMartin K. Petersen 		return -EINVAL;
5618597136abSMartin K. Petersen 	}
5619597136abSMartin K. Petersen 
5620773642d9SDouglas Gilbert 	switch (sdebug_dif) {
56218475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5622f46eb0e9SDouglas Gilbert 		break;
56238475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
56248475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
56258475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5626f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5627c6a44287SMartin K. Petersen 		break;
5628c6a44287SMartin K. Petersen 
5629c6a44287SMartin K. Petersen 	default:
5630c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5631c6a44287SMartin K. Petersen 		return -EINVAL;
5632c6a44287SMartin K. Petersen 	}
5633c6a44287SMartin K. Petersen 
5634aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
5635aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
5636aa5334c4SMaurizio Lombardi 		return -EINVAL;
5637aa5334c4SMaurizio Lombardi 	}
5638aa5334c4SMaurizio Lombardi 
5639773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5640c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5641c6a44287SMartin K. Petersen 		return -EINVAL;
5642c6a44287SMartin K. Petersen 	}
5643c6a44287SMartin K. Petersen 
5644773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5645c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5646c6a44287SMartin K. Petersen 		return -EINVAL;
5647c6a44287SMartin K. Petersen 	}
5648c6a44287SMartin K. Petersen 
5649773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5650773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5651ea61fca5SMartin K. Petersen 		return -EINVAL;
5652ea61fca5SMartin K. Petersen 	}
56538d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
56548d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
56558d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
56568d039e22SDouglas Gilbert 	}
5657ea61fca5SMartin K. Petersen 
5658773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5659773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5660ea61fca5SMartin K. Petersen 		return -EINVAL;
5661ea61fca5SMartin K. Petersen 	}
5662ea61fca5SMartin K. Petersen 
5663c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5664c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5665c4837394SDouglas Gilbert 		return -EINVAL;
5666c4837394SDouglas Gilbert 	}
5667c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5668c4837394SDouglas Gilbert 			       GFP_KERNEL);
5669c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5670c4837394SDouglas Gilbert 		return -ENOMEM;
5671c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5672c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5673c4837394SDouglas Gilbert 
5674773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5675773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5676773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5677773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
567828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
56791da177e4SLinus Torvalds 
56801da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
56811da177e4SLinus Torvalds 	sdebug_heads = 8;
56821da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5683773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
56841da177e4SLinus Torvalds 		sdebug_heads = 64;
5685773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5686fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
56871da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
56881da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
56891da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
56901da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
56911da177e4SLinus Torvalds 		sdebug_heads = 255;
56921da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
56931da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
56941da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
56951da177e4SLinus Torvalds 	}
56965b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5697773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5698773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
56996014759cSMartin K. Petersen 
5700773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5701773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
57026014759cSMartin K. Petersen 
5703773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5704773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
57056014759cSMartin K. Petersen 
5706773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5707773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5708773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5709c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5710c4837394SDouglas Gilbert 			ret = -EINVAL;
571187c715dcSDouglas Gilbert 			goto free_q_arr;
571244d92694SMartin K. Petersen 		}
571344d92694SMartin K. Petersen 	}
571487c715dcSDouglas Gilbert 	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
571587c715dcSDouglas Gilbert 	if (want_store) {
571687c715dcSDouglas Gilbert 		idx = sdebug_add_store();
571787c715dcSDouglas Gilbert 		if (idx < 0) {
571887c715dcSDouglas Gilbert 			ret = idx;
571987c715dcSDouglas Gilbert 			goto free_q_arr;
572087c715dcSDouglas Gilbert 		}
572144d92694SMartin K. Petersen 	}
572244d92694SMartin K. Petersen 
57239b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
57249b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5725c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
57269b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
57276ecaff7fSRandy Dunlap 		goto free_vm;
57286ecaff7fSRandy Dunlap 	}
57296ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
57306ecaff7fSRandy Dunlap 	if (ret < 0) {
5731c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
57326ecaff7fSRandy Dunlap 		goto dev_unreg;
57336ecaff7fSRandy Dunlap 	}
57346ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
57356ecaff7fSRandy Dunlap 	if (ret < 0) {
5736c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
57376ecaff7fSRandy Dunlap 		goto bus_unreg;
57386ecaff7fSRandy Dunlap 	}
57391da177e4SLinus Torvalds 
574087c715dcSDouglas Gilbert 	hosts_to_add = sdebug_add_host;
5741773642d9SDouglas Gilbert 	sdebug_add_host = 0;
57421da177e4SLinus Torvalds 
574387c715dcSDouglas Gilbert 	for (k = 0; k < hosts_to_add; k++) {
574487c715dcSDouglas Gilbert 		if (want_store && k == 0) {
574587c715dcSDouglas Gilbert 			ret = sdebug_add_host_helper(idx);
574687c715dcSDouglas Gilbert 			if (ret < 0) {
574787c715dcSDouglas Gilbert 				pr_err("add_host_helper k=%d, error=%d\n",
574887c715dcSDouglas Gilbert 				       k, -ret);
574987c715dcSDouglas Gilbert 				break;
575087c715dcSDouglas Gilbert 			}
575187c715dcSDouglas Gilbert 		} else {
575287c715dcSDouglas Gilbert 			ret = sdebug_do_add_host(want_store &&
575387c715dcSDouglas Gilbert 						 sdebug_per_host_store);
575487c715dcSDouglas Gilbert 			if (ret < 0) {
575587c715dcSDouglas Gilbert 				pr_err("add_host k=%d error=%d\n", k, -ret);
57561da177e4SLinus Torvalds 				break;
57571da177e4SLinus Torvalds 			}
57581da177e4SLinus Torvalds 		}
575987c715dcSDouglas Gilbert 	}
5760773642d9SDouglas Gilbert 	if (sdebug_verbose)
576187c715dcSDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_num_hosts);
5762c1287970STomas Winkler 
57631da177e4SLinus Torvalds 	return 0;
57646ecaff7fSRandy Dunlap 
57656ecaff7fSRandy Dunlap bus_unreg:
57666ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
57676ecaff7fSRandy Dunlap dev_unreg:
57689b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
57696ecaff7fSRandy Dunlap free_vm:
577087c715dcSDouglas Gilbert 	sdebug_erase_store(idx, NULL);
5771c4837394SDouglas Gilbert free_q_arr:
5772c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
57736ecaff7fSRandy Dunlap 	return ret;
57741da177e4SLinus Torvalds }
57751da177e4SLinus Torvalds 
57761da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
57771da177e4SLinus Torvalds {
577887c715dcSDouglas Gilbert 	int k = sdebug_num_hosts;
57791da177e4SLinus Torvalds 
57801da177e4SLinus Torvalds 	stop_all_queued();
57811da177e4SLinus Torvalds 	for (; k; k--)
578287c715dcSDouglas Gilbert 		sdebug_do_remove_host(true);
578352ab9768SLuis Henriques 	free_all_queued();
57841da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
57851da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
57869b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
57871da177e4SLinus Torvalds 
578887c715dcSDouglas Gilbert 	sdebug_erase_all_stores(false);
578987c715dcSDouglas Gilbert 	xa_destroy(per_store_ap);
57901da177e4SLinus Torvalds }
57911da177e4SLinus Torvalds 
57921da177e4SLinus Torvalds device_initcall(scsi_debug_init);
57931da177e4SLinus Torvalds module_exit(scsi_debug_exit);
57941da177e4SLinus Torvalds 
57951da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
57961da177e4SLinus Torvalds {
57971da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
57981da177e4SLinus Torvalds 
57991da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
58001da177e4SLinus Torvalds 	kfree(sdbg_host);
58011da177e4SLinus Torvalds }
58021da177e4SLinus Torvalds 
580387c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */
580487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
58051da177e4SLinus Torvalds {
580687c715dcSDouglas Gilbert 	if (idx < 0)
580787c715dcSDouglas Gilbert 		return;
580887c715dcSDouglas Gilbert 	if (!sip) {
580987c715dcSDouglas Gilbert 		if (xa_empty(per_store_ap))
581087c715dcSDouglas Gilbert 			return;
581187c715dcSDouglas Gilbert 		sip = xa_load(per_store_ap, idx);
581287c715dcSDouglas Gilbert 		if (!sip)
581387c715dcSDouglas Gilbert 			return;
581487c715dcSDouglas Gilbert 	}
581587c715dcSDouglas Gilbert 	vfree(sip->map_storep);
581687c715dcSDouglas Gilbert 	vfree(sip->dif_storep);
581787c715dcSDouglas Gilbert 	vfree(sip->storep);
581887c715dcSDouglas Gilbert 	xa_erase(per_store_ap, idx);
581987c715dcSDouglas Gilbert 	kfree(sip);
582087c715dcSDouglas Gilbert }
582187c715dcSDouglas Gilbert 
582287c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */
582387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first)
582487c715dcSDouglas Gilbert {
582587c715dcSDouglas Gilbert 	unsigned long idx;
582687c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
582787c715dcSDouglas Gilbert 
582887c715dcSDouglas Gilbert 	xa_for_each(per_store_ap, idx, sip) {
582987c715dcSDouglas Gilbert 		if (apart_from_first)
583087c715dcSDouglas Gilbert 			apart_from_first = false;
583187c715dcSDouglas Gilbert 		else
583287c715dcSDouglas Gilbert 			sdebug_erase_store(idx, sip);
583387c715dcSDouglas Gilbert 	}
583487c715dcSDouglas Gilbert 	if (apart_from_first)
583587c715dcSDouglas Gilbert 		sdeb_most_recent_idx = sdeb_first_idx;
583687c715dcSDouglas Gilbert }
583787c715dcSDouglas Gilbert 
583887c715dcSDouglas Gilbert /*
583987c715dcSDouglas Gilbert  * Returns store xarray new element index (idx) if >=0 else negated errno.
584087c715dcSDouglas Gilbert  * Limit the number of stores to 65536.
584187c715dcSDouglas Gilbert  */
584287c715dcSDouglas Gilbert static int sdebug_add_store(void)
584387c715dcSDouglas Gilbert {
584487c715dcSDouglas Gilbert 	int res;
584587c715dcSDouglas Gilbert 	u32 n_idx;
584687c715dcSDouglas Gilbert 	unsigned long iflags;
584787c715dcSDouglas Gilbert 	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
584887c715dcSDouglas Gilbert 	struct sdeb_store_info *sip = NULL;
584987c715dcSDouglas Gilbert 	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
585087c715dcSDouglas Gilbert 
585187c715dcSDouglas Gilbert 	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
585287c715dcSDouglas Gilbert 	if (!sip)
585387c715dcSDouglas Gilbert 		return -ENOMEM;
585487c715dcSDouglas Gilbert 
585587c715dcSDouglas Gilbert 	xa_lock_irqsave(per_store_ap, iflags);
585687c715dcSDouglas Gilbert 	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
585787c715dcSDouglas Gilbert 	if (unlikely(res < 0)) {
585887c715dcSDouglas Gilbert 		xa_unlock_irqrestore(per_store_ap, iflags);
585987c715dcSDouglas Gilbert 		kfree(sip);
586087c715dcSDouglas Gilbert 		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
586187c715dcSDouglas Gilbert 		return res;
586287c715dcSDouglas Gilbert 	}
586387c715dcSDouglas Gilbert 	sdeb_most_recent_idx = n_idx;
586487c715dcSDouglas Gilbert 	if (sdeb_first_idx < 0)
586587c715dcSDouglas Gilbert 		sdeb_first_idx = n_idx;
586687c715dcSDouglas Gilbert 	xa_unlock_irqrestore(per_store_ap, iflags);
586787c715dcSDouglas Gilbert 
586887c715dcSDouglas Gilbert 	res = -ENOMEM;
586987c715dcSDouglas Gilbert 	sip->storep = vzalloc(sz);
587087c715dcSDouglas Gilbert 	if (!sip->storep) {
587187c715dcSDouglas Gilbert 		pr_err("user data oom\n");
587287c715dcSDouglas Gilbert 		goto err;
587387c715dcSDouglas Gilbert 	}
587487c715dcSDouglas Gilbert 	if (sdebug_num_parts > 0)
587587c715dcSDouglas Gilbert 		sdebug_build_parts(sip->storep, sz);
587687c715dcSDouglas Gilbert 
587787c715dcSDouglas Gilbert 	/* DIF/DIX: what T10 calls Protection Information (PI) */
587887c715dcSDouglas Gilbert 	if (sdebug_dix) {
587987c715dcSDouglas Gilbert 		int dif_size;
588087c715dcSDouglas Gilbert 
588187c715dcSDouglas Gilbert 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
588287c715dcSDouglas Gilbert 		sip->dif_storep = vmalloc(dif_size);
588387c715dcSDouglas Gilbert 
588487c715dcSDouglas Gilbert 		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
588587c715dcSDouglas Gilbert 			sip->dif_storep);
588687c715dcSDouglas Gilbert 
588787c715dcSDouglas Gilbert 		if (!sip->dif_storep) {
588887c715dcSDouglas Gilbert 			pr_err("DIX oom\n");
588987c715dcSDouglas Gilbert 			goto err;
589087c715dcSDouglas Gilbert 		}
589187c715dcSDouglas Gilbert 		memset(sip->dif_storep, 0xff, dif_size);
589287c715dcSDouglas Gilbert 	}
589387c715dcSDouglas Gilbert 	/* Logical Block Provisioning */
589487c715dcSDouglas Gilbert 	if (scsi_debug_lbp()) {
589587c715dcSDouglas Gilbert 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
589687c715dcSDouglas Gilbert 		sip->map_storep = vmalloc(array_size(sizeof(long),
589787c715dcSDouglas Gilbert 						     BITS_TO_LONGS(map_size)));
589887c715dcSDouglas Gilbert 
589987c715dcSDouglas Gilbert 		pr_info("%lu provisioning blocks\n", map_size);
590087c715dcSDouglas Gilbert 
590187c715dcSDouglas Gilbert 		if (!sip->map_storep) {
590287c715dcSDouglas Gilbert 			pr_err("LBP map oom\n");
590387c715dcSDouglas Gilbert 			goto err;
590487c715dcSDouglas Gilbert 		}
590587c715dcSDouglas Gilbert 
590687c715dcSDouglas Gilbert 		bitmap_zero(sip->map_storep, map_size);
590787c715dcSDouglas Gilbert 
590887c715dcSDouglas Gilbert 		/* Map first 1KB for partition table */
590987c715dcSDouglas Gilbert 		if (sdebug_num_parts)
591087c715dcSDouglas Gilbert 			map_region(sip, 0, 2);
591187c715dcSDouglas Gilbert 	}
591287c715dcSDouglas Gilbert 
591387c715dcSDouglas Gilbert 	rwlock_init(&sip->macc_lck);
591487c715dcSDouglas Gilbert 	return (int)n_idx;
591587c715dcSDouglas Gilbert err:
591687c715dcSDouglas Gilbert 	sdebug_erase_store((int)n_idx, sip);
591787c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -res);
591887c715dcSDouglas Gilbert 	return res;
591987c715dcSDouglas Gilbert }
592087c715dcSDouglas Gilbert 
592187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx)
592287c715dcSDouglas Gilbert {
592387c715dcSDouglas Gilbert 	int k, devs_per_host, idx;
592487c715dcSDouglas Gilbert 	int error = -ENOMEM;
59251da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
59268b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
59271da177e4SLinus Torvalds 
592824669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
592987c715dcSDouglas Gilbert 	if (!sdbg_host)
59301da177e4SLinus Torvalds 		return -ENOMEM;
593187c715dcSDouglas Gilbert 	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
593287c715dcSDouglas Gilbert 	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
593387c715dcSDouglas Gilbert 		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
593487c715dcSDouglas Gilbert 	sdbg_host->si_idx = idx;
59351da177e4SLinus Torvalds 
59361da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
59371da177e4SLinus Torvalds 
5938773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
59391da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
59405cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
594187c715dcSDouglas Gilbert 		if (!sdbg_devinfo)
59421da177e4SLinus Torvalds 			goto clean;
59431da177e4SLinus Torvalds 	}
59441da177e4SLinus Torvalds 
59451da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
59461da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
59471da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
59481da177e4SLinus Torvalds 
59491da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
59509b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
59511da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
595287c715dcSDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
59531da177e4SLinus Torvalds 
59541da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
59551da177e4SLinus Torvalds 	if (error)
59561da177e4SLinus Torvalds 		goto clean;
59571da177e4SLinus Torvalds 
595887c715dcSDouglas Gilbert 	++sdebug_num_hosts;
595987c715dcSDouglas Gilbert 	return 0;
59601da177e4SLinus Torvalds 
59611da177e4SLinus Torvalds clean:
59628b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
59638b40228fSFUJITA Tomonori 				 dev_list) {
59641da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
59651da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
59661da177e4SLinus Torvalds 	}
59671da177e4SLinus Torvalds 	kfree(sdbg_host);
596887c715dcSDouglas Gilbert 	pr_warn("%s: failed, errno=%d\n", __func__, -error);
59691da177e4SLinus Torvalds 	return error;
59701da177e4SLinus Torvalds }
59711da177e4SLinus Torvalds 
597287c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store)
59731da177e4SLinus Torvalds {
597487c715dcSDouglas Gilbert 	int ph_idx = sdeb_most_recent_idx;
597587c715dcSDouglas Gilbert 
597687c715dcSDouglas Gilbert 	if (mk_new_store) {
597787c715dcSDouglas Gilbert 		ph_idx = sdebug_add_store();
597887c715dcSDouglas Gilbert 		if (ph_idx < 0)
597987c715dcSDouglas Gilbert 			return ph_idx;
598087c715dcSDouglas Gilbert 	}
598187c715dcSDouglas Gilbert 	return sdebug_add_host_helper(ph_idx);
598287c715dcSDouglas Gilbert }
598387c715dcSDouglas Gilbert 
598487c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end)
598587c715dcSDouglas Gilbert {
598687c715dcSDouglas Gilbert 	int idx = -1;
59871da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
598887c715dcSDouglas Gilbert 	struct sdebug_host_info *sdbg_host2;
59891da177e4SLinus Torvalds 
59901da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
59911da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
59921da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
59931da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
599487c715dcSDouglas Gilbert 		idx = sdbg_host->si_idx;
59951da177e4SLinus Torvalds 	}
599687c715dcSDouglas Gilbert 	if (!the_end && idx >= 0) {
599787c715dcSDouglas Gilbert 		bool unique = true;
599887c715dcSDouglas Gilbert 
599987c715dcSDouglas Gilbert 		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
600087c715dcSDouglas Gilbert 			if (sdbg_host2 == sdbg_host)
600187c715dcSDouglas Gilbert 				continue;
600287c715dcSDouglas Gilbert 			if (idx == sdbg_host2->si_idx) {
600387c715dcSDouglas Gilbert 				unique = false;
600487c715dcSDouglas Gilbert 				break;
600587c715dcSDouglas Gilbert 			}
600687c715dcSDouglas Gilbert 		}
600787c715dcSDouglas Gilbert 		if (unique) {
600887c715dcSDouglas Gilbert 			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
600987c715dcSDouglas Gilbert 			if (idx == sdeb_most_recent_idx)
601087c715dcSDouglas Gilbert 				--sdeb_most_recent_idx;
601187c715dcSDouglas Gilbert 		}
601287c715dcSDouglas Gilbert 	}
601387c715dcSDouglas Gilbert 	if (sdbg_host)
601487c715dcSDouglas Gilbert 		list_del(&sdbg_host->host_list);
60151da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
60161da177e4SLinus Torvalds 
60171da177e4SLinus Torvalds 	if (!sdbg_host)
60181da177e4SLinus Torvalds 		return;
60191da177e4SLinus Torvalds 
60201da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
602187c715dcSDouglas Gilbert 	--sdebug_num_hosts;
60221da177e4SLinus Torvalds }
60231da177e4SLinus Torvalds 
6024fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
6025cbf67842SDouglas Gilbert {
6026cbf67842SDouglas Gilbert 	int num_in_q = 0;
6027cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
6028cbf67842SDouglas Gilbert 
6029c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
6030cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
6031cbf67842SDouglas Gilbert 	if (NULL == devip) {
6032c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
6033cbf67842SDouglas Gilbert 		return	-ENODEV;
6034cbf67842SDouglas Gilbert 	}
6035cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
6036c40ecc12SChristoph Hellwig 
6037cbf67842SDouglas Gilbert 	if (qdepth < 1)
6038cbf67842SDouglas Gilbert 		qdepth = 1;
6039c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
6040c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
6041c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
6042db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
6043cbf67842SDouglas Gilbert 
6044773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
6045c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
6046c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
6047cbf67842SDouglas Gilbert 	}
6048c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
6049cbf67842SDouglas Gilbert 	return sdev->queue_depth;
6050cbf67842SDouglas Gilbert }
6051cbf67842SDouglas Gilbert 
6052c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
6053817fd66bSDouglas Gilbert {
6054c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
6055773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
6056773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
6057773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
6058c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
6059773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
6060817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
6061c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
6062817fd66bSDouglas Gilbert 	}
6063c4837394SDouglas Gilbert 	return false;
6064817fd66bSDouglas Gilbert }
6065817fd66bSDouglas Gilbert 
60667ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
60677ee6d1b4SBart Van Assche {
60687ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
60697ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
60707ee6d1b4SBart Van Assche }
60717ee6d1b4SBart Van Assche 
6072fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
6073fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
6074c2248fc9SDouglas Gilbert {
6075c2248fc9SDouglas Gilbert 	u8 sdeb_i;
6076c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
6077c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
6078c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
6079c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
608087c715dcSDouglas Gilbert 
6081c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
6082c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
6083f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
6084c2248fc9SDouglas Gilbert 	int k, na;
6085c2248fc9SDouglas Gilbert 	int errsts = 0;
6086c2248fc9SDouglas Gilbert 	u32 flags;
6087c2248fc9SDouglas Gilbert 	u16 sa;
6088c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
6089c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
6090c2248fc9SDouglas Gilbert 
6091c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
6092c4837394SDouglas Gilbert 	if (sdebug_statistics)
6093c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
6094f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
6095f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
6096c2248fc9SDouglas Gilbert 		char b[120];
6097c2248fc9SDouglas Gilbert 		int n, len, sb;
6098c2248fc9SDouglas Gilbert 
6099c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
6100c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
6101c2248fc9SDouglas Gilbert 		if (len > 32)
6102c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
6103c2248fc9SDouglas Gilbert 		else {
6104c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
6105c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
6106c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
6107c2248fc9SDouglas Gilbert 		}
6108458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
6109458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
6110c2248fc9SDouglas Gilbert 	}
61117ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
61127ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
611334d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
6114f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
6115f46eb0e9SDouglas Gilbert 		goto err_out;
6116c2248fc9SDouglas Gilbert 
6117c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
6118c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
6119c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
6120f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
6121f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
6122c2248fc9SDouglas Gilbert 		if (NULL == devip)
6123f46eb0e9SDouglas Gilbert 			goto err_out;
6124c2248fc9SDouglas Gilbert 	}
6125c2248fc9SDouglas Gilbert 	na = oip->num_attached;
6126c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
6127c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
6128c2248fc9SDouglas Gilbert 		r_oip = oip;
6129c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
6130c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
6131c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
6132c2248fc9SDouglas Gilbert 			else
6133c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
6134c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
6135c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
6136c2248fc9SDouglas Gilbert 					break;
6137c2248fc9SDouglas Gilbert 			}
6138c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
6139c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
6140c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
6141c2248fc9SDouglas Gilbert 					break;
6142c2248fc9SDouglas Gilbert 			}
6143c2248fc9SDouglas Gilbert 		}
6144c2248fc9SDouglas Gilbert 		if (k > na) {
6145c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
6146c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
6147c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
6148c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
6149c2248fc9SDouglas Gilbert 			else
6150c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
6151c2248fc9SDouglas Gilbert 			goto check_cond;
6152c2248fc9SDouglas Gilbert 		}
6153c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
6154c2248fc9SDouglas Gilbert 	flags = oip->flags;
6155f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
6156c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
6157c2248fc9SDouglas Gilbert 		goto check_cond;
6158c2248fc9SDouglas Gilbert 	}
6159f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
6160773642d9SDouglas Gilbert 		if (sdebug_verbose)
6161773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
6162773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
6163c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
6164c2248fc9SDouglas Gilbert 		goto check_cond;
6165c2248fc9SDouglas Gilbert 	}
6166f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
6167c2248fc9SDouglas Gilbert 		u8 rem;
6168c2248fc9SDouglas Gilbert 		int j;
6169c2248fc9SDouglas Gilbert 
6170c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
6171c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
6172c2248fc9SDouglas Gilbert 			if (rem) {
6173c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
6174c2248fc9SDouglas Gilbert 					if (0x80 & rem)
6175c2248fc9SDouglas Gilbert 						break;
6176c2248fc9SDouglas Gilbert 				}
6177c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
6178c2248fc9SDouglas Gilbert 				goto check_cond;
6179c2248fc9SDouglas Gilbert 			}
6180c2248fc9SDouglas Gilbert 		}
6181c2248fc9SDouglas Gilbert 	}
6182f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
6183b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
6184b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
6185f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
6186c2248fc9SDouglas Gilbert 		if (errsts)
6187c2248fc9SDouglas Gilbert 			goto check_cond;
6188c2248fc9SDouglas Gilbert 	}
6189c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
6190c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
6191773642d9SDouglas Gilbert 		if (sdebug_verbose)
6192c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
6193c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
6194c2248fc9SDouglas Gilbert 				    "required");
6195c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
6196c2248fc9SDouglas Gilbert 		goto fini;
6197c2248fc9SDouglas Gilbert 	}
6198773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
6199c2248fc9SDouglas Gilbert 		goto fini;
6200f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
6201c4837394SDouglas Gilbert 		if (fake_timeout(scp))
6202c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
6203c2248fc9SDouglas Gilbert 	}
6204f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
6205f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
6206f66b8517SMartin Wilck 	else
6207f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
6208c2248fc9SDouglas Gilbert 
6209c2248fc9SDouglas Gilbert fini:
621067da413fSDouglas Gilbert 	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
6211f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
621275aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
621375aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
621480c49563SDouglas Gilbert 		/*
621575aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
621675aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
621775aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
621875aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
621980c49563SDouglas Gilbert 		 */
622080c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
62214f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
622280c49563SDouglas Gilbert 
62234f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
6224f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
622580c49563SDouglas Gilbert 	} else
6226f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
622710bde980SDouglas Gilbert 				     sdebug_ndelay);
6228c2248fc9SDouglas Gilbert check_cond:
6229f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
6230f46eb0e9SDouglas Gilbert err_out:
6231f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
6232c2248fc9SDouglas Gilbert }
6233c2248fc9SDouglas Gilbert 
62349e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
6235c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
6236c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
62379e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
62389e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
62399e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
62409e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
62419e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
62429e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
62439e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
6244185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
6245cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
62469e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
62479e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
6248cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
6249cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
62509e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
6251c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
62529e603ca0SFUJITA Tomonori 	.this_id =		7,
625365e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
6254cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
62556bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
625650c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
62579e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
6258c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
62599e603ca0SFUJITA Tomonori };
62609e603ca0SFUJITA Tomonori 
62611da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
62621da177e4SLinus Torvalds {
62631da177e4SLinus Torvalds 	int error = 0;
62641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
62651da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
6266f46eb0e9SDouglas Gilbert 	int hprot;
62671da177e4SLinus Torvalds 
62681da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
62691da177e4SLinus Torvalds 
6270773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
62712a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
62724af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
62734af14d11SChristoph Hellwig 
62741da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
62751da177e4SLinus Torvalds 	if (NULL == hpnt) {
6276c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
62771da177e4SLinus Torvalds 		error = -ENODEV;
62781da177e4SLinus Torvalds 		return error;
62791da177e4SLinus Torvalds 	}
6280c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
62819b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
6282c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
6283c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
6284c4837394SDouglas Gilbert 	}
6285c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
6286c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
6287c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
62881da177e4SLinus Torvalds 
62891da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
62901da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
6291773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
6292773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
62931da177e4SLinus Torvalds 	else
6294773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
6295773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
6296f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
62971da177e4SLinus Torvalds 
6298f46eb0e9SDouglas Gilbert 	hprot = 0;
6299c6a44287SMartin K. Petersen 
6300773642d9SDouglas Gilbert 	switch (sdebug_dif) {
6301c6a44287SMartin K. Petersen 
63028475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
6303f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
6304773642d9SDouglas Gilbert 		if (sdebug_dix)
6305f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
6306c6a44287SMartin K. Petersen 		break;
6307c6a44287SMartin K. Petersen 
63088475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
6309f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
6310773642d9SDouglas Gilbert 		if (sdebug_dix)
6311f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
6312c6a44287SMartin K. Petersen 		break;
6313c6a44287SMartin K. Petersen 
63148475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
6315f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
6316773642d9SDouglas Gilbert 		if (sdebug_dix)
6317f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
6318c6a44287SMartin K. Petersen 		break;
6319c6a44287SMartin K. Petersen 
6320c6a44287SMartin K. Petersen 	default:
6321773642d9SDouglas Gilbert 		if (sdebug_dix)
6322f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
6323c6a44287SMartin K. Petersen 		break;
6324c6a44287SMartin K. Petersen 	}
6325c6a44287SMartin K. Petersen 
6326f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
6327c6a44287SMartin K. Petersen 
6328f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
6329c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
6330f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
6331f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
6332f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
6333f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
6334f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
6335f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
6336f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
6337c6a44287SMartin K. Petersen 
6338773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
6339c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
6340c6a44287SMartin K. Petersen 	else
6341c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
6342c6a44287SMartin K. Petersen 
6343773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
6344773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
6345c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
6346c4837394SDouglas Gilbert 		sdebug_statistics = true;
63471da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
63481da177e4SLinus Torvalds 	if (error) {
6349c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
63501da177e4SLinus Torvalds 		error = -ENODEV;
63511da177e4SLinus Torvalds 		scsi_host_put(hpnt);
635287c715dcSDouglas Gilbert 	} else {
63531da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
635487c715dcSDouglas Gilbert 	}
63551da177e4SLinus Torvalds 
63561da177e4SLinus Torvalds 	return error;
63571da177e4SLinus Torvalds }
63581da177e4SLinus Torvalds 
63591da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
63601da177e4SLinus Torvalds {
63611da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
63628b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
63631da177e4SLinus Torvalds 
63641da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
63651da177e4SLinus Torvalds 
63661da177e4SLinus Torvalds 	if (!sdbg_host) {
6367c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
63681da177e4SLinus Torvalds 		return -ENODEV;
63691da177e4SLinus Torvalds 	}
63701da177e4SLinus Torvalds 
63711da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
63721da177e4SLinus Torvalds 
63738b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
63748b40228fSFUJITA Tomonori 				 dev_list) {
63751da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
63761da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
63771da177e4SLinus Torvalds 	}
63781da177e4SLinus Torvalds 
63791da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
63801da177e4SLinus Torvalds 	return 0;
63811da177e4SLinus Torvalds }
63821da177e4SLinus Torvalds 
63838dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
63848dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
63851da177e4SLinus Torvalds {
63868dea0d02SFUJITA Tomonori 	return 1;
63878dea0d02SFUJITA Tomonori }
63881da177e4SLinus Torvalds 
63898dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
63908dea0d02SFUJITA Tomonori 	.name = "pseudo",
63918dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
63928dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
63938dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
639482069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
63958dea0d02SFUJITA Tomonori };
6396