xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 1442f76d)
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>
42c6a44287SMartin K. Petersen 
43c6a44287SMartin K. Petersen #include <net/checksum.h>
449ff26eefSFUJITA Tomonori 
4544d92694SMartin K. Petersen #include <asm/unaligned.h>
4644d92694SMartin K. Petersen 
479ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
489ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
499ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
501da177e4SLinus Torvalds #include <scsi/scsi_host.h>
511da177e4SLinus Torvalds #include <scsi/scsicam.h>
52a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
53cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
54395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
551da177e4SLinus Torvalds 
56c6a44287SMartin K. Petersen #include "sd.h"
571da177e4SLinus Torvalds #include "scsi_logging.h"
581da177e4SLinus Torvalds 
59773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6080c49563SDouglas Gilbert #define SDEBUG_VERSION "0188"	/* format to fit INQUIRY revision field */
6140d07b52SDouglas Gilbert static const char *sdebug_version_date = "20190125";
62cbf67842SDouglas Gilbert 
63cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
641da177e4SLinus Torvalds 
656f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
66c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
67c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
68c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
691da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
70c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
711da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7222017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
731da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
74c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
759447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27
76cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
77cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
7819c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
7919c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8022017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8122017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
82cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
83cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
84cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8522017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
861da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
876f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
88c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
89c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9022017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
91acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
92acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
93481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
941da177e4SLinus Torvalds 
956f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
966f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
976f3cbf55SDouglas Gilbert 
981da177e4SLinus Torvalds /* Default values for driver parameters */
991da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1001da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1011da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1021da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1031da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1041da177e4SLinus Torvalds  */
1055b94e232SMartin K. Petersen #define DEF_ATO 1
1069b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
107c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1081da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1095b94e232SMartin K. Petersen #define DEF_DIF 0
1105b94e232SMartin K. Petersen #define DEF_DIX 0
1115b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1121da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1135b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1145b94e232SMartin K. Petersen #define DEF_GUARD 0
115cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1165b94e232SMartin K. Petersen #define DEF_LBPU 0
1175b94e232SMartin K. Petersen #define DEF_LBPWS 0
1185b94e232SMartin K. Petersen #define DEF_LBPWS10 0
119be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1205b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
121cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1225b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1231da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1241da177e4SLinus Torvalds #define DEF_OPTS   0
12532c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1265b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
12786e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
128b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
129d986788bSMartin Pitt #define DEF_REMOVABLE false
130760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1315b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1325b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1335b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1356014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1365b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1375b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1385b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
139c2248fc9SDouglas Gilbert #define DEF_STRICT 0
140c4837394SDouglas Gilbert #define DEF_STATISTICS false
141c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14209ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
143c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1441da177e4SLinus Torvalds 
145b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
146b01f6f83SDouglas Gilbert 
147773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
148773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
149773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
150773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
151773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
152773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
153773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
154773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
155773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
156773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
157773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
158773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
159773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
160773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
161773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
162773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1637ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1647382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
165773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
166773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
167773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
168773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
169773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1707ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1717382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1727382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1731da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
174fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1751da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
176773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1776f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
178773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1797382f9d8SDouglas Gilbert  *   - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
1807382f9d8SDouglas Gilbert  *     CMD_ABORT
1811da177e4SLinus Torvalds  *
1827382f9d8SDouglas Gilbert  * When "every_nth" < 0 then after "- every_nth" commands the selected
1837382f9d8SDouglas Gilbert  * error will be injected. The error will be injected on every subsequent
1847382f9d8SDouglas Gilbert  * command until some other action occurs; for example, the user writing
1857382f9d8SDouglas Gilbert  * a new value (other than -1 or 1) to every_nth:
1867382f9d8SDouglas Gilbert  *      echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
1871da177e4SLinus Torvalds  */
1881da177e4SLinus Torvalds 
189cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
190cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
191cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
192cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
193cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
194cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
195cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1960d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
19719c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
198acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
199acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
200acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
201cbf67842SDouglas Gilbert 
202773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2031da177e4SLinus Torvalds  * sector on read commands: */
2041da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20532f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2081da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2091da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2101da177e4SLinus Torvalds 
211c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
212c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
213c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
214c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
215c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
216c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
217c4837394SDouglas Gilbert  */
218c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
219c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
220cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
221cbf67842SDouglas Gilbert 
222fd32119bSDouglas Gilbert #define F_D_IN			1
223fd32119bSDouglas Gilbert #define F_D_OUT			2
224fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
225fd32119bSDouglas Gilbert #define F_D_UNKN		8
226fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
227fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
228fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
229fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
230fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
231fd32119bSDouglas Gilbert #define F_INV_OP		0x200
232fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
233fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
2344f2c8bf6SDouglas Gilbert #define F_SSU_DELAY		0x1000
2354f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY		0x2000
236fd32119bSDouglas Gilbert 
237fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
23846f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
239fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2404f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
241fd32119bSDouglas Gilbert 
242fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
243fd32119bSDouglas Gilbert 
244b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
245fd32119bSDouglas Gilbert 
246fd32119bSDouglas Gilbert 
247fd32119bSDouglas Gilbert struct sdebug_dev_info {
248fd32119bSDouglas Gilbert 	struct list_head dev_list;
249fd32119bSDouglas Gilbert 	unsigned int channel;
250fd32119bSDouglas Gilbert 	unsigned int target;
251fd32119bSDouglas Gilbert 	u64 lun;
252bf476433SChristoph Hellwig 	uuid_t lu_name;
253fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
254fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
255fd32119bSDouglas Gilbert 	atomic_t num_in_q;
256c4837394SDouglas Gilbert 	atomic_t stopped;
257fd32119bSDouglas Gilbert 	bool used;
258fd32119bSDouglas Gilbert };
259fd32119bSDouglas Gilbert 
260fd32119bSDouglas Gilbert struct sdebug_host_info {
261fd32119bSDouglas Gilbert 	struct list_head host_list;
262fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
263fd32119bSDouglas Gilbert 	struct device dev;
264fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
265fd32119bSDouglas Gilbert };
266fd32119bSDouglas Gilbert 
267fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
268fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
269fd32119bSDouglas Gilbert 
27010bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
27110bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
27210bde980SDouglas Gilbert 
273fd32119bSDouglas Gilbert struct sdebug_defer {
274fd32119bSDouglas Gilbert 	struct hrtimer hrt;
275fd32119bSDouglas Gilbert 	struct execute_work ew;
276c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
277c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
278c4837394SDouglas Gilbert 	int issuing_cpu;
27910bde980SDouglas Gilbert 	bool init_hrt;
28010bde980SDouglas Gilbert 	bool init_wq;
2817382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
28210bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
283fd32119bSDouglas Gilbert };
284fd32119bSDouglas Gilbert 
285fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
286c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
287c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
288c4837394SDouglas Gilbert 	 */
289fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
290fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
291c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
292c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
293c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
294c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
295c4837394SDouglas Gilbert 	unsigned int inj_short:1;
2967ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
2977382f9d8SDouglas Gilbert 	unsigned int inj_cmd_abort:1;
298fd32119bSDouglas Gilbert };
299fd32119bSDouglas Gilbert 
300c4837394SDouglas Gilbert struct sdebug_queue {
301c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
302c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
303c4837394SDouglas Gilbert 	spinlock_t qc_lock;
304c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
305fd32119bSDouglas Gilbert };
306fd32119bSDouglas Gilbert 
307c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
308c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
309c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
310c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
311c4837394SDouglas Gilbert 
312fd32119bSDouglas Gilbert struct opcode_info_t {
313b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
314b01f6f83SDouglas Gilbert 				/* for terminating element */
315fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
316fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
317fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
318fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
319fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3209a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3219a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
322fd32119bSDouglas Gilbert };
323fd32119bSDouglas Gilbert 
324fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
325c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
326c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
327c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
328c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
329c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
330c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
331c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
332c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
333c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
334c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
335c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
336c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
337c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
33846f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
33946f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
340c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
341c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
342c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
343481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
344c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
345c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
346c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
347c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
348c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
349c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
350c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
351c208556aSBart Van Assche 	SDEB_I_WRITE_BUFFER = 25,
352c208556aSBart Van Assche 	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
353c208556aSBart Van Assche 	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
354c208556aSBart Van Assche 	SDEB_I_COMP_WRITE = 28,
355c208556aSBart Van Assche 	SDEB_I_LAST_ELEMENT = 29,	/* keep this last (previous + 1) */
356c2248fc9SDouglas Gilbert };
357c2248fc9SDouglas Gilbert 
358c4837394SDouglas Gilbert 
359c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
360c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
361c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
362c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
363c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
364c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
365c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
366c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
367c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
368c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
369c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
370c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
371c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
372c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
373c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
374c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
375c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
376c208556aSBart Van Assche 	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
377c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
378c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
379fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
380c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
383c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
384c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
385c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
38680c49563SDouglas Gilbert 	0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
38746f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
388c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
389c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
390c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
39146f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
39246f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
393c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
394c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
395c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
396c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 0, 0,
399c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400c2248fc9SDouglas Gilbert };
401c2248fc9SDouglas Gilbert 
40280c49563SDouglas Gilbert /*
40380c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
40480c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
40580c49563SDouglas Gilbert  * command completion, they can mask their return value with
40680c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
40780c49563SDouglas Gilbert  */
40880c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
40980c49563SDouglas Gilbert 
410c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
411c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
412c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
413c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
414c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
415c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
416c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
417c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
418c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
419481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
420c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
421c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
422c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
423c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
424c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
42538d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
42638d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
427c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
428c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
42938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
430acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
43180c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
432c2248fc9SDouglas Gilbert 
43346f64e70SDouglas Gilbert /*
43446f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
43546f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
43646f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
43746f64e70SDouglas Gilbert  */
43846f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
439c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
440c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
441c2248fc9SDouglas Gilbert };
442c2248fc9SDouglas Gilbert 
44346f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
444c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
445c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
446c2248fc9SDouglas Gilbert };
447c2248fc9SDouglas Gilbert 
44846f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
44946f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
450b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
451c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
45246f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
453c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
45446f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
455b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
456c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
457c2248fc9SDouglas Gilbert };
458c2248fc9SDouglas Gilbert 
45946f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
46046f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
46146f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
46246f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
46346f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
46446f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
46546f64e70SDouglas Gilbert 		   0, 0, 0} },
46646f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
46746f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
46846f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
469c2248fc9SDouglas Gilbert };
470c2248fc9SDouglas Gilbert 
47146f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
472c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
473c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47446f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
475c2248fc9SDouglas Gilbert };
476c2248fc9SDouglas Gilbert 
47746f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
47846f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
479b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
480c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
481481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
482481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
483481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
484c2248fc9SDouglas Gilbert };
485c2248fc9SDouglas Gilbert 
48646f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
48738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
488c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
48946f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
49038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
491c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
49246f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
493c2248fc9SDouglas Gilbert };
494c2248fc9SDouglas Gilbert 
49546f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
49646f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
497c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49846f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
499c2248fc9SDouglas Gilbert };
500c2248fc9SDouglas Gilbert 
50146f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
502c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
503c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
504c2248fc9SDouglas Gilbert };
505c2248fc9SDouglas Gilbert 
50646f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
507c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
508c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
509c2248fc9SDouglas Gilbert };
510c2248fc9SDouglas Gilbert 
51180c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5124f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
51380c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51480c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
51580c49563SDouglas Gilbert };
51680c49563SDouglas Gilbert 
517c2248fc9SDouglas Gilbert 
518c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
519c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
520c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
521c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
522c2248fc9SDouglas Gilbert /* 0 */
52346f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
524c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52546f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
526c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
528c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
52946f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
530c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
531c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
532c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
533c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53446f64e70SDouglas Gilbert /* 5 */
53546f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
53646f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
53746f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
53846f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
53946f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
54046f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54146f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
542c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
543c2248fc9SDouglas Gilbert 	     0, 0, 0} },
54446f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
545c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
546c2248fc9SDouglas Gilbert 	     0, 0} },
54746f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
54846f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
54946f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
550c2248fc9SDouglas Gilbert /* 10 */
55146f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
55246f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
55346f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55480c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
5554f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
556c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
55746f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
55846f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
55946f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56046f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
561481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
562481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
563481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
56446f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
56546f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
56646f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
56746f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
56846f64e70SDouglas Gilbert /* 15 */
569c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
570c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
57146f64e70SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
572f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
573f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
57446f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
57546f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
57646f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
57746f64e70SDouglas Gilbert 	     0xff, 0xff} },
57846f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
57946f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
580c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
581c2248fc9SDouglas Gilbert 	     0} },
58246f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
58346f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
584c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
585c2248fc9SDouglas Gilbert 	     0} },
586c2248fc9SDouglas Gilbert /* 20 */
587f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
588f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
589c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
590c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
591c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
592c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
593c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
594c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
59546f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
596b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
59746f64e70SDouglas Gilbert /* 25 */
598acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
599acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
600acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
60146f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
60246f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
60346f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
60446f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
6054f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
60680c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
607b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
60880c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
60946f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
610c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
611b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
612c2248fc9SDouglas Gilbert 
613c208556aSBart Van Assche /* 29 */
614c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
615c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
616c2248fc9SDouglas Gilbert };
617c2248fc9SDouglas Gilbert 
618773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
619773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
6209b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
621c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
622773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
623773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
624773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
625773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
626773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
627773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
628773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
629773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
630773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
631c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
632d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
633d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
634cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
635c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
636773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
637773642d9SDouglas Gilbert static int sdebug_no_uld;
638773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
639773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
640773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
641773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
642773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
64386e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
644b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
645773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
646773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
647773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
648773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
649773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
650773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
651773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
652773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
653773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
654773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
655773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
656773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
657773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
65809ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
659773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
660773642d9SDouglas Gilbert static bool sdebug_clustering;
661773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
662773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
663817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
664773642d9SDouglas Gilbert static bool sdebug_verbose;
665f46eb0e9SDouglas Gilbert static bool have_dif_prot;
6664f2c8bf6SDouglas Gilbert static bool write_since_sync;
667c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
6689447b6ceSMartin K. Petersen static bool sdebug_wp;
6691da177e4SLinus Torvalds 
670c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6711da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6741da177e4SLinus Torvalds    may still need them */
6751da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6761da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6771da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6801da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6836ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
68444d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6851da177e4SLinus Torvalds 
68644d92694SMartin K. Petersen static unsigned long map_size;
687cbf67842SDouglas Gilbert static int num_aborts;
688cbf67842SDouglas Gilbert static int num_dev_resets;
689cbf67842SDouglas Gilbert static int num_target_resets;
690cbf67842SDouglas Gilbert static int num_bus_resets;
691cbf67842SDouglas Gilbert static int num_host_resets;
692c6a44287SMartin K. Petersen static int dix_writes;
693c6a44287SMartin K. Petersen static int dix_reads;
694c6a44287SMartin K. Petersen static int dif_errors;
6951da177e4SLinus Torvalds 
696c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
697c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
698fd32119bSDouglas Gilbert 
6991da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
7001da177e4SLinus Torvalds 
701cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
702cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
7071da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
7081da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
7091da177e4SLinus Torvalds };
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds static const int check_condition_result =
7121da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
7131da177e4SLinus Torvalds 
714c6a44287SMartin K. Petersen static const int illegal_condition_result =
715c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
716c6a44287SMartin K. Petersen 
717cbf67842SDouglas Gilbert static const int device_qfull_result =
718cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
719cbf67842SDouglas Gilbert 
720fd32119bSDouglas Gilbert 
721760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
722760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
723760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
724760f3b03SDouglas Gilbert  */
725760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
726fd32119bSDouglas Gilbert {
727fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
728fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
729fd32119bSDouglas Gilbert }
730c65b1445SDouglas Gilbert 
73140d07b52SDouglas Gilbert static void *lba2fake_store(unsigned long long lba)
73214faa944SAkinobu Mita {
73314faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
73414faa944SAkinobu Mita 
735773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
73614faa944SAkinobu Mita }
73714faa944SAkinobu Mita 
7386ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
73914faa944SAkinobu Mita {
74049413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
74114faa944SAkinobu Mita 
74214faa944SAkinobu Mita 	return dif_storep + sector;
74314faa944SAkinobu Mita }
74414faa944SAkinobu Mita 
7458dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7468dea0d02SFUJITA Tomonori {
7478dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7488dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7498dea0d02SFUJITA Tomonori 
7508dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7518dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7528dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7538dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
754773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
755773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7568dea0d02SFUJITA Tomonori 		else
757773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
758773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
759f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7608dea0d02SFUJITA Tomonori 	}
7618dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7628dea0d02SFUJITA Tomonori }
7638dea0d02SFUJITA Tomonori 
76422017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
76522017ed2SDouglas Gilbert 
76622017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
767fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
768fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
76922017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
77022017ed2SDouglas Gilbert {
77122017ed2SDouglas Gilbert 	unsigned char *sbuff;
77222017ed2SDouglas Gilbert 	u8 sks[4];
77322017ed2SDouglas Gilbert 	int sl, asc;
77422017ed2SDouglas Gilbert 
77522017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
77622017ed2SDouglas Gilbert 	if (!sbuff) {
77722017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
77822017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
77922017ed2SDouglas Gilbert 		return;
78022017ed2SDouglas Gilbert 	}
78122017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
78222017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
783773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
78422017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
78522017ed2SDouglas Gilbert 	sks[0] = 0x80;
78622017ed2SDouglas Gilbert 	if (c_d)
78722017ed2SDouglas Gilbert 		sks[0] |= 0x40;
78822017ed2SDouglas Gilbert 	if (in_bit >= 0) {
78922017ed2SDouglas Gilbert 		sks[0] |= 0x8;
79022017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
79122017ed2SDouglas Gilbert 	}
79222017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
793773642d9SDouglas Gilbert 	if (sdebug_dsense) {
79422017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
79522017ed2SDouglas Gilbert 		sbuff[7] = sl;
79622017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
79722017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
79822017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
79922017ed2SDouglas Gilbert 	} else
80022017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
801773642d9SDouglas Gilbert 	if (sdebug_verbose)
80222017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
80322017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
80422017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
80522017ed2SDouglas Gilbert }
80622017ed2SDouglas Gilbert 
807cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
8088dea0d02SFUJITA Tomonori {
8098dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
8108dea0d02SFUJITA Tomonori 
811cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
812cbf67842SDouglas Gilbert 	if (!sbuff) {
813cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
814cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
815cbf67842SDouglas Gilbert 		return;
816cbf67842SDouglas Gilbert 	}
817cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
8188dea0d02SFUJITA Tomonori 
819773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
8208dea0d02SFUJITA Tomonori 
821773642d9SDouglas Gilbert 	if (sdebug_verbose)
822cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
823cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
824cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
8258dea0d02SFUJITA Tomonori }
8261da177e4SLinus Torvalds 
827fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
82822017ed2SDouglas Gilbert {
82922017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
83022017ed2SDouglas Gilbert }
83122017ed2SDouglas Gilbert 
8326f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
8336f4e626fSNathan Chancellor 			    void __user *arg)
8341da177e4SLinus Torvalds {
835773642d9SDouglas Gilbert 	if (sdebug_verbose) {
836cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
837cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
838cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
839cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
840cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
841cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
842cbf67842SDouglas Gilbert 				    __func__);
843cbf67842SDouglas Gilbert 		else
844cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
845cbf67842SDouglas Gilbert 				    __func__, cmd);
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds 	return -EINVAL;
8481da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8491da177e4SLinus Torvalds }
8501da177e4SLinus Torvalds 
8519b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8529b760fd8SDouglas Gilbert {
8539b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8549b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8559b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8569b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8579b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8589b760fd8SDouglas Gilbert 		break;
8599b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8609b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8619b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8629b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8639b760fd8SDouglas Gilbert 		break;
8649b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8659b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8669b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8679b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8689b760fd8SDouglas Gilbert 		break;
8699b760fd8SDouglas Gilbert 	case 16:
8709b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8719b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8729b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8739b760fd8SDouglas Gilbert 		break;
8749b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8759b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8769b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8779b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8789b760fd8SDouglas Gilbert 		break;
8799b760fd8SDouglas Gilbert 	default:
8809b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8819b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8829b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8839b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8849b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8859b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8869b760fd8SDouglas Gilbert 		break;
8879b760fd8SDouglas Gilbert 	}
8889b760fd8SDouglas Gilbert }
8899b760fd8SDouglas Gilbert 
8909b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8919b760fd8SDouglas Gilbert {
8929b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8939b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
8949b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
8959b760fd8SDouglas Gilbert 
8969b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
8979b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8989b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
8999b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
9009b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
9019b760fd8SDouglas Gilbert 		}
9029b760fd8SDouglas Gilbert 	}
9039b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
9049b760fd8SDouglas Gilbert }
9059b760fd8SDouglas Gilbert 
90619c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
90719c8ead7SEwan D. Milne {
90819c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
90919c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
91019c8ead7SEwan D. Milne 
91119c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
91219c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
91319c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
91419c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
91519c8ead7SEwan D. Milne 			    (devip->target == dp->target))
91619c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
91719c8ead7SEwan D. Milne 		}
91819c8ead7SEwan D. Milne 	}
91919c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
92019c8ead7SEwan D. Milne }
92119c8ead7SEwan D. Milne 
922f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
9231da177e4SLinus Torvalds {
924cbf67842SDouglas Gilbert 	int k;
925cbf67842SDouglas Gilbert 
926cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
927cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
928cbf67842SDouglas Gilbert 		const char *cp = NULL;
929cbf67842SDouglas Gilbert 
930cbf67842SDouglas Gilbert 		switch (k) {
931cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
932f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
933f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
934773642d9SDouglas Gilbert 			if (sdebug_verbose)
935cbf67842SDouglas Gilbert 				cp = "power on reset";
936cbf67842SDouglas Gilbert 			break;
937cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
938f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
939f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
940773642d9SDouglas Gilbert 			if (sdebug_verbose)
941cbf67842SDouglas Gilbert 				cp = "bus reset";
942cbf67842SDouglas Gilbert 			break;
943cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
944f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
945f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
946773642d9SDouglas Gilbert 			if (sdebug_verbose)
947cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
948cbf67842SDouglas Gilbert 			break;
9490d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
950f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
951f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
952773642d9SDouglas Gilbert 			if (sdebug_verbose)
9530d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
954f49accf1SEwan D. Milne 			break;
955acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
956f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
957b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
958b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
959773642d9SDouglas Gilbert 			if (sdebug_verbose)
960acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
961acafd0b9SEwan D. Milne 			break;
962acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
963f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
964acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
965acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
966773642d9SDouglas Gilbert 			if (sdebug_verbose)
967acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
968acafd0b9SEwan D. Milne 			break;
96919c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
97019c8ead7SEwan D. Milne 			/*
97119c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
97219c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
97319c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
97419c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
975773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
97619c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
97719c8ead7SEwan D. Milne 			 */
978773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
97919c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
980f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
98119c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
98219c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
983773642d9SDouglas Gilbert 			if (sdebug_verbose)
98419c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
98519c8ead7SEwan D. Milne 			break;
986cbf67842SDouglas Gilbert 		default:
987773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
988773642d9SDouglas Gilbert 			if (sdebug_verbose)
989cbf67842SDouglas Gilbert 				cp = "unknown";
990cbf67842SDouglas Gilbert 			break;
991cbf67842SDouglas Gilbert 		}
992cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
993773642d9SDouglas Gilbert 		if (sdebug_verbose)
994f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
995cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
996cbf67842SDouglas Gilbert 				   my_name, cp);
9971da177e4SLinus Torvalds 		return check_condition_result;
9981da177e4SLinus Torvalds 	}
9991da177e4SLinus Torvalds 	return 0;
10001da177e4SLinus Torvalds }
10011da177e4SLinus Torvalds 
1002fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
10031da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
10041da177e4SLinus Torvalds 				int arr_len)
10051da177e4SLinus Torvalds {
100621a61829SFUJITA Tomonori 	int act_len;
1007ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
10081da177e4SLinus Torvalds 
1009072d0bb3SFUJITA Tomonori 	if (!sdb->length)
10101da177e4SLinus Torvalds 		return 0;
1011ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1012773642d9SDouglas Gilbert 		return DID_ERROR << 16;
101321a61829SFUJITA Tomonori 
101421a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
101521a61829SFUJITA Tomonori 				      arr, arr_len);
101642d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
101721a61829SFUJITA Tomonori 
10181da177e4SLinus Torvalds 	return 0;
10191da177e4SLinus Torvalds }
10201da177e4SLinus Torvalds 
1021fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1022fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1023fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1024fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1025fb0cc8d1SDouglas Gilbert  */
1026fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1027fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1028fb0cc8d1SDouglas Gilbert {
10299237f04eSDamien Le Moal 	unsigned int act_len, n;
1030ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1031fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1032fb0cc8d1SDouglas Gilbert 
1033fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1034fb0cc8d1SDouglas Gilbert 		return 0;
1035ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1036fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1037fb0cc8d1SDouglas Gilbert 
1038fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1039fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1040fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
104142d387beSBart Van Assche 		 __func__, off_dst, scsi_bufflen(scp), act_len,
104242d387beSBart Van Assche 		 scsi_get_resid(scp));
10439237f04eSDamien Le Moal 	n = scsi_bufflen(scp) - (off_dst + act_len);
104442d387beSBart Van Assche 	scsi_set_resid(scp, min(scsi_get_resid(scp), n));
1045fb0cc8d1SDouglas Gilbert 	return 0;
1046fb0cc8d1SDouglas Gilbert }
1047fb0cc8d1SDouglas Gilbert 
1048fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1049fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1050fb0cc8d1SDouglas Gilbert  */
10511da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
105221a61829SFUJITA Tomonori 			       int arr_len)
10531da177e4SLinus Torvalds {
105421a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10551da177e4SLinus Torvalds 		return 0;
1056ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
10571da177e4SLinus Torvalds 		return -1;
105821a61829SFUJITA Tomonori 
105921a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 
1063e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1064e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10659b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10661b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10671b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10681b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10691b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10701da177e4SLinus Torvalds 
1071cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1072760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10735a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
107409ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1075bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10761da177e4SLinus Torvalds {
1077c65b1445SDouglas Gilbert 	int num, port_a;
1078c65b1445SDouglas Gilbert 	char b[32];
10791da177e4SLinus Torvalds 
1080c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10811da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10821da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10831da177e4SLinus Torvalds 	arr[1] = 0x1;
10841da177e4SLinus Torvalds 	arr[2] = 0x0;
1085e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1086e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10871da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10881da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10891da177e4SLinus Torvalds 	arr[3] = num;
10901da177e4SLinus Torvalds 	num += 4;
1091c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
109209ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
109309ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
109409ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
109509ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
109609ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
109709ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
109809ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
109909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110009ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
110109ba24c1SDouglas Gilbert 			num += 16;
110209ba24c1SDouglas Gilbert 		} else {
11031b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1104c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1105c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1106c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1107c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
11081b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1109773642d9SDouglas Gilbert 			num += 8;
111009ba24c1SDouglas Gilbert 		}
1111c65b1445SDouglas Gilbert 		/* Target relative port number */
1112c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1113c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1114c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1115c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1116c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1117c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1118c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1119c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1120c65b1445SDouglas Gilbert 	}
11211b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1122c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1123c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1124c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1125c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11261b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1127773642d9SDouglas Gilbert 	num += 8;
11281b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
11295a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11305a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11315a09e398SHannes Reinecke 	arr[num++] = 0x0;
11325a09e398SHannes Reinecke 	arr[num++] = 0x4;
11335a09e398SHannes Reinecke 	arr[num++] = 0;
11345a09e398SHannes Reinecke 	arr[num++] = 0;
1135773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1136773642d9SDouglas Gilbert 	num += 2;
11371b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1138c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1139c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1140c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1141c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11421b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1143773642d9SDouglas Gilbert 	num += 8;
1144c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1145c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1146c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1147c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1148c65b1445SDouglas Gilbert 	arr[num++] = 24;
11491b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1150c65b1445SDouglas Gilbert 	num += 12;
1151c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1152c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1153c65b1445SDouglas Gilbert 	num += 8;
1154c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1155c65b1445SDouglas Gilbert 	num += 4;
1156c65b1445SDouglas Gilbert 	return num;
1157c65b1445SDouglas Gilbert }
1158c65b1445SDouglas Gilbert 
1159c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1160c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1161c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1162c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1163c65b1445SDouglas Gilbert };
1164c65b1445SDouglas Gilbert 
1165cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1166760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1167c65b1445SDouglas Gilbert {
1168c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1169c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1170c65b1445SDouglas Gilbert }
1171c65b1445SDouglas Gilbert 
1172cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1173760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1174c65b1445SDouglas Gilbert {
1175c65b1445SDouglas Gilbert 	int num = 0;
1176c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1177c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1178c65b1445SDouglas Gilbert 	int plen, olen;
1179c65b1445SDouglas Gilbert 
1180c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1181c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1182c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1183c65b1445SDouglas Gilbert 	olen = strlen(na1);
1184c65b1445SDouglas Gilbert 	plen = olen + 1;
1185c65b1445SDouglas Gilbert 	if (plen % 4)
1186c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1187c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1188c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1189c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1190c65b1445SDouglas Gilbert 	num += plen;
1191c65b1445SDouglas Gilbert 
1192c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1193c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1194c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1195c65b1445SDouglas Gilbert 	olen = strlen(na2);
1196c65b1445SDouglas Gilbert 	plen = olen + 1;
1197c65b1445SDouglas Gilbert 	if (plen % 4)
1198c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1199c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1200c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1201c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1202c65b1445SDouglas Gilbert 	num += plen;
1203c65b1445SDouglas Gilbert 
1204c65b1445SDouglas Gilbert 	return num;
1205c65b1445SDouglas Gilbert }
1206c65b1445SDouglas Gilbert 
1207c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1208760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1209c65b1445SDouglas Gilbert {
1210c65b1445SDouglas Gilbert 	int num = 0;
1211c65b1445SDouglas Gilbert 	int port_a, port_b;
1212c65b1445SDouglas Gilbert 
1213c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1214c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1215c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1216c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1217c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1218c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1219c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1220c65b1445SDouglas Gilbert 	num += 6;
1221c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1222c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1223c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1224c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1225c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1226c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1227c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12281b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1229773642d9SDouglas Gilbert 	num += 8;
1230c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1231c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1232c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1233c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1234c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1235c65b1445SDouglas Gilbert 	num += 6;
1236c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1237c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1238c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1239c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1240c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1241c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1242c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12431b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1244773642d9SDouglas Gilbert 	num += 8;
1245c65b1445SDouglas Gilbert 
1246c65b1445SDouglas Gilbert 	return num;
1247c65b1445SDouglas Gilbert }
1248c65b1445SDouglas Gilbert 
1249c65b1445SDouglas Gilbert 
1250c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1251c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1252c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1253c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1254c65b1445SDouglas Gilbert '1','2','3','4',
1255c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1256c65b1445SDouglas Gilbert 0xec,0,0,0,
1257c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1258c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1259c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1260c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1261c65b1445SDouglas Gilbert 0x53,0x41,
1262c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1263c65b1445SDouglas Gilbert 0x20,0x20,
1264c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1265c65b1445SDouglas Gilbert 0x10,0x80,
1266c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1267c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1268c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1269c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1270c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1271c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1272c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1273c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1274c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1275c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1276c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1277c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1278c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1279c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1280c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1281c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1282c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1283c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1284c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1285c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1286c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1287c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1288c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1289c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1290c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1291c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1292c65b1445SDouglas Gilbert };
1293c65b1445SDouglas Gilbert 
1294cbf67842SDouglas Gilbert /* ATA Information VPD page */
1295760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1296c65b1445SDouglas Gilbert {
1297c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1298c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1299c65b1445SDouglas Gilbert }
1300c65b1445SDouglas Gilbert 
1301c65b1445SDouglas Gilbert 
1302c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
13031e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
13041e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13051e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13061e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1307c65b1445SDouglas Gilbert };
1308c65b1445SDouglas Gilbert 
1309cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1310760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1311c65b1445SDouglas Gilbert {
1312ea61fca5SMartin K. Petersen 	unsigned int gran;
1313ea61fca5SMartin K. Petersen 
1314c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1315e308b3d1SMartin K. Petersen 
1316e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
131786e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
131886e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
131986e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
132086e6828aSLukas Herbolt 	else
1321773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1322773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1323e308b3d1SMartin K. Petersen 
1324e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1325773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1326773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
132744d92694SMartin K. Petersen 
1328e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1329773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1330e308b3d1SMartin K. Petersen 
1331773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1332e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1333773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1334e308b3d1SMartin K. Petersen 
1335e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1336773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
133744d92694SMartin K. Petersen 	}
133844d92694SMartin K. Petersen 
1339e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1340773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1341773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
134244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
134344d92694SMartin K. Petersen 	}
134444d92694SMartin K. Petersen 
1345e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1346773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13476014759cSMartin K. Petersen 
13485b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1349773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13505b94e232SMartin K. Petersen 
13515b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
135244d92694SMartin K. Petersen 
1353c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13541da177e4SLinus Torvalds }
13551da177e4SLinus Torvalds 
13561e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1357760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1358eac6e8e4SMatthew Wilcox {
1359eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1360eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13611e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13621e49f785SDouglas Gilbert 	arr[2] = 0;
13631e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1364eac6e8e4SMatthew Wilcox 
1365eac6e8e4SMatthew Wilcox 	return 0x3c;
1366eac6e8e4SMatthew Wilcox }
13671da177e4SLinus Torvalds 
1368760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1369760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13706014759cSMartin K. Petersen {
13713f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13726014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1373773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13746014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1375773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13766014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1377773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13785b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1379760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1380760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1381760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1382760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1383760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13843f0bc3b3SMartin K. Petersen 	return 0x4;
13856014759cSMartin K. Petersen }
13866014759cSMartin K. Petersen 
13871da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1388c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13891da177e4SLinus Torvalds 
1390c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13911da177e4SLinus Torvalds {
13921da177e4SLinus Torvalds 	unsigned char pq_pdt;
13935a09e398SHannes Reinecke 	unsigned char *arr;
139401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
13955a09e398SHannes Reinecke 	int alloc_len, n, ret;
1396760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
13971da177e4SLinus Torvalds 
1398773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
13996f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
14006f3cbf55SDouglas Gilbert 	if (! arr)
14016f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1402760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1403b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1404c2248fc9SDouglas Gilbert 	if (have_wlun)
1405b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1406b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1407b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1408c65b1445SDouglas Gilbert 	else
1409773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
14101da177e4SLinus Torvalds 	arr[0] = pq_pdt;
14111da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
141222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
14135a09e398SHannes Reinecke 		kfree(arr);
14141da177e4SLinus Torvalds 		return check_condition_result;
14151da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
14165a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1417c65b1445SDouglas Gilbert 		char lu_id_str[6];
1418c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
14191da177e4SLinus Torvalds 
14205a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
14215a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1422b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
142323183910SDouglas Gilbert 			host_no = 0;
1424c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1425c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1426c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1427c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1428c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
14291da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1430c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1431c65b1445SDouglas Gilbert 			n = 4;
1432c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1433c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1434c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1435c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1436c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1437c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1438c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1439c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1440760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1441c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1442760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1443760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1444760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1445760f3b03SDouglas Gilbert 			}
1446c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14471da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1448c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14491da177e4SLinus Torvalds 			arr[3] = len;
1450c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14511da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1452c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1453760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14545a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
145509ba24c1SDouglas Gilbert 						lu_id_str, len,
145609ba24c1SDouglas Gilbert 						&devip->lu_name);
1457c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1458c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1459760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1460c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1461c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1462760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1463c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1464c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1465c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14668475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1467c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1468760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1469c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1470c6a44287SMartin K. Petersen 			else
1471c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1472c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1473c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1474c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1475c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1476c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1477c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1478c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1479c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1480c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1481c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1482760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1483760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1484c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1485760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1486773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1487760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1488c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1489760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1490760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1491eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1492760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1493760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14946014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1495760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
14961da177e4SLinus Torvalds 		} else {
149722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
14985a09e398SHannes Reinecke 			kfree(arr);
14991da177e4SLinus Torvalds 			return check_condition_result;
15001da177e4SLinus Torvalds 		}
1501773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
15025a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1503c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
15045a09e398SHannes Reinecke 		kfree(arr);
15055a09e398SHannes Reinecke 		return ret;
15061da177e4SLinus Torvalds 	}
15071da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1508773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1509773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
15101da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
15111da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1512f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1513b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
151470bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1515c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
15161da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1517c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1518e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1519e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1520e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
15219b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
15229b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
15231da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1524760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1525760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1526c65b1445SDouglas Gilbert 	n = 62;
1527760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1528760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1529760f3b03SDouglas Gilbert 		n += 2;
1530760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1531760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1532760f3b03SDouglas Gilbert 		n += 2;
15331da177e4SLinus Torvalds 	}
1534760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15355a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15361da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
15375a09e398SHannes Reinecke 	kfree(arr);
15385a09e398SHannes Reinecke 	return ret;
15391da177e4SLinus Torvalds }
15401da177e4SLinus Torvalds 
1541fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1542fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1543fd32119bSDouglas Gilbert 
15441da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
15451da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
15461da177e4SLinus Torvalds {
15471da177e4SLinus Torvalds 	unsigned char *sbuff;
154801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1549cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15502492fc09STomas Winkler 	bool dsense;
15511da177e4SLinus Torvalds 	int len = 18;
15521da177e4SLinus Torvalds 
1553c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1554c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1555cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1556c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1557c2248fc9SDouglas Gilbert 		if (dsense) {
1558c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1559c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1560c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1561c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1562c2248fc9SDouglas Gilbert 			len = 8;
1563c65b1445SDouglas Gilbert 		} else {
1564c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1565c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1566c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1567c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1568c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1569c65b1445SDouglas Gilbert 		}
1570c65b1445SDouglas Gilbert 	} else {
1571cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1572773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1573c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1574c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1575c2248fc9SDouglas Gilbert 			if (dsense) {
1576c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1577c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1578c2248fc9SDouglas Gilbert 				len = 8;
1579c2248fc9SDouglas Gilbert 			} else {
1580c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1581c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1582c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1583c2248fc9SDouglas Gilbert 			}
1584c2248fc9SDouglas Gilbert 		} else if (dsense) {
1585c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15861da177e4SLinus Torvalds 			arr[0] = 0x72;
15871da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15881da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15891da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15901da177e4SLinus Torvalds 			len = 8;
1591c2248fc9SDouglas Gilbert 		} else {
1592c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1593c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1594c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1595c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1596c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1597c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1598c65b1445SDouglas Gilbert 		}
1599c2248fc9SDouglas Gilbert 
1600c65b1445SDouglas Gilbert 	}
1601cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
16021da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
16031da177e4SLinus Torvalds }
16041da177e4SLinus Torvalds 
1605c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1606c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1607c65b1445SDouglas Gilbert {
160801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1609c4837394SDouglas Gilbert 	int power_cond, stop;
16104f2c8bf6SDouglas Gilbert 	bool changing;
1611c65b1445SDouglas Gilbert 
1612c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1613c65b1445SDouglas Gilbert 	if (power_cond) {
161422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1615c65b1445SDouglas Gilbert 		return check_condition_result;
1616c65b1445SDouglas Gilbert 	}
1617c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
16184f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1619c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
16204f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
16214f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
16224f2c8bf6SDouglas Gilbert 	else
16234f2c8bf6SDouglas Gilbert 		return 0;
1624c65b1445SDouglas Gilbert }
1625c65b1445SDouglas Gilbert 
162628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
162728898873SFUJITA Tomonori {
1628773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1629773642d9SDouglas Gilbert 
1630773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1631773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1632773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
163328898873SFUJITA Tomonori 	else
163428898873SFUJITA Tomonori 		return sdebug_store_sectors;
163528898873SFUJITA Tomonori }
163628898873SFUJITA Tomonori 
16371da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16381da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
16391da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
16401da177e4SLinus Torvalds {
16411da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1642c65b1445SDouglas Gilbert 	unsigned int capac;
16431da177e4SLinus Torvalds 
1644c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
164528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
16461da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1647c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1648c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1649773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1650773642d9SDouglas Gilbert 	} else
1651773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1652773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16531da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16541da177e4SLinus Torvalds }
16551da177e4SLinus Torvalds 
1656c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1657c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1658c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1659c65b1445SDouglas Gilbert {
166001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1661c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1662773642d9SDouglas Gilbert 	int alloc_len;
1663c65b1445SDouglas Gilbert 
1664773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1665c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
166628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1667c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1668773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1669773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1670773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1671773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
167244d92694SMartin K. Petersen 
1673be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16745b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1675760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1676760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1677760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1678760f3b03SDouglas Gilbert 		 */
1679760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1680760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1681be1dd78dSEric Sandeen 	}
168244d92694SMartin K. Petersen 
1683773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1684c6a44287SMartin K. Petersen 
1685760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1686773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1687c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1688c6a44287SMartin K. Petersen 	}
1689c6a44287SMartin K. Petersen 
1690c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1691c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1692c65b1445SDouglas Gilbert }
1693c65b1445SDouglas Gilbert 
16945a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
16955a09e398SHannes Reinecke 
16965a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
16975a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
16985a09e398SHannes Reinecke {
169901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
17005a09e398SHannes Reinecke 	unsigned char *arr;
17015a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
17025a09e398SHannes Reinecke 	int n, ret, alen, rlen;
17035a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
17045a09e398SHannes Reinecke 
1705773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
17066f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
17076f3cbf55SDouglas Gilbert 	if (! arr)
17086f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
17095a09e398SHannes Reinecke 	/*
17105a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
17115a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
17125a09e398SHannes Reinecke 	 * So we create two port groups with one port each
17135a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
17145a09e398SHannes Reinecke 	 */
17155a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
17165a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
17175a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
17185a09e398SHannes Reinecke 			(devip->channel & 0x7f);
17195a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
17205a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
17215a09e398SHannes Reinecke 
17225a09e398SHannes Reinecke 	/*
17235a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
17245a09e398SHannes Reinecke 	 */
17255a09e398SHannes Reinecke 	n = 4;
1726b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
17275a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
17285a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
17295a09e398SHannes Reinecke 	} else {
17305a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1731773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
17325a09e398SHannes Reinecke 	}
1733773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1734773642d9SDouglas Gilbert 	n += 2;
17355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17385a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1741773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1742773642d9SDouglas Gilbert 	n += 2;
17435a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
17445a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1745773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1746773642d9SDouglas Gilbert 	n += 2;
17475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17505a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1753773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1754773642d9SDouglas Gilbert 	n += 2;
17555a09e398SHannes Reinecke 
17565a09e398SHannes Reinecke 	rlen = n - 4;
1757773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17585a09e398SHannes Reinecke 
17595a09e398SHannes Reinecke 	/*
17605a09e398SHannes Reinecke 	 * Return the smallest value of either
17615a09e398SHannes Reinecke 	 * - The allocated length
17625a09e398SHannes Reinecke 	 * - The constructed command length
17635a09e398SHannes Reinecke 	 * - The maximum array size
17645a09e398SHannes Reinecke 	 */
17655a09e398SHannes Reinecke 	rlen = min(alen,n);
17665a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17675a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17685a09e398SHannes Reinecke 	kfree(arr);
17695a09e398SHannes Reinecke 	return ret;
17705a09e398SHannes Reinecke }
17715a09e398SHannes Reinecke 
1772fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1773fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
177438d5c833SDouglas Gilbert {
177538d5c833SDouglas Gilbert 	bool rctd;
177638d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
177738d5c833SDouglas Gilbert 	u16 req_sa, u;
177838d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
177938d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
178038d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
178138d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
178238d5c833SDouglas Gilbert 	u8 *arr;
178338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
178438d5c833SDouglas Gilbert 
178538d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
178638d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
178738d5c833SDouglas Gilbert 	req_opcode = cmd[3];
178838d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
178938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17906d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
179138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
179238d5c833SDouglas Gilbert 		return check_condition_result;
179338d5c833SDouglas Gilbert 	}
179438d5c833SDouglas Gilbert 	if (alloc_len > 8192)
179538d5c833SDouglas Gilbert 		a_len = 8192;
179638d5c833SDouglas Gilbert 	else
179738d5c833SDouglas Gilbert 		a_len = alloc_len;
179899531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
179938d5c833SDouglas Gilbert 	if (NULL == arr) {
180038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
180138d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
180238d5c833SDouglas Gilbert 		return check_condition_result;
180338d5c833SDouglas Gilbert 	}
180438d5c833SDouglas Gilbert 	switch (reporting_opts) {
180538d5c833SDouglas Gilbert 	case 0:	/* all commands */
180638d5c833SDouglas Gilbert 		/* count number of commands */
180738d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
180838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
180938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181038d5c833SDouglas Gilbert 				continue;
181138d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
181238d5c833SDouglas Gilbert 		}
181338d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
181438d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
181538d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
181638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
181738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181838d5c833SDouglas Gilbert 				continue;
181938d5c833SDouglas Gilbert 			na = oip->num_attached;
182038d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
182138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
182238d5c833SDouglas Gilbert 			if (rctd)
182338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
182438d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
182538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
182638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
182738d5c833SDouglas Gilbert 			if (rctd)
182838d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
182938d5c833SDouglas Gilbert 			r_oip = oip;
183038d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
183138d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
183238d5c833SDouglas Gilbert 					continue;
183338d5c833SDouglas Gilbert 				offset += bump;
183438d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
183538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
183638d5c833SDouglas Gilbert 				if (rctd)
183738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
183838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
183938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
184038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
184138d5c833SDouglas Gilbert 						   arr + offset + 6);
184238d5c833SDouglas Gilbert 				if (rctd)
184338d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
184438d5c833SDouglas Gilbert 							   arr + offset + 8);
184538d5c833SDouglas Gilbert 			}
184638d5c833SDouglas Gilbert 			oip = r_oip;
184738d5c833SDouglas Gilbert 			offset += bump;
184838d5c833SDouglas Gilbert 		}
184938d5c833SDouglas Gilbert 		break;
185038d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
185138d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
185238d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
185338d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
185438d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
185538d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
185638d5c833SDouglas Gilbert 			supp = 1;
185738d5c833SDouglas Gilbert 			offset = 4;
185838d5c833SDouglas Gilbert 		} else {
185938d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
186038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
186138d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
186238d5c833SDouglas Gilbert 							     2, 2);
186338d5c833SDouglas Gilbert 					kfree(arr);
186438d5c833SDouglas Gilbert 					return check_condition_result;
186538d5c833SDouglas Gilbert 				}
186638d5c833SDouglas Gilbert 				req_sa = 0;
186738d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
186838d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
186938d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
187038d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
187138d5c833SDouglas Gilbert 				return check_condition_result;
187238d5c833SDouglas Gilbert 			}
187338d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
187438d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
187538d5c833SDouglas Gilbert 				supp = 3;
187638d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
187738d5c833SDouglas Gilbert 				na = oip->num_attached;
187838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
187938d5c833SDouglas Gilbert 				     ++k, ++oip) {
188038d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
188138d5c833SDouglas Gilbert 						break;
188238d5c833SDouglas Gilbert 				}
188338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
188438d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
188538d5c833SDouglas Gilbert 				na = oip->num_attached;
188638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
188738d5c833SDouglas Gilbert 				     ++k, ++oip) {
188838d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
188938d5c833SDouglas Gilbert 						break;
189038d5c833SDouglas Gilbert 				}
189138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
189238d5c833SDouglas Gilbert 			} else
189338d5c833SDouglas Gilbert 				supp = 3;
189438d5c833SDouglas Gilbert 			if (3 == supp) {
189538d5c833SDouglas Gilbert 				u = oip->len_mask[0];
189638d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
189738d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
189838d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
189938d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
190038d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
190138d5c833SDouglas Gilbert 				offset = 4 + u;
190238d5c833SDouglas Gilbert 			} else
190338d5c833SDouglas Gilbert 				offset = 4;
190438d5c833SDouglas Gilbert 		}
190538d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
190638d5c833SDouglas Gilbert 		if (rctd) {
190738d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
190838d5c833SDouglas Gilbert 			offset += 12;
190938d5c833SDouglas Gilbert 		}
191038d5c833SDouglas Gilbert 		break;
191138d5c833SDouglas Gilbert 	default:
191238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
191338d5c833SDouglas Gilbert 		kfree(arr);
191438d5c833SDouglas Gilbert 		return check_condition_result;
191538d5c833SDouglas Gilbert 	}
191638d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
191738d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
191838d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
191938d5c833SDouglas Gilbert 	kfree(arr);
192038d5c833SDouglas Gilbert 	return errsts;
192138d5c833SDouglas Gilbert }
192238d5c833SDouglas Gilbert 
1923fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1924fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
192538d5c833SDouglas Gilbert {
192638d5c833SDouglas Gilbert 	bool repd;
192738d5c833SDouglas Gilbert 	u32 alloc_len, len;
192838d5c833SDouglas Gilbert 	u8 arr[16];
192938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
193038d5c833SDouglas Gilbert 
193138d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
193238d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
193338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
193438d5c833SDouglas Gilbert 	if (alloc_len < 4) {
193538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
193638d5c833SDouglas Gilbert 		return check_condition_result;
193738d5c833SDouglas Gilbert 	}
193838d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
193938d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
194038d5c833SDouglas Gilbert 	if (repd) {
194138d5c833SDouglas Gilbert 		arr[3] = 0xc;
194238d5c833SDouglas Gilbert 		len = 16;
194338d5c833SDouglas Gilbert 	} else
194438d5c833SDouglas Gilbert 		len = 4;
194538d5c833SDouglas Gilbert 
194638d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
194738d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
194838d5c833SDouglas Gilbert }
194938d5c833SDouglas Gilbert 
19501da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
19511da177e4SLinus Torvalds 
19521da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
19531da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19541da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19551da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19581da177e4SLinus Torvalds 	if (1 == pcontrol)
19591da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19601da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19611da177e4SLinus Torvalds }
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
19641da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19651da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19661da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19671da177e4SLinus Torvalds 
19681da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19691da177e4SLinus Torvalds 	if (1 == pcontrol)
19701da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19711da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19721da177e4SLinus Torvalds }
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
19751da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19761da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19771da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19781da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1981773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1982773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1983773642d9SDouglas Gilbert 	if (sdebug_removable)
19841da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19851da177e4SLinus Torvalds 	if (1 == pcontrol)
19861da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19871da177e4SLinus Torvalds 	return sizeof(format_pg);
19881da177e4SLinus Torvalds }
19891da177e4SLinus Torvalds 
1990fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1991fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1992fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1993fd32119bSDouglas Gilbert 
19941da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
19951da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1996cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1997cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1998cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
19991da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
20001da177e4SLinus Torvalds 
2001773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2002cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
20031da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
20041da177e4SLinus Torvalds 	if (1 == pcontrol)
2005cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2006cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2007cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
20081da177e4SLinus Torvalds 	return sizeof(caching_pg);
20091da177e4SLinus Torvalds }
20101da177e4SLinus Torvalds 
2011fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2012fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2013fd32119bSDouglas Gilbert 
20141da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
20151da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2016c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2017c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2018c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
20191da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
20201da177e4SLinus Torvalds 
2021773642d9SDouglas Gilbert 	if (sdebug_dsense)
20221da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2023c65b1445SDouglas Gilbert 	else
2024c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2025c6a44287SMartin K. Petersen 
2026773642d9SDouglas Gilbert 	if (sdebug_ato)
2027c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2028c6a44287SMartin K. Petersen 
20291da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
20301da177e4SLinus Torvalds 	if (1 == pcontrol)
2031c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2032c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2033c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
20341da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20351da177e4SLinus Torvalds }
20361da177e4SLinus Torvalds 
2037c65b1445SDouglas Gilbert 
20381da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
20391da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2040c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
20411da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2042c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2043c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2044c65b1445SDouglas Gilbert 
20451da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
20461da177e4SLinus Torvalds 	if (1 == pcontrol)
2047c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2048c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2049c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
20501da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
20511da177e4SLinus Torvalds }
20521da177e4SLinus Torvalds 
2053c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2054c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2055c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2056c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2057c65b1445SDouglas Gilbert 
2058c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2059c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2060c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2061c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2062c65b1445SDouglas Gilbert }
2063c65b1445SDouglas Gilbert 
2064c65b1445SDouglas Gilbert 
2065c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2066c65b1445SDouglas Gilbert 			      int target_dev_id)
2067c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2068c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2069c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2070773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2071773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2072c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2073c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2074c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2075c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2076773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2077773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2078c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2079c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2080c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2081c65b1445SDouglas Gilbert 		};
2082c65b1445SDouglas Gilbert 	int port_a, port_b;
2083c65b1445SDouglas Gilbert 
20841b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20851b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20861b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20871b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2088c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2089c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2090c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2091773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2092773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2093c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2094c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2095c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2096c65b1445SDouglas Gilbert }
2097c65b1445SDouglas Gilbert 
2098c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2099c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2100c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2101c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2102c65b1445SDouglas Gilbert 		};
2103c65b1445SDouglas Gilbert 
2104c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2105c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2106c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2107c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2108c65b1445SDouglas Gilbert }
2109c65b1445SDouglas Gilbert 
21101da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
21111da177e4SLinus Torvalds 
2112fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2113fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
21141da177e4SLinus Torvalds {
211523183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
21161da177e4SLinus Torvalds 	unsigned char dev_spec;
2117760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2118c2248fc9SDouglas Gilbert 	int target = scp->device->id;
21191da177e4SLinus Torvalds 	unsigned char *ap;
21201da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
212101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2122760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
21231da177e4SLinus Torvalds 
2124760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
21251da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
21261da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
21271da177e4SLinus Torvalds 	subpcode = cmd[3];
21281da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2129760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2130760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2131760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
213223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
213323183910SDouglas Gilbert 	else
213423183910SDouglas Gilbert 		bd_len = 0;
2135773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21361da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21371da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2138cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
21391da177e4SLinus Torvalds 		return check_condition_result;
21401da177e4SLinus Torvalds 	}
2141c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2142c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2143b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
21449447b6ceSMartin K. Petersen 	if (is_disk) {
2145b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
21469447b6ceSMartin K. Petersen 		if (sdebug_wp)
21479447b6ceSMartin K. Petersen 			dev_spec |= 0x80;
21489447b6ceSMartin K. Petersen 	} else
214923183910SDouglas Gilbert 		dev_spec = 0x0;
21501da177e4SLinus Torvalds 	if (msense_6) {
21511da177e4SLinus Torvalds 		arr[2] = dev_spec;
215223183910SDouglas Gilbert 		arr[3] = bd_len;
21531da177e4SLinus Torvalds 		offset = 4;
21541da177e4SLinus Torvalds 	} else {
21551da177e4SLinus Torvalds 		arr[3] = dev_spec;
215623183910SDouglas Gilbert 		if (16 == bd_len)
215723183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
215823183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21591da177e4SLinus Torvalds 		offset = 8;
21601da177e4SLinus Torvalds 	}
21611da177e4SLinus Torvalds 	ap = arr + offset;
216228898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
216328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
216428898873SFUJITA Tomonori 
216523183910SDouglas Gilbert 	if (8 == bd_len) {
2166773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2167773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2168773642d9SDouglas Gilbert 		else
2169773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2170773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
217123183910SDouglas Gilbert 		offset += bd_len;
217223183910SDouglas Gilbert 		ap = arr + offset;
217323183910SDouglas Gilbert 	} else if (16 == bd_len) {
2174773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2175773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
217623183910SDouglas Gilbert 		offset += bd_len;
217723183910SDouglas Gilbert 		ap = arr + offset;
217823183910SDouglas Gilbert 	}
21791da177e4SLinus Torvalds 
2180c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2181c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
218222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21831da177e4SLinus Torvalds 		return check_condition_result;
21841da177e4SLinus Torvalds 	}
2185760f3b03SDouglas Gilbert 	bad_pcode = false;
2186760f3b03SDouglas Gilbert 
21871da177e4SLinus Torvalds 	switch (pcode) {
21881da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21891da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21901da177e4SLinus Torvalds 		offset += len;
21911da177e4SLinus Torvalds 		break;
21921da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21931da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21941da177e4SLinus Torvalds 		offset += len;
21951da177e4SLinus Torvalds 		break;
21961da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2197760f3b03SDouglas Gilbert 		if (is_disk) {
21981da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
21991da177e4SLinus Torvalds 			offset += len;
2200760f3b03SDouglas Gilbert 		} else
2201760f3b03SDouglas Gilbert 			bad_pcode = true;
22021da177e4SLinus Torvalds 		break;
22031da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2204760f3b03SDouglas Gilbert 		if (is_disk) {
22051da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
22061da177e4SLinus Torvalds 			offset += len;
2207760f3b03SDouglas Gilbert 		} else
2208760f3b03SDouglas Gilbert 			bad_pcode = true;
22091da177e4SLinus Torvalds 		break;
22101da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
22111da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
22121da177e4SLinus Torvalds 		offset += len;
22131da177e4SLinus Torvalds 		break;
2214c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2215c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
221622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2217c65b1445SDouglas Gilbert 			return check_condition_result;
2218c65b1445SDouglas Gilbert 		}
2219c65b1445SDouglas Gilbert 		len = 0;
2220c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2221c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2222c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2223c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2224c65b1445SDouglas Gilbert 						  target_dev_id);
2225c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2226c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2227c65b1445SDouglas Gilbert 		offset += len;
2228c65b1445SDouglas Gilbert 		break;
22291da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
22301da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
22311da177e4SLinus Torvalds 		offset += len;
22321da177e4SLinus Torvalds 		break;
22331da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2234c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
22351da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
22361da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2237760f3b03SDouglas Gilbert 			if (is_disk) {
2238760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2239760f3b03SDouglas Gilbert 						      target);
2240760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2241760f3b03SDouglas Gilbert 						       target);
2242760f3b03SDouglas Gilbert 			}
22431da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2244c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2245c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2246c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2247c65b1445SDouglas Gilbert 						  target, target_dev_id);
2248c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2249c65b1445SDouglas Gilbert 			}
22501da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2251760f3b03SDouglas Gilbert 			offset += len;
2252c65b1445SDouglas Gilbert 		} else {
225322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2254c65b1445SDouglas Gilbert 			return check_condition_result;
2255c65b1445SDouglas Gilbert 		}
22561da177e4SLinus Torvalds 		break;
22571da177e4SLinus Torvalds 	default:
2258760f3b03SDouglas Gilbert 		bad_pcode = true;
2259760f3b03SDouglas Gilbert 		break;
2260760f3b03SDouglas Gilbert 	}
2261760f3b03SDouglas Gilbert 	if (bad_pcode) {
226222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22631da177e4SLinus Torvalds 		return check_condition_result;
22641da177e4SLinus Torvalds 	}
22651da177e4SLinus Torvalds 	if (msense_6)
22661da177e4SLinus Torvalds 		arr[0] = offset - 1;
2267773642d9SDouglas Gilbert 	else
2268773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22691da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22701da177e4SLinus Torvalds }
22711da177e4SLinus Torvalds 
2272c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2273c65b1445SDouglas Gilbert 
2274fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2275fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2276c65b1445SDouglas Gilbert {
2277c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2278c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2279c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
228001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2281c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2282c65b1445SDouglas Gilbert 
2283c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2284c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2285c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2286773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2287c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
228822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2289c65b1445SDouglas Gilbert 		return check_condition_result;
2290c65b1445SDouglas Gilbert 	}
2291c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2292c65b1445SDouglas Gilbert 	if (-1 == res)
2293773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2294773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2295cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2296cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2297cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2298773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2299773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
230023183910SDouglas Gilbert 	if (md_len > 2) {
230122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2302c65b1445SDouglas Gilbert 		return check_condition_result;
2303c65b1445SDouglas Gilbert 	}
2304c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2305c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2306c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2307c65b1445SDouglas Gilbert 	if (ps) {
230822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2309c65b1445SDouglas Gilbert 		return check_condition_result;
2310c65b1445SDouglas Gilbert 	}
2311c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2312773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2313c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2314c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2315cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2316c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2317c65b1445SDouglas Gilbert 		return check_condition_result;
2318c65b1445SDouglas Gilbert 	}
2319c65b1445SDouglas Gilbert 	switch (mpage) {
2320cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2321cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2322cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2323cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2324cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2325cbf67842SDouglas Gilbert 		}
2326cbf67842SDouglas Gilbert 		break;
2327c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2328c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2329c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2330c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
23319447b6ceSMartin K. Petersen 			if (ctrl_m_pg[4] & 0x8)
23329447b6ceSMartin K. Petersen 				sdebug_wp = true;
23339447b6ceSMartin K. Petersen 			else
23349447b6ceSMartin K. Petersen 				sdebug_wp = false;
2335773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2336cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2337c65b1445SDouglas Gilbert 		}
2338c65b1445SDouglas Gilbert 		break;
2339c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2340c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2341c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2342c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2343cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2344c65b1445SDouglas Gilbert 		}
2345c65b1445SDouglas Gilbert 		break;
2346c65b1445SDouglas Gilbert 	default:
2347c65b1445SDouglas Gilbert 		break;
2348c65b1445SDouglas Gilbert 	}
234922017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2350c65b1445SDouglas Gilbert 	return check_condition_result;
2351cbf67842SDouglas Gilbert set_mode_changed_ua:
2352cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2353cbf67842SDouglas Gilbert 	return 0;
2354c65b1445SDouglas Gilbert }
2355c65b1445SDouglas Gilbert 
2356c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2357c65b1445SDouglas Gilbert {
2358c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2359c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2360c65b1445SDouglas Gilbert 		};
2361c65b1445SDouglas Gilbert 
2362c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2363c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2364c65b1445SDouglas Gilbert }
2365c65b1445SDouglas Gilbert 
2366c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2367c65b1445SDouglas Gilbert {
2368c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2369c65b1445SDouglas Gilbert 		};
2370c65b1445SDouglas Gilbert 
2371c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2372c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2373c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2374c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2375c65b1445SDouglas Gilbert 	}
2376c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2377c65b1445SDouglas Gilbert }
2378c65b1445SDouglas Gilbert 
2379c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2380c65b1445SDouglas Gilbert 
2381c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2382c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2383c65b1445SDouglas Gilbert {
2384ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2385c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
238601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2387c65b1445SDouglas Gilbert 
2388c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2389c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2390c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2391c65b1445SDouglas Gilbert 	if (ppc || sp) {
239222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2393c65b1445SDouglas Gilbert 		return check_condition_result;
2394c65b1445SDouglas Gilbert 	}
2395c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
239623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2397773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2398c65b1445SDouglas Gilbert 	arr[0] = pcode;
239923183910SDouglas Gilbert 	if (0 == subpcode) {
2400c65b1445SDouglas Gilbert 		switch (pcode) {
2401c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2402c65b1445SDouglas Gilbert 			n = 4;
2403c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2404c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2405c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2406c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2407c65b1445SDouglas Gilbert 			break;
2408c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2409c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2410c65b1445SDouglas Gilbert 			break;
2411c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2412c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2413c65b1445SDouglas Gilbert 			break;
2414c65b1445SDouglas Gilbert 		default:
241522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2416c65b1445SDouglas Gilbert 			return check_condition_result;
2417c65b1445SDouglas Gilbert 		}
241823183910SDouglas Gilbert 	} else if (0xff == subpcode) {
241923183910SDouglas Gilbert 		arr[0] |= 0x40;
242023183910SDouglas Gilbert 		arr[1] = subpcode;
242123183910SDouglas Gilbert 		switch (pcode) {
242223183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
242323183910SDouglas Gilbert 			n = 4;
242423183910SDouglas Gilbert 			arr[n++] = 0x0;
242523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
242623183910SDouglas Gilbert 			arr[n++] = 0x0;
242723183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
242823183910SDouglas Gilbert 			arr[n++] = 0xd;
242923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
243023183910SDouglas Gilbert 			arr[n++] = 0x2f;
243123183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
243223183910SDouglas Gilbert 			arr[3] = n - 4;
243323183910SDouglas Gilbert 			break;
243423183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
243523183910SDouglas Gilbert 			n = 4;
243623183910SDouglas Gilbert 			arr[n++] = 0xd;
243723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
243823183910SDouglas Gilbert 			arr[3] = n - 4;
243923183910SDouglas Gilbert 			break;
244023183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
244123183910SDouglas Gilbert 			n = 4;
244223183910SDouglas Gilbert 			arr[n++] = 0x2f;
244323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
244423183910SDouglas Gilbert 			arr[3] = n - 4;
244523183910SDouglas Gilbert 			break;
244623183910SDouglas Gilbert 		default:
244722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
244823183910SDouglas Gilbert 			return check_condition_result;
244923183910SDouglas Gilbert 		}
245023183910SDouglas Gilbert 	} else {
245122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
245223183910SDouglas Gilbert 		return check_condition_result;
245323183910SDouglas Gilbert 	}
2454773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2455c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2456c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2457c65b1445SDouglas Gilbert }
2458c65b1445SDouglas Gilbert 
24599447b6ceSMartin K. Petersen static inline int check_device_access_params(struct scsi_cmnd *scp,
24609447b6ceSMartin K. Petersen 	unsigned long long lba, unsigned int num, bool write)
24611da177e4SLinus Torvalds {
2462c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
246322017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24641da177e4SLinus Torvalds 		return check_condition_result;
24651da177e4SLinus Torvalds 	}
2466c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2467c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
246822017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2469cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2470c65b1445SDouglas Gilbert 		return check_condition_result;
2471c65b1445SDouglas Gilbert 	}
24729447b6ceSMartin K. Petersen 	if (write && unlikely(sdebug_wp)) {
24739447b6ceSMartin K. Petersen 		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
24749447b6ceSMartin K. Petersen 		return check_condition_result;
24759447b6ceSMartin K. Petersen 	}
247619789100SFUJITA Tomonori 	return 0;
247719789100SFUJITA Tomonori }
247819789100SFUJITA Tomonori 
2479a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
24800a7e69c7SDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
24810a7e69c7SDouglas Gilbert 			    u32 num, bool do_write)
248219789100SFUJITA Tomonori {
248319789100SFUJITA Tomonori 	int ret;
2484c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2485ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scmd->sdb;
2486a4517511SAkinobu Mita 	enum dma_data_direction dir;
248719789100SFUJITA Tomonori 
2488c2248fc9SDouglas Gilbert 	if (do_write) {
2489a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
24904f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2491a4517511SAkinobu Mita 	} else {
2492a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2493a4517511SAkinobu Mita 	}
2494a4517511SAkinobu Mita 
2495a4517511SAkinobu Mita 	if (!sdb->length)
2496a4517511SAkinobu Mita 		return 0;
2497ae3d56d8SChristoph Hellwig 	if (scmd->sc_data_direction != dir)
2498a4517511SAkinobu Mita 		return -1;
249919789100SFUJITA Tomonori 
250019789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
250119789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
250219789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
250319789100SFUJITA Tomonori 
2504386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2505773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
25060a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2507773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2508a4517511SAkinobu Mita 		return ret;
2509a4517511SAkinobu Mita 
2510a4517511SAkinobu Mita 	if (rest) {
2511386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2512773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
25130a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
25140a7e69c7SDouglas Gilbert 			    do_write);
2515a4517511SAkinobu Mita 	}
251619789100SFUJITA Tomonori 
251719789100SFUJITA Tomonori 	return ret;
251819789100SFUJITA Tomonori }
251919789100SFUJITA Tomonori 
252040d07b52SDouglas Gilbert /* If lba2fake_store(lba,num) compares equal to arr(num), then copy top half of
252140d07b52SDouglas Gilbert  * arr into lba2fake_store(lba,num) and return true. If comparison fails then
252238d5c833SDouglas Gilbert  * return false. */
2523fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
252438d5c833SDouglas Gilbert {
252538d5c833SDouglas Gilbert 	bool res;
252638d5c833SDouglas Gilbert 	u64 block, rest = 0;
252738d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2528773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
252938d5c833SDouglas Gilbert 
253038d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
253138d5c833SDouglas Gilbert 	if (block + num > store_blks)
253238d5c833SDouglas Gilbert 		rest = block + num - store_blks;
253338d5c833SDouglas Gilbert 
253438d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
253538d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
253638d5c833SDouglas Gilbert 	if (!res)
253738d5c833SDouglas Gilbert 		return res;
253838d5c833SDouglas Gilbert 	if (rest)
253938d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
254038d5c833SDouglas Gilbert 			     rest * lb_size);
254138d5c833SDouglas Gilbert 	if (!res)
254238d5c833SDouglas Gilbert 		return res;
254338d5c833SDouglas Gilbert 	arr += num * lb_size;
254438d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
254538d5c833SDouglas Gilbert 	if (rest)
254638d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
254738d5c833SDouglas Gilbert 		       rest * lb_size);
254838d5c833SDouglas Gilbert 	return res;
254938d5c833SDouglas Gilbert }
255038d5c833SDouglas Gilbert 
255151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2552beb40ea4SAkinobu Mita {
255351d648afSAkinobu Mita 	__be16 csum;
2554beb40ea4SAkinobu Mita 
2555773642d9SDouglas Gilbert 	if (sdebug_guard)
255651d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
255751d648afSAkinobu Mita 	else
2558beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
255951d648afSAkinobu Mita 
2560beb40ea4SAkinobu Mita 	return csum;
2561beb40ea4SAkinobu Mita }
2562beb40ea4SAkinobu Mita 
25636ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2564beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2565beb40ea4SAkinobu Mita {
2566773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2567beb40ea4SAkinobu Mita 
2568beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2569c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2570beb40ea4SAkinobu Mita 			(unsigned long)sector,
2571beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2572beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2573beb40ea4SAkinobu Mita 		return 0x01;
2574beb40ea4SAkinobu Mita 	}
25758475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2576beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2577c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2578c1287970STomas Winkler 			(unsigned long)sector);
2579beb40ea4SAkinobu Mita 		return 0x03;
2580beb40ea4SAkinobu Mita 	}
25818475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2582beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2583c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2584c1287970STomas Winkler 			(unsigned long)sector);
2585beb40ea4SAkinobu Mita 		return 0x03;
2586beb40ea4SAkinobu Mita 	}
2587beb40ea4SAkinobu Mita 	return 0;
2588beb40ea4SAkinobu Mita }
2589beb40ea4SAkinobu Mita 
2590bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
259165f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2592c6a44287SMartin K. Petersen {
2593be4e11beSAkinobu Mita 	size_t resid;
2594c6a44287SMartin K. Petersen 	void *paddr;
259514faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2596be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2597c6a44287SMartin K. Petersen 
2598e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2599e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2600c6a44287SMartin K. Petersen 
2601be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2602be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2603be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2604be4e11beSAkinobu Mita 
2605be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2606be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
260714faa944SAkinobu Mita 		void *start = dif_store(sector);
2608be4e11beSAkinobu Mita 		size_t rest = 0;
260914faa944SAkinobu Mita 
261014faa944SAkinobu Mita 		if (dif_store_end < start + len)
261114faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2612c6a44287SMartin K. Petersen 
2613be4e11beSAkinobu Mita 		paddr = miter.addr;
261414faa944SAkinobu Mita 
261565f72f2aSAkinobu Mita 		if (read)
261665f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
261765f72f2aSAkinobu Mita 		else
261865f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
261965f72f2aSAkinobu Mita 
262065f72f2aSAkinobu Mita 		if (rest) {
262165f72f2aSAkinobu Mita 			if (read)
262214faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
262365f72f2aSAkinobu Mita 			else
262465f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
262565f72f2aSAkinobu Mita 		}
2626c6a44287SMartin K. Petersen 
2627e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2628c6a44287SMartin K. Petersen 		resid -= len;
2629c6a44287SMartin K. Petersen 	}
2630be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2631bb8c063cSAkinobu Mita }
2632c6a44287SMartin K. Petersen 
2633bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2634bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2635bb8c063cSAkinobu Mita {
2636bb8c063cSAkinobu Mita 	unsigned int i;
26376ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2638bb8c063cSAkinobu Mita 	sector_t sector;
2639bb8c063cSAkinobu Mita 
2640c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2641bb8c063cSAkinobu Mita 		int ret;
2642bb8c063cSAkinobu Mita 
2643bb8c063cSAkinobu Mita 		sector = start_sec + i;
2644bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2645bb8c063cSAkinobu Mita 
264651d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2647bb8c063cSAkinobu Mita 			continue;
2648bb8c063cSAkinobu Mita 
264940d07b52SDouglas Gilbert 		ret = dif_verify(sdt, lba2fake_store(sector), sector, ei_lba);
2650bb8c063cSAkinobu Mita 		if (ret) {
2651bb8c063cSAkinobu Mita 			dif_errors++;
2652bb8c063cSAkinobu Mita 			return ret;
2653bb8c063cSAkinobu Mita 		}
2654bb8c063cSAkinobu Mita 	}
2655bb8c063cSAkinobu Mita 
265665f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2657c6a44287SMartin K. Petersen 	dix_reads++;
2658c6a44287SMartin K. Petersen 
2659c6a44287SMartin K. Petersen 	return 0;
2660c6a44287SMartin K. Petersen }
2661c6a44287SMartin K. Petersen 
2662fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
266319789100SFUJITA Tomonori {
2664c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2665c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2666c2248fc9SDouglas Gilbert 	u64 lba;
2667c2248fc9SDouglas Gilbert 	u32 num;
2668c2248fc9SDouglas Gilbert 	u32 ei_lba;
266919789100SFUJITA Tomonori 	unsigned long iflags;
267019789100SFUJITA Tomonori 	int ret;
2671c2248fc9SDouglas Gilbert 	bool check_prot;
267219789100SFUJITA Tomonori 
2673c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2674c2248fc9SDouglas Gilbert 	case READ_16:
2675c2248fc9SDouglas Gilbert 		ei_lba = 0;
2676c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2677c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2678c2248fc9SDouglas Gilbert 		check_prot = true;
2679c2248fc9SDouglas Gilbert 		break;
2680c2248fc9SDouglas Gilbert 	case READ_10:
2681c2248fc9SDouglas Gilbert 		ei_lba = 0;
2682c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2683c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2684c2248fc9SDouglas Gilbert 		check_prot = true;
2685c2248fc9SDouglas Gilbert 		break;
2686c2248fc9SDouglas Gilbert 	case READ_6:
2687c2248fc9SDouglas Gilbert 		ei_lba = 0;
2688c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2689c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2690c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2691c2248fc9SDouglas Gilbert 		check_prot = true;
2692c2248fc9SDouglas Gilbert 		break;
2693c2248fc9SDouglas Gilbert 	case READ_12:
2694c2248fc9SDouglas Gilbert 		ei_lba = 0;
2695c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2696c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2697c2248fc9SDouglas Gilbert 		check_prot = true;
2698c2248fc9SDouglas Gilbert 		break;
2699c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2700c2248fc9SDouglas Gilbert 		ei_lba = 0;
2701c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2702c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2703c2248fc9SDouglas Gilbert 		check_prot = false;
2704c2248fc9SDouglas Gilbert 		break;
2705c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2706c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2707c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2708c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2709c2248fc9SDouglas Gilbert 		check_prot = false;
2710c2248fc9SDouglas Gilbert 		break;
2711c2248fc9SDouglas Gilbert 	}
2712f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
27138475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2714c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2715c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2716c2248fc9SDouglas Gilbert 			return check_condition_result;
2717c2248fc9SDouglas Gilbert 		}
27188475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
27198475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2720c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2721c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2722c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2723c2248fc9SDouglas Gilbert 	}
2724f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2725c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2726c2248fc9SDouglas Gilbert 
2727c4837394SDouglas Gilbert 		if (sqcp) {
2728c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2729c2248fc9SDouglas Gilbert 				num /= 2;
2730c2248fc9SDouglas Gilbert 		}
2731c4837394SDouglas Gilbert 	} else
2732c4837394SDouglas Gilbert 		sqcp = NULL;
2733c2248fc9SDouglas Gilbert 
27349447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
27359447b6ceSMartin K. Petersen 	if (ret)
27369447b6ceSMartin K. Petersen 		return ret;
2737f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2738d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2739d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
2740c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2741c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2742c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2743c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2744c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
274532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
274632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2747c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2748c65b1445SDouglas Gilbert 		}
2749c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
27501da177e4SLinus Torvalds 		return check_condition_result;
27511da177e4SLinus Torvalds 	}
2752c6a44287SMartin K. Petersen 
27536c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
27546c78cc06SAkinobu Mita 
2755c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2756f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2757c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2758c6a44287SMartin K. Petersen 
2759c6a44287SMartin K. Petersen 		if (prot_ret) {
27606c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2761c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2762c6a44287SMartin K. Petersen 			return illegal_condition_result;
2763c6a44287SMartin K. Petersen 		}
2764c6a44287SMartin K. Petersen 	}
2765c6a44287SMartin K. Petersen 
27660a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, false);
27671da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2768f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2769a4517511SAkinobu Mita 		return DID_ERROR << 16;
2770a4517511SAkinobu Mita 
277142d387beSBart Van Assche 	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
2772a4517511SAkinobu Mita 
2773c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2774c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2775c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2776c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2777c2248fc9SDouglas Gilbert 			return check_condition_result;
2778c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2779c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2780c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2781c2248fc9SDouglas Gilbert 			return check_condition_result;
2782c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2783c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2784c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2785c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2786c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2787c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2788c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2789c2248fc9SDouglas Gilbert 		}
2790c2248fc9SDouglas Gilbert 	}
2791a4517511SAkinobu Mita 	return 0;
27921da177e4SLinus Torvalds }
27931da177e4SLinus Torvalds 
279458a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2795c6a44287SMartin K. Petersen {
2796cbf67842SDouglas Gilbert 	int i, j, n;
2797c6a44287SMartin K. Petersen 
2798cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2799c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2800cbf67842SDouglas Gilbert 		char b[128];
2801c6a44287SMartin K. Petersen 
2802cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2803c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2804c6a44287SMartin K. Petersen 
2805cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2806cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2807cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2808cbf67842SDouglas Gilbert 			else
2809cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2810cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2811cbf67842SDouglas Gilbert 		}
2812cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2813c6a44287SMartin K. Petersen 	}
2814c6a44287SMartin K. Petersen }
2815c6a44287SMartin K. Petersen 
2816c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2817395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2818c6a44287SMartin K. Petersen {
2819be4e11beSAkinobu Mita 	int ret;
28206ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2821be4e11beSAkinobu Mita 	void *daddr;
282265f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2823c6a44287SMartin K. Petersen 	int ppage_offset;
2824be4e11beSAkinobu Mita 	int dpage_offset;
2825be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2826be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2827c6a44287SMartin K. Petersen 
2828c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2829c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2830c6a44287SMartin K. Petersen 
2831be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2832be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2833be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2834be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2835be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2836c6a44287SMartin K. Petersen 
2837be4e11beSAkinobu Mita 	/* For each protection page */
2838be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2839be4e11beSAkinobu Mita 		dpage_offset = 0;
2840be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2841be4e11beSAkinobu Mita 			ret = 0x01;
2842be4e11beSAkinobu Mita 			goto out;
2843c6a44287SMartin K. Petersen 		}
2844c6a44287SMartin K. Petersen 
2845be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
28466ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2847be4e11beSAkinobu Mita 			/* If we're at the end of the current
2848be4e11beSAkinobu Mita 			 * data page advance to the next one
2849be4e11beSAkinobu Mita 			 */
2850be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2851be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2852be4e11beSAkinobu Mita 					ret = 0x01;
2853be4e11beSAkinobu Mita 					goto out;
2854be4e11beSAkinobu Mita 				}
2855be4e11beSAkinobu Mita 				dpage_offset = 0;
2856be4e11beSAkinobu Mita 			}
2857c6a44287SMartin K. Petersen 
2858be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2859be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2860be4e11beSAkinobu Mita 
2861be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2862beb40ea4SAkinobu Mita 			if (ret) {
2863773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2864395cef03SMartin K. Petersen 				goto out;
2865395cef03SMartin K. Petersen 			}
2866395cef03SMartin K. Petersen 
2867c6a44287SMartin K. Petersen 			sector++;
2868395cef03SMartin K. Petersen 			ei_lba++;
2869773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2870c6a44287SMartin K. Petersen 		}
2871be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2872be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2873c6a44287SMartin K. Petersen 	}
2874be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2875c6a44287SMartin K. Petersen 
287665f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2877c6a44287SMartin K. Petersen 	dix_writes++;
2878c6a44287SMartin K. Petersen 
2879c6a44287SMartin K. Petersen 	return 0;
2880c6a44287SMartin K. Petersen 
2881c6a44287SMartin K. Petersen out:
2882c6a44287SMartin K. Petersen 	dif_errors++;
2883be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2884be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2885c6a44287SMartin K. Petersen 	return ret;
2886c6a44287SMartin K. Petersen }
2887c6a44287SMartin K. Petersen 
2888b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2889b90ebc3dSAkinobu Mita {
2890773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2891773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2892773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2893b90ebc3dSAkinobu Mita 	return lba;
2894b90ebc3dSAkinobu Mita }
2895b90ebc3dSAkinobu Mita 
2896b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2897b90ebc3dSAkinobu Mita {
2898773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2899a027b5b9SAkinobu Mita 
2900773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2901773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2902a027b5b9SAkinobu Mita 	return lba;
2903a027b5b9SAkinobu Mita }
2904a027b5b9SAkinobu Mita 
290544d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
290644d92694SMartin K. Petersen {
2907b90ebc3dSAkinobu Mita 	sector_t end;
2908b90ebc3dSAkinobu Mita 	unsigned int mapped;
2909b90ebc3dSAkinobu Mita 	unsigned long index;
2910b90ebc3dSAkinobu Mita 	unsigned long next;
291144d92694SMartin K. Petersen 
2912b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2913b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
291444d92694SMartin K. Petersen 
291544d92694SMartin K. Petersen 	if (mapped)
2916b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
291744d92694SMartin K. Petersen 	else
2918b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
291944d92694SMartin K. Petersen 
2920b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
292144d92694SMartin K. Petersen 	*num = end - lba;
292244d92694SMartin K. Petersen 	return mapped;
292344d92694SMartin K. Petersen }
292444d92694SMartin K. Petersen 
292544d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
292644d92694SMartin K. Petersen {
292744d92694SMartin K. Petersen 	sector_t end = lba + len;
292844d92694SMartin K. Petersen 
292944d92694SMartin K. Petersen 	while (lba < end) {
2930b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
293144d92694SMartin K. Petersen 
2932b90ebc3dSAkinobu Mita 		if (index < map_size)
2933b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
293444d92694SMartin K. Petersen 
2935b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
293644d92694SMartin K. Petersen 	}
293744d92694SMartin K. Petersen }
293844d92694SMartin K. Petersen 
293944d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
294044d92694SMartin K. Petersen {
294144d92694SMartin K. Petersen 	sector_t end = lba + len;
294244d92694SMartin K. Petersen 
294344d92694SMartin K. Petersen 	while (lba < end) {
2944b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
294544d92694SMartin K. Petersen 
2946b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2947773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2948b90ebc3dSAkinobu Mita 		    index < map_size) {
2949b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2950760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2951be1dd78dSEric Sandeen 				memset(fake_storep +
2952760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2953760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2954773642d9SDouglas Gilbert 				       sdebug_sector_size *
2955773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2956be1dd78dSEric Sandeen 			}
2957e9926b43SAkinobu Mita 			if (dif_storep) {
2958e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2959e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2960773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2961e9926b43SAkinobu Mita 			}
2962b90ebc3dSAkinobu Mita 		}
2963b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
296444d92694SMartin K. Petersen 	}
296544d92694SMartin K. Petersen }
296644d92694SMartin K. Petersen 
2967fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
29681da177e4SLinus Torvalds {
2969c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2970c2248fc9SDouglas Gilbert 	u64 lba;
2971c2248fc9SDouglas Gilbert 	u32 num;
2972c2248fc9SDouglas Gilbert 	u32 ei_lba;
29731da177e4SLinus Torvalds 	unsigned long iflags;
297419789100SFUJITA Tomonori 	int ret;
2975c2248fc9SDouglas Gilbert 	bool check_prot;
29761da177e4SLinus Torvalds 
2977c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2978c2248fc9SDouglas Gilbert 	case WRITE_16:
2979c2248fc9SDouglas Gilbert 		ei_lba = 0;
2980c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2981c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2982c2248fc9SDouglas Gilbert 		check_prot = true;
2983c2248fc9SDouglas Gilbert 		break;
2984c2248fc9SDouglas Gilbert 	case WRITE_10:
2985c2248fc9SDouglas Gilbert 		ei_lba = 0;
2986c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2987c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2988c2248fc9SDouglas Gilbert 		check_prot = true;
2989c2248fc9SDouglas Gilbert 		break;
2990c2248fc9SDouglas Gilbert 	case WRITE_6:
2991c2248fc9SDouglas Gilbert 		ei_lba = 0;
2992c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2993c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2994c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2995c2248fc9SDouglas Gilbert 		check_prot = true;
2996c2248fc9SDouglas Gilbert 		break;
2997c2248fc9SDouglas Gilbert 	case WRITE_12:
2998c2248fc9SDouglas Gilbert 		ei_lba = 0;
2999c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3000c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3001c2248fc9SDouglas Gilbert 		check_prot = true;
3002c2248fc9SDouglas Gilbert 		break;
3003c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3004c2248fc9SDouglas Gilbert 		ei_lba = 0;
3005c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3006c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3007c2248fc9SDouglas Gilbert 		check_prot = false;
3008c2248fc9SDouglas Gilbert 		break;
3009c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3010c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3011c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3012c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3013c2248fc9SDouglas Gilbert 		check_prot = false;
3014c2248fc9SDouglas Gilbert 		break;
3015c2248fc9SDouglas Gilbert 	}
3016f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
30178475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3018c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3019c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3020c2248fc9SDouglas Gilbert 			return check_condition_result;
3021c2248fc9SDouglas Gilbert 		}
30228475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
30238475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3024c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3025c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3026c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3027c2248fc9SDouglas Gilbert 	}
30289447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, true);
30299447b6ceSMartin K. Petersen 	if (ret)
30309447b6ceSMartin K. Petersen 		return ret;
30316c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
30326c78cc06SAkinobu Mita 
3033c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3034f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3035c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3036c6a44287SMartin K. Petersen 
3037c6a44287SMartin K. Petersen 		if (prot_ret) {
30386c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
3039c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3040c6a44287SMartin K. Petersen 			return illegal_condition_result;
3041c6a44287SMartin K. Petersen 		}
3042c6a44287SMartin K. Petersen 	}
3043c6a44287SMartin K. Petersen 
30440a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, true);
3045f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
304644d92694SMartin K. Petersen 		map_region(lba, num);
30471da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3048f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3049773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3050c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3051c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3052c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3053cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3054773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
305544d92694SMartin K. Petersen 
3056f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3057c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3058c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3059c2248fc9SDouglas Gilbert 
3060c4837394SDouglas Gilbert 		if (sqcp) {
3061c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3062c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3063c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3064c2248fc9SDouglas Gilbert 				return check_condition_result;
3065c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3066c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3067c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3068c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3069c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3070c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3071c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3072c2248fc9SDouglas Gilbert 			}
3073c2248fc9SDouglas Gilbert 		}
3074c4837394SDouglas Gilbert 	}
30751da177e4SLinus Torvalds 	return 0;
30761da177e4SLinus Torvalds }
30771da177e4SLinus Torvalds 
3078481b5e5cSDouglas Gilbert /*
3079481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3080481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3081481b5e5cSDouglas Gilbert  */
3082481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3083481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3084481b5e5cSDouglas Gilbert {
3085481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3086481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3087481b5e5cSDouglas Gilbert 	u8 *up;
3088481b5e5cSDouglas Gilbert 	u8 wrprotect;
3089481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3090481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3091481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3092481b5e5cSDouglas Gilbert 	u32 ei_lba;
3093481b5e5cSDouglas Gilbert 	u64 lba;
3094481b5e5cSDouglas Gilbert 	unsigned long iflags;
3095481b5e5cSDouglas Gilbert 	int ret, res;
3096481b5e5cSDouglas Gilbert 	bool is_16;
3097481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3098481b5e5cSDouglas Gilbert 
3099481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3100481b5e5cSDouglas Gilbert 		is_16 = false;
3101481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3102481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3103481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3104481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3105481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3106481b5e5cSDouglas Gilbert 		is_16 = true;
3107481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3108481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3109481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3110481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3111481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3112481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3113481b5e5cSDouglas Gilbert 			    wrprotect) {
3114481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3115481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3116481b5e5cSDouglas Gilbert 			}
3117481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3118481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3119481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3120481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3121481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3122481b5e5cSDouglas Gilbert 		}
3123481b5e5cSDouglas Gilbert 	}
3124481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3125481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3126481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3127481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3128481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3129481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3130481b5e5cSDouglas Gilbert 				my_name, __func__);
3131481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3132481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3133481b5e5cSDouglas Gilbert 	}
3134481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3135481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3136481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3137481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3138481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3139481b5e5cSDouglas Gilbert 				my_name, __func__);
3140481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3141481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3142481b5e5cSDouglas Gilbert 	}
3143481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3144481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3145481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3146481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3147481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3148481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3149481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3150481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3151481b5e5cSDouglas Gilbert 	if (res == -1) {
3152481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3153481b5e5cSDouglas Gilbert 		goto err_out;
3154481b5e5cSDouglas Gilbert 	}
3155481b5e5cSDouglas Gilbert 
3156481b5e5cSDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
3157481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3158481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3159481b5e5cSDouglas Gilbert 	cum_lb = 0;
3160481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3161481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3162481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3163481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3164481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3165481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3166481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3167481b5e5cSDouglas Gilbert 		if (num == 0)
3168481b5e5cSDouglas Gilbert 			continue;
31699447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
3170481b5e5cSDouglas Gilbert 		if (ret)
3171481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3172481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3173481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3174481b5e5cSDouglas Gilbert 
3175481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3176481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3177481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3178481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3179481b5e5cSDouglas Gilbert 				    my_name, __func__);
3180481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3181481b5e5cSDouglas Gilbert 					0);
3182481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3183481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3184481b5e5cSDouglas Gilbert 		}
3185481b5e5cSDouglas Gilbert 
3186481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3187481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3188481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3189481b5e5cSDouglas Gilbert 							 ei_lba);
3190481b5e5cSDouglas Gilbert 
3191481b5e5cSDouglas Gilbert 			if (prot_ret) {
3192481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3193481b5e5cSDouglas Gilbert 						prot_ret);
3194481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3195481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3196481b5e5cSDouglas Gilbert 			}
3197481b5e5cSDouglas Gilbert 		}
3198481b5e5cSDouglas Gilbert 
3199481b5e5cSDouglas Gilbert 		ret = do_device_access(scp, sg_off, lba, num, true);
3200481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
3201481b5e5cSDouglas Gilbert 			map_region(lba, num);
3202481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3203481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3204481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3205481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3206481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3207481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3208481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3209481b5e5cSDouglas Gilbert 
3210481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3211481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3212481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3213481b5e5cSDouglas Gilbert 
3214481b5e5cSDouglas Gilbert 			if (sqcp) {
3215481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3216481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3217481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3218481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3219481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3220481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3221481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3222481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3223481b5e5cSDouglas Gilbert 							0x10, 1);
3224481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3225481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3226481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3227481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3228481b5e5cSDouglas Gilbert 							0x10, 1);
3229481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3230481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3231481b5e5cSDouglas Gilbert 				}
3232481b5e5cSDouglas Gilbert 			}
3233481b5e5cSDouglas Gilbert 		}
3234481b5e5cSDouglas Gilbert 		sg_off += num_by;
3235481b5e5cSDouglas Gilbert 		cum_lb += num;
3236481b5e5cSDouglas Gilbert 	}
3237481b5e5cSDouglas Gilbert 	ret = 0;
3238481b5e5cSDouglas Gilbert err_out_unlock:
3239481b5e5cSDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3240481b5e5cSDouglas Gilbert err_out:
3241481b5e5cSDouglas Gilbert 	kfree(lrdp);
3242481b5e5cSDouglas Gilbert 	return ret;
3243481b5e5cSDouglas Gilbert }
3244481b5e5cSDouglas Gilbert 
3245fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3246fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
324744d92694SMartin K. Petersen {
324840d07b52SDouglas Gilbert 	int ret;
324944d92694SMartin K. Petersen 	unsigned long iflags;
325044d92694SMartin K. Petersen 	unsigned long long i;
325140d07b52SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
325240d07b52SDouglas Gilbert 	u64 block, lbaa;
325340d07b52SDouglas Gilbert 	u8 *fs1p;
325444d92694SMartin K. Petersen 
32559447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, true);
325644d92694SMartin K. Petersen 	if (ret)
325744d92694SMartin K. Petersen 		return ret;
325844d92694SMartin K. Petersen 
325944d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
326044d92694SMartin K. Petersen 
32619ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
326244d92694SMartin K. Petersen 		unmap_region(lba, num);
326344d92694SMartin K. Petersen 		goto out;
326444d92694SMartin K. Petersen 	}
326540d07b52SDouglas Gilbert 	lbaa = lba;
326640d07b52SDouglas Gilbert 	block = do_div(lbaa, sdebug_store_sectors);
3267c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
326840d07b52SDouglas Gilbert 	fs1p = fake_storep + (block * lb_size);
3269c2248fc9SDouglas Gilbert 	if (ndob) {
327040d07b52SDouglas Gilbert 		memset(fs1p, 0, lb_size);
3271c2248fc9SDouglas Gilbert 		ret = 0;
3272c2248fc9SDouglas Gilbert 	} else
327340d07b52SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
327444d92694SMartin K. Petersen 
327544d92694SMartin K. Petersen 	if (-1 == ret) {
327644d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3277773642d9SDouglas Gilbert 		return DID_ERROR << 16;
327840d07b52SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < lb_size))
3279c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3280e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
328140d07b52SDouglas Gilbert 			    my_name, "write same", lb_size, ret);
328244d92694SMartin K. Petersen 
328344d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
328440d07b52SDouglas Gilbert 	for (i = 1 ; i < num ; i++) {
328540d07b52SDouglas Gilbert 		lbaa = lba + i;
328640d07b52SDouglas Gilbert 		block = do_div(lbaa, sdebug_store_sectors);
328740d07b52SDouglas Gilbert 		memmove(fake_storep + (block * lb_size), fs1p, lb_size);
328840d07b52SDouglas Gilbert 	}
32899ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
329044d92694SMartin K. Petersen 		map_region(lba, num);
329144d92694SMartin K. Petersen out:
329244d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
329344d92694SMartin K. Petersen 
329444d92694SMartin K. Petersen 	return 0;
329544d92694SMartin K. Petersen }
329644d92694SMartin K. Petersen 
3297fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3298fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3299c2248fc9SDouglas Gilbert {
3300c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3301c2248fc9SDouglas Gilbert 	u32 lba;
3302c2248fc9SDouglas Gilbert 	u16 num;
3303c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3304c2248fc9SDouglas Gilbert 	bool unmap = false;
3305c2248fc9SDouglas Gilbert 
3306c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3307773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3308c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3309c2248fc9SDouglas Gilbert 			return check_condition_result;
3310c2248fc9SDouglas Gilbert 		} else
3311c2248fc9SDouglas Gilbert 			unmap = true;
3312c2248fc9SDouglas Gilbert 	}
3313c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3314c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3315773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3316c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3317c2248fc9SDouglas Gilbert 		return check_condition_result;
3318c2248fc9SDouglas Gilbert 	}
3319c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3320c2248fc9SDouglas Gilbert }
3321c2248fc9SDouglas Gilbert 
3322fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3323fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3324c2248fc9SDouglas Gilbert {
3325c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3326c2248fc9SDouglas Gilbert 	u64 lba;
3327c2248fc9SDouglas Gilbert 	u32 num;
3328c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3329c2248fc9SDouglas Gilbert 	bool unmap = false;
3330c2248fc9SDouglas Gilbert 	bool ndob = false;
3331c2248fc9SDouglas Gilbert 
3332c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3333773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3334c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3335c2248fc9SDouglas Gilbert 			return check_condition_result;
3336c2248fc9SDouglas Gilbert 		} else
3337c2248fc9SDouglas Gilbert 			unmap = true;
3338c2248fc9SDouglas Gilbert 	}
3339c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3340c2248fc9SDouglas Gilbert 		ndob = true;
3341c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3342c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3343773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3344c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3345c2248fc9SDouglas Gilbert 		return check_condition_result;
3346c2248fc9SDouglas Gilbert 	}
3347c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3348c2248fc9SDouglas Gilbert }
3349c2248fc9SDouglas Gilbert 
3350acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3351acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3352acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3353fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3354fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3355acafd0b9SEwan D. Milne {
3356acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3357acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3358acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3359acafd0b9SEwan D. Milne 	u8 mode;
3360acafd0b9SEwan D. Milne 
3361acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3362acafd0b9SEwan D. Milne 	switch (mode) {
3363acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3364acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3365acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3366acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3367acafd0b9SEwan D. Milne 		break;
3368acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3369acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3370acafd0b9SEwan D. Milne 		break;
3371acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3372acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3373acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3374acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3375acafd0b9SEwan D. Milne 				    dev_list)
3376acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3377acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3378acafd0b9SEwan D. Milne 				if (devip != dp)
3379acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3380acafd0b9SEwan D. Milne 						dp->uas_bm);
3381acafd0b9SEwan D. Milne 			}
3382acafd0b9SEwan D. Milne 		break;
3383acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3384acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3385acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3386acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3387acafd0b9SEwan D. Milne 				    dev_list)
3388acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3389acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3390acafd0b9SEwan D. Milne 					dp->uas_bm);
3391acafd0b9SEwan D. Milne 		break;
3392acafd0b9SEwan D. Milne 	default:
3393acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3394acafd0b9SEwan D. Milne 		break;
3395acafd0b9SEwan D. Milne 	}
3396acafd0b9SEwan D. Milne 	return 0;
3397acafd0b9SEwan D. Milne }
3398acafd0b9SEwan D. Milne 
3399fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3400fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
340138d5c833SDouglas Gilbert {
340238d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
340338d5c833SDouglas Gilbert 	u8 *arr;
340438d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
340538d5c833SDouglas Gilbert 	u64 lba;
340638d5c833SDouglas Gilbert 	u32 dnum;
3407773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
340838d5c833SDouglas Gilbert 	u8 num;
340938d5c833SDouglas Gilbert 	unsigned long iflags;
341038d5c833SDouglas Gilbert 	int ret;
3411d467d31fSDouglas Gilbert 	int retval = 0;
341238d5c833SDouglas Gilbert 
3413d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
341438d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
341538d5c833SDouglas Gilbert 	if (0 == num)
341638d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
34178475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
341838d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
341938d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
342038d5c833SDouglas Gilbert 		return check_condition_result;
342138d5c833SDouglas Gilbert 	}
34228475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34238475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
342438d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
342538d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
342638d5c833SDouglas Gilbert 			    "to DIF device\n");
34279447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, num, false);
34289447b6ceSMartin K. Petersen 	if (ret)
34299447b6ceSMartin K. Petersen 		return ret;
3430d467d31fSDouglas Gilbert 	dnum = 2 * num;
34316396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3432d467d31fSDouglas Gilbert 	if (NULL == arr) {
3433d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3434d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3435d467d31fSDouglas Gilbert 		return check_condition_result;
3436d467d31fSDouglas Gilbert 	}
343738d5c833SDouglas Gilbert 
343838d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
343938d5c833SDouglas Gilbert 
344038d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
344138d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
344238d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
344338d5c833SDouglas Gilbert 	fake_storep = arr;
34440a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, 0, dnum, true);
344538d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
344638d5c833SDouglas Gilbert 	if (ret == -1) {
3447d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3448d467d31fSDouglas Gilbert 		goto cleanup;
3449773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
345038d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
345138d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
345238d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
345338d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
345438d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3455d467d31fSDouglas Gilbert 		retval = check_condition_result;
3456d467d31fSDouglas Gilbert 		goto cleanup;
345738d5c833SDouglas Gilbert 	}
345838d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
345938d5c833SDouglas Gilbert 		map_region(lba, num);
3460d467d31fSDouglas Gilbert cleanup:
346138d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3462d467d31fSDouglas Gilbert 	kfree(arr);
3463d467d31fSDouglas Gilbert 	return retval;
346438d5c833SDouglas Gilbert }
346538d5c833SDouglas Gilbert 
346644d92694SMartin K. Petersen struct unmap_block_desc {
346744d92694SMartin K. Petersen 	__be64	lba;
346844d92694SMartin K. Petersen 	__be32	blocks;
346944d92694SMartin K. Petersen 	__be32	__reserved;
347044d92694SMartin K. Petersen };
347144d92694SMartin K. Petersen 
3472fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
347344d92694SMartin K. Petersen {
347444d92694SMartin K. Petersen 	unsigned char *buf;
347544d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
347644d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
347744d92694SMartin K. Petersen 	int ret;
34786c78cc06SAkinobu Mita 	unsigned long iflags;
347944d92694SMartin K. Petersen 
348044d92694SMartin K. Petersen 
3481c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3482c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3483c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3484c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
348544d92694SMartin K. Petersen 
348644d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3487773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3488c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
348944d92694SMartin K. Petersen 		return check_condition_result;
3490c2248fc9SDouglas Gilbert 	}
349144d92694SMartin K. Petersen 
3492b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3493c2248fc9SDouglas Gilbert 	if (!buf) {
3494c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3495c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3496c2248fc9SDouglas Gilbert 		return check_condition_result;
3497c2248fc9SDouglas Gilbert 	}
3498c2248fc9SDouglas Gilbert 
3499c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
350044d92694SMartin K. Petersen 
350144d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
350244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
350344d92694SMartin K. Petersen 
350444d92694SMartin K. Petersen 	desc = (void *)&buf[8];
350544d92694SMartin K. Petersen 
35066c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
35076c78cc06SAkinobu Mita 
350844d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
350944d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
351044d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
351144d92694SMartin K. Petersen 
35129447b6ceSMartin K. Petersen 		ret = check_device_access_params(scp, lba, num, true);
351344d92694SMartin K. Petersen 		if (ret)
351444d92694SMartin K. Petersen 			goto out;
351544d92694SMartin K. Petersen 
351644d92694SMartin K. Petersen 		unmap_region(lba, num);
351744d92694SMartin K. Petersen 	}
351844d92694SMartin K. Petersen 
351944d92694SMartin K. Petersen 	ret = 0;
352044d92694SMartin K. Petersen 
352144d92694SMartin K. Petersen out:
35226c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
352344d92694SMartin K. Petersen 	kfree(buf);
352444d92694SMartin K. Petersen 
352544d92694SMartin K. Petersen 	return ret;
352644d92694SMartin K. Petersen }
352744d92694SMartin K. Petersen 
352844d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
352944d92694SMartin K. Petersen 
3530fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3531fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
353244d92694SMartin K. Petersen {
3533c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3534c2248fc9SDouglas Gilbert 	u64 lba;
3535c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3536c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
353744d92694SMartin K. Petersen 	int ret;
353844d92694SMartin K. Petersen 
3539c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3540c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
354144d92694SMartin K. Petersen 
354244d92694SMartin K. Petersen 	if (alloc_len < 24)
354344d92694SMartin K. Petersen 		return 0;
354444d92694SMartin K. Petersen 
35459447b6ceSMartin K. Petersen 	ret = check_device_access_params(scp, lba, 1, false);
354644d92694SMartin K. Petersen 	if (ret)
354744d92694SMartin K. Petersen 		return ret;
354844d92694SMartin K. Petersen 
3549c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
355044d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3551c2248fc9SDouglas Gilbert 	else {
3552c2248fc9SDouglas Gilbert 		mapped = 1;
3553c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3554c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3555c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3556c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3557c2248fc9SDouglas Gilbert 		else
3558c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3559c2248fc9SDouglas Gilbert 	}
356044d92694SMartin K. Petersen 
356144d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3562c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3563c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3564c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3565c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
356644d92694SMartin K. Petersen 
3567c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
356844d92694SMartin K. Petersen }
356944d92694SMartin K. Petersen 
357080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
357180c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
357280c49563SDouglas Gilbert {
35734f2c8bf6SDouglas Gilbert 	int res = 0;
357480c49563SDouglas Gilbert 	u64 lba;
357580c49563SDouglas Gilbert 	u32 num_blocks;
357680c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
357780c49563SDouglas Gilbert 
357880c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
357980c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
358080c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
358180c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
358280c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
358380c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
358480c49563SDouglas Gilbert 	}
358580c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
358680c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
358780c49563SDouglas Gilbert 		return check_condition_result;
358880c49563SDouglas Gilbert 	}
35894f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
35904f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
35914f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
35924f2c8bf6SDouglas Gilbert 		write_since_sync = false;
35934f2c8bf6SDouglas Gilbert 	return res;
359480c49563SDouglas Gilbert }
359580c49563SDouglas Gilbert 
3596fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3597fb0cc8d1SDouglas Gilbert 
35988d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
35998d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
36008d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
36018d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
36028d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
36038d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
36048d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
36058d039e22SDouglas Gilbert  */
36061da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
36071da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
36081da177e4SLinus Torvalds {
360901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
36108d039e22SDouglas Gilbert 	unsigned int alloc_len;
36118d039e22SDouglas Gilbert 	unsigned char select_report;
36128d039e22SDouglas Gilbert 	u64 lun;
36138d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3614fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
36158d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
36168d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
36178d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
36188d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3619fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3620fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3621fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
36221da177e4SLinus Torvalds 
362319c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
36248d039e22SDouglas Gilbert 
36258d039e22SDouglas Gilbert 	select_report = cmd[2];
36268d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
36278d039e22SDouglas Gilbert 
36288d039e22SDouglas Gilbert 	if (alloc_len < 4) {
36298d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
36308d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
36311da177e4SLinus Torvalds 		return check_condition_result;
36321da177e4SLinus Torvalds 	}
36338d039e22SDouglas Gilbert 
36348d039e22SDouglas Gilbert 	switch (select_report) {
36358d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3636773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36378d039e22SDouglas Gilbert 		wlun_cnt = 0;
36388d039e22SDouglas Gilbert 		break;
36398d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3640c65b1445SDouglas Gilbert 		lun_cnt = 0;
36418d039e22SDouglas Gilbert 		wlun_cnt = 1;
36428d039e22SDouglas Gilbert 		break;
36438d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
36448d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36458d039e22SDouglas Gilbert 		wlun_cnt = 1;
36468d039e22SDouglas Gilbert 		break;
36478d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
36488d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
36498d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
36508d039e22SDouglas Gilbert 	default:
36518d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
36528d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
36538d039e22SDouglas Gilbert 		return check_condition_result;
36548d039e22SDouglas Gilbert 	}
36558d039e22SDouglas Gilbert 
36568d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3657c65b1445SDouglas Gilbert 		--lun_cnt;
36588d039e22SDouglas Gilbert 
36598d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3660fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3661fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
36628d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
36638d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
36648d039e22SDouglas Gilbert 
3665fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
36668d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3667fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3668fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3669fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3670fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3671fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3672fb0cc8d1SDouglas Gilbert 			++lun_p;
3673fb0cc8d1SDouglas Gilbert 			j = 1;
3674fb0cc8d1SDouglas Gilbert 		}
3675fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3676fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3677fb0cc8d1SDouglas Gilbert 				break;
3678fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3679fb0cc8d1SDouglas Gilbert 		}
3680fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3681fb0cc8d1SDouglas Gilbert 			break;
3682fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3683fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3684fb0cc8d1SDouglas Gilbert 		if (res)
3685fb0cc8d1SDouglas Gilbert 			return res;
3686fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3687fb0cc8d1SDouglas Gilbert 	}
3688fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3689fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3690fb0cc8d1SDouglas Gilbert 		++j;
3691fb0cc8d1SDouglas Gilbert 	}
3692fb0cc8d1SDouglas Gilbert 	if (j > 0)
3693fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
36948d039e22SDouglas Gilbert 	return res;
36951da177e4SLinus Torvalds }
36961da177e4SLinus Torvalds 
3697c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3698c4837394SDouglas Gilbert {
3699c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
3700c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3701c4837394SDouglas Gilbert 
3702458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3703458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
3704458df78bSBart Van Assche 		hwq = 0;
3705458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
3706c4837394SDouglas Gilbert }
3707c4837394SDouglas Gilbert 
3708c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3709fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
37101da177e4SLinus Torvalds {
37117382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
3712c4837394SDouglas Gilbert 	int qc_idx;
3713cbf67842SDouglas Gilbert 	int retiring = 0;
37141da177e4SLinus Torvalds 	unsigned long iflags;
3715c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3716cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3717cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3718cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
37191da177e4SLinus Torvalds 
372010bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
37217382f9d8SDouglas Gilbert 	if (unlikely(aborted))
37227382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
3723c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3724c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3725c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3726cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3727c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3728c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3729c4837394SDouglas Gilbert 	}
3730c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3731c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
37321da177e4SLinus Torvalds 		return;
37331da177e4SLinus Torvalds 	}
3734c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3735c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3736cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3737b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3738c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3739c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3740c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
37411da177e4SLinus Torvalds 		return;
37421da177e4SLinus Torvalds 	}
3743cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3744f46eb0e9SDouglas Gilbert 	if (likely(devip))
3745cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3746cbf67842SDouglas Gilbert 	else
3747c1287970STomas Winkler 		pr_err("devip=NULL\n");
3748f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3749cbf67842SDouglas Gilbert 		retiring = 1;
3750cbf67842SDouglas Gilbert 
3751cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3752c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3753c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3754c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3755cbf67842SDouglas Gilbert 		return;
37561da177e4SLinus Torvalds 	}
37571da177e4SLinus Torvalds 
3758cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3759cbf67842SDouglas Gilbert 		int k, retval;
3760cbf67842SDouglas Gilbert 
3761cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3762c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3763c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3764c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3765cbf67842SDouglas Gilbert 			return;
3766cbf67842SDouglas Gilbert 		}
3767c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3768773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3769cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3770cbf67842SDouglas Gilbert 		else
3771cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3772cbf67842SDouglas Gilbert 	}
3773c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
37747382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
37757382f9d8SDouglas Gilbert 		if (sdebug_verbose)
37767382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
37777382f9d8SDouglas Gilbert 		return;
37787382f9d8SDouglas Gilbert 	}
3779cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3780cbf67842SDouglas Gilbert }
3781cbf67842SDouglas Gilbert 
3782cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3783fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3784cbf67842SDouglas Gilbert {
3785a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3786a10bc12aSDouglas Gilbert 						  hrt);
3787a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3788cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3789cbf67842SDouglas Gilbert }
37901da177e4SLinus Torvalds 
3791a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3792fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3793a10bc12aSDouglas Gilbert {
3794a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3795a10bc12aSDouglas Gilbert 						  ew.work);
3796a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3797a10bc12aSDouglas Gilbert }
3798a10bc12aSDouglas Gilbert 
379909ba24c1SDouglas Gilbert static bool got_shared_uuid;
3800bf476433SChristoph Hellwig static uuid_t shared_uuid;
380109ba24c1SDouglas Gilbert 
3802fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3803fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
38045cb2fc06SFUJITA Tomonori {
38055cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
38065cb2fc06SFUJITA Tomonori 
38075cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
38085cb2fc06SFUJITA Tomonori 	if (devip) {
380909ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3810bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
381109ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
381209ba24c1SDouglas Gilbert 			if (got_shared_uuid)
381309ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
381409ba24c1SDouglas Gilbert 			else {
3815bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
381609ba24c1SDouglas Gilbert 				got_shared_uuid = true;
381709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
381809ba24c1SDouglas Gilbert 			}
381909ba24c1SDouglas Gilbert 		}
38205cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
38215cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
38225cb2fc06SFUJITA Tomonori 	}
38235cb2fc06SFUJITA Tomonori 	return devip;
38245cb2fc06SFUJITA Tomonori }
38255cb2fc06SFUJITA Tomonori 
3826f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
38271da177e4SLinus Torvalds {
38281da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
38291da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3830f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
38311da177e4SLinus Torvalds 
3832d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
38331da177e4SLinus Torvalds 	if (!sdbg_host) {
3834c1287970STomas Winkler 		pr_err("Host info NULL\n");
38351da177e4SLinus Torvalds 		return NULL;
38361da177e4SLinus Torvalds 	}
38371da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
38381da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
38391da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
38401da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
38411da177e4SLinus Torvalds 			return devip;
38421da177e4SLinus Torvalds 		else {
38431da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
38441da177e4SLinus Torvalds 				open_devip = devip;
38451da177e4SLinus Torvalds 		}
38461da177e4SLinus Torvalds 	}
38475cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
38485cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
38495cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3850c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
38511da177e4SLinus Torvalds 			return NULL;
38521da177e4SLinus Torvalds 		}
38531da177e4SLinus Torvalds 	}
3854a75869d1SFUJITA Tomonori 
38551da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
38561da177e4SLinus Torvalds 	open_devip->target = sdev->id;
38571da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
38581da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3859cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3860cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3861c2248fc9SDouglas Gilbert 	open_devip->used = true;
38621da177e4SLinus Torvalds 	return open_devip;
38631da177e4SLinus Torvalds }
38641da177e4SLinus Torvalds 
38658dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
38661da177e4SLinus Torvalds {
3867773642d9SDouglas Gilbert 	if (sdebug_verbose)
3868c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
38698dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
38708dea0d02SFUJITA Tomonori 	return 0;
38718dea0d02SFUJITA Tomonori }
38721da177e4SLinus Torvalds 
38738dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
38748dea0d02SFUJITA Tomonori {
3875f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3876f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3877a34c4e98SFUJITA Tomonori 
3878773642d9SDouglas Gilbert 	if (sdebug_verbose)
3879c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
38808dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3881b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3882b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3883b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3884f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3885b01f6f83SDouglas Gilbert 		if (devip == NULL)
38868dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3887f46eb0e9SDouglas Gilbert 	}
3888c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
3889773642d9SDouglas Gilbert 	if (sdebug_no_uld)
389078d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
38919b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
38928dea0d02SFUJITA Tomonori 	return 0;
38938dea0d02SFUJITA Tomonori }
38948dea0d02SFUJITA Tomonori 
38958dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
38968dea0d02SFUJITA Tomonori {
38978dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
38988dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
38998dea0d02SFUJITA Tomonori 
3900773642d9SDouglas Gilbert 	if (sdebug_verbose)
3901c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
39028dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39038dea0d02SFUJITA Tomonori 	if (devip) {
390425985edcSLucas De Marchi 		/* make this slot available for re-use */
3905c2248fc9SDouglas Gilbert 		devip->used = false;
39068dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
39078dea0d02SFUJITA Tomonori 	}
39088dea0d02SFUJITA Tomonori }
39098dea0d02SFUJITA Tomonori 
391010bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
391110bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
3912c4837394SDouglas Gilbert {
3913c4837394SDouglas Gilbert 	if (!sd_dp)
3914c4837394SDouglas Gilbert 		return;
391510bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
3916c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
391710bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
3918c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3919c4837394SDouglas Gilbert }
3920c4837394SDouglas Gilbert 
3921a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3922a10bc12aSDouglas Gilbert    returns false */
3923a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
39248dea0d02SFUJITA Tomonori {
39258dea0d02SFUJITA Tomonori 	unsigned long iflags;
3926c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
392710bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
3928c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
39298dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3930cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3931a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39328dea0d02SFUJITA Tomonori 
3933c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3934c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3935773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3936cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3937cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3938cbf67842SDouglas Gilbert 			qmax = r_qmax;
3939cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3940c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3941c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3942a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3943a10bc12aSDouglas Gilbert 					continue;
3944c4837394SDouglas Gilbert 				/* found */
3945db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3946db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3947db525fceSDouglas Gilbert 				if (devip)
3948db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3949db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3950a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
395110bde980SDouglas Gilbert 				if (sd_dp) {
395210bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
395310bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
395410bde980SDouglas Gilbert 				} else
395510bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
3956c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
395710bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
3958c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3959a10bc12aSDouglas Gilbert 				return true;
39608dea0d02SFUJITA Tomonori 			}
3961cbf67842SDouglas Gilbert 		}
3962c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3963c4837394SDouglas Gilbert 	}
3964a10bc12aSDouglas Gilbert 	return false;
39658dea0d02SFUJITA Tomonori }
39668dea0d02SFUJITA Tomonori 
3967a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
39688dea0d02SFUJITA Tomonori static void stop_all_queued(void)
39698dea0d02SFUJITA Tomonori {
39708dea0d02SFUJITA Tomonori 	unsigned long iflags;
3971c4837394SDouglas Gilbert 	int j, k;
397210bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
3973c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
39748dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3975cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3976a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39778dea0d02SFUJITA Tomonori 
3978c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3979c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3980c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3981c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3982c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3983c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3984a10bc12aSDouglas Gilbert 					continue;
3985db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3986db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3987db525fceSDouglas Gilbert 				if (devip)
3988db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3989db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3990a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
399110bde980SDouglas Gilbert 				if (sd_dp) {
399210bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
399310bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
399410bde980SDouglas Gilbert 				} else
399510bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
3996c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
399710bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
3998c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3999c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
40008dea0d02SFUJITA Tomonori 			}
40018dea0d02SFUJITA Tomonori 		}
4002c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4003c4837394SDouglas Gilbert 	}
4004cbf67842SDouglas Gilbert }
4005cbf67842SDouglas Gilbert 
4006cbf67842SDouglas Gilbert /* Free queued command memory on heap */
4007cbf67842SDouglas Gilbert static void free_all_queued(void)
4008cbf67842SDouglas Gilbert {
4009c4837394SDouglas Gilbert 	int j, k;
4010c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4011cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4012cbf67842SDouglas Gilbert 
4013c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4014c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4015c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
4016a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
4017a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
4018cbf67842SDouglas Gilbert 		}
40191da177e4SLinus Torvalds 	}
4020c4837394SDouglas Gilbert }
40211da177e4SLinus Torvalds 
40221da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
40231da177e4SLinus Torvalds {
4024a10bc12aSDouglas Gilbert 	bool ok;
4025a10bc12aSDouglas Gilbert 
40261da177e4SLinus Torvalds 	++num_aborts;
4027cbf67842SDouglas Gilbert 	if (SCpnt) {
4028a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
4029a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4030a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4031a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
4032a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
4033cbf67842SDouglas Gilbert 	}
40341da177e4SLinus Torvalds 	return SUCCESS;
40351da177e4SLinus Torvalds }
40361da177e4SLinus Torvalds 
40371da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
40381da177e4SLinus Torvalds {
40391da177e4SLinus Torvalds 	++num_dev_resets;
4040cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
4041cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
4042f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
4043f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
4044cbf67842SDouglas Gilbert 
4045773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4046cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
40471da177e4SLinus Torvalds 		if (devip)
4048cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
40491da177e4SLinus Torvalds 	}
40501da177e4SLinus Torvalds 	return SUCCESS;
40511da177e4SLinus Torvalds }
40521da177e4SLinus Torvalds 
4053cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4054cbf67842SDouglas Gilbert {
4055cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
4056cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4057cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
4058cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
4059cbf67842SDouglas Gilbert 	int k = 0;
4060cbf67842SDouglas Gilbert 
4061cbf67842SDouglas Gilbert 	++num_target_resets;
4062cbf67842SDouglas Gilbert 	if (!SCpnt)
4063cbf67842SDouglas Gilbert 		goto lie;
4064cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4065cbf67842SDouglas Gilbert 	if (!sdp)
4066cbf67842SDouglas Gilbert 		goto lie;
4067773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4068cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4069cbf67842SDouglas Gilbert 	hp = sdp->host;
4070cbf67842SDouglas Gilbert 	if (!hp)
4071cbf67842SDouglas Gilbert 		goto lie;
4072cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4073cbf67842SDouglas Gilbert 	if (sdbg_host) {
4074cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
4075cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
4076cbf67842SDouglas Gilbert 				    dev_list)
4077cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
4078cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4079cbf67842SDouglas Gilbert 				++k;
4080cbf67842SDouglas Gilbert 			}
4081cbf67842SDouglas Gilbert 	}
4082773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4083cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4084cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
4085cbf67842SDouglas Gilbert lie:
4086cbf67842SDouglas Gilbert 	return SUCCESS;
4087cbf67842SDouglas Gilbert }
4088cbf67842SDouglas Gilbert 
40891da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
40901da177e4SLinus Torvalds {
40911da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4092cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
40931da177e4SLinus Torvalds 	struct scsi_device *sdp;
40941da177e4SLinus Torvalds 	struct Scsi_Host *hp;
4095cbf67842SDouglas Gilbert 	int k = 0;
40961da177e4SLinus Torvalds 
40971da177e4SLinus Torvalds 	++num_bus_resets;
4098cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
4099cbf67842SDouglas Gilbert 		goto lie;
4100cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4101773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4102cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4103cbf67842SDouglas Gilbert 	hp = sdp->host;
4104cbf67842SDouglas Gilbert 	if (hp) {
4105d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
41061da177e4SLinus Torvalds 		if (sdbg_host) {
4107cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
41081da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
4109cbf67842SDouglas Gilbert 					    dev_list) {
4110cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4111cbf67842SDouglas Gilbert 				++k;
41121da177e4SLinus Torvalds 			}
41131da177e4SLinus Torvalds 		}
4114cbf67842SDouglas Gilbert 	}
4115773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4116cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4117cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
4118cbf67842SDouglas Gilbert lie:
41191da177e4SLinus Torvalds 	return SUCCESS;
41201da177e4SLinus Torvalds }
41211da177e4SLinus Torvalds 
41221da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
41231da177e4SLinus Torvalds {
41241da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4125cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4126cbf67842SDouglas Gilbert 	int k = 0;
41271da177e4SLinus Torvalds 
41281da177e4SLinus Torvalds 	++num_host_resets;
4129773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4130cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
41311da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
41321da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
4133cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
4134cbf67842SDouglas Gilbert 				    dev_list) {
4135cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4136cbf67842SDouglas Gilbert 			++k;
4137cbf67842SDouglas Gilbert 		}
41381da177e4SLinus Torvalds 	}
41391da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
41401da177e4SLinus Torvalds 	stop_all_queued();
4141773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4142cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
4143cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
41441da177e4SLinus Torvalds 	return SUCCESS;
41451da177e4SLinus Torvalds }
41461da177e4SLinus Torvalds 
4147f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
41485f2578e5SFUJITA Tomonori 				      unsigned long store_size)
41491da177e4SLinus Torvalds {
41501442f76dSChristoph Hellwig 	struct msdos_partition *pp;
41511da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
41521da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
41531da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
41541da177e4SLinus Torvalds 
41551da177e4SLinus Torvalds 	/* assume partition table already zeroed */
4156773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
41571da177e4SLinus Torvalds 		return;
4158773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4159773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
4160c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
41611da177e4SLinus Torvalds 	}
4162c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
41631da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4164773642d9SDouglas Gilbert 			   / sdebug_num_parts;
41651da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
41661da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4167773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
41681da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
41691da177e4SLinus Torvalds 			    * heads_by_sects;
4170773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4171773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
41721da177e4SLinus Torvalds 
41731da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
41741da177e4SLinus Torvalds 	ramp[511] = 0xAA;
41751442f76dSChristoph Hellwig 	pp = (struct msdos_partition *)(ramp + 0x1be);
41761da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
41771da177e4SLinus Torvalds 		start_sec = starts[k];
41781da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
41791da177e4SLinus Torvalds 		pp->boot_ind = 0;
41801da177e4SLinus Torvalds 
41811da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
41821da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
41831da177e4SLinus Torvalds 			   / sdebug_sectors_per;
41841da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
41851da177e4SLinus Torvalds 
41861da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
41871da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
41881da177e4SLinus Torvalds 			       / sdebug_sectors_per;
41891da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
41901da177e4SLinus Torvalds 
4191150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4192150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
41931da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
41941da177e4SLinus Torvalds 	}
41951da177e4SLinus Torvalds }
41961da177e4SLinus Torvalds 
4197c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4198c4837394SDouglas Gilbert {
4199c4837394SDouglas Gilbert 	int j;
4200c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4201c4837394SDouglas Gilbert 
4202c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4203c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4204c4837394SDouglas Gilbert }
4205c4837394SDouglas Gilbert 
4206c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4207c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4208c4837394SDouglas Gilbert  */
4209c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4210c4837394SDouglas Gilbert {
4211c4837394SDouglas Gilbert 	int count, modulo;
4212c4837394SDouglas Gilbert 
4213c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4214c4837394SDouglas Gilbert 	if (modulo < 2)
4215c4837394SDouglas Gilbert 		return;
4216c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4217c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4218c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4219c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4220c4837394SDouglas Gilbert }
4221c4837394SDouglas Gilbert 
4222c4837394SDouglas Gilbert static void clear_queue_stats(void)
4223c4837394SDouglas Gilbert {
4224c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4225c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4226c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4227c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4228c4837394SDouglas Gilbert }
4229c4837394SDouglas Gilbert 
4230c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4231c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4232c4837394SDouglas Gilbert {
4233f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4234f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
4235f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
4236f9ba7af8SMartin Wilck 				= sqcp->inj_dif
42377382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
42387382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
4239c4837394SDouglas Gilbert 		return;
4240f9ba7af8SMartin Wilck 	}
4241c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4242c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4243c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4244c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4245c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
42467ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
42477382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
4248c4837394SDouglas Gilbert }
4249c4837394SDouglas Gilbert 
4250c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4251c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4252c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4253c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4254c4837394SDouglas Gilbert  */
4255fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4256f66b8517SMartin Wilck 			 int scsi_result,
4257f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
4258f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
4259f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
42601da177e4SLinus Torvalds {
4261cbf67842SDouglas Gilbert 	unsigned long iflags;
4262cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4263c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4264c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4265299b6c07STomas Winkler 	struct scsi_device *sdp;
4266a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
42671da177e4SLinus Torvalds 
4268b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4269b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4270f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4271f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
42721da177e4SLinus Torvalds 	}
4273299b6c07STomas Winkler 	sdp = cmnd->device;
4274299b6c07STomas Winkler 
4275cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4276cd62b7daSDouglas Gilbert 		goto respond_in_thread;
42771da177e4SLinus Torvalds 
4278cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4279c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4280c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4281c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4282c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4283c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4284c4837394SDouglas Gilbert 	}
4285cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4286cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4287cbf67842SDouglas Gilbert 	inject = 0;
4288f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4289cd62b7daSDouglas Gilbert 		if (scsi_result) {
4290c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4291cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4292cd62b7daSDouglas Gilbert 		} else
4293cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4294c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4295773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4296f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4297cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4298cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4299773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4300cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4301cbf67842SDouglas Gilbert 			inject = 1;
4302cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
43031da177e4SLinus Torvalds 		}
4304cbf67842SDouglas Gilbert 	}
4305cbf67842SDouglas Gilbert 
4306c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4307f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4308c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4309cd62b7daSDouglas Gilbert 		if (scsi_result)
4310cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4311773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4312cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4313773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4314cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4315cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4316773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4317cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4318cbf67842SDouglas Gilbert 						    "report: host busy"));
4319cd62b7daSDouglas Gilbert 		if (scsi_result)
4320cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4321cd62b7daSDouglas Gilbert 		else
4322cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
43231da177e4SLinus Torvalds 	}
4324c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4325cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4326c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
43271da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4328c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4329a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4330c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4331c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4332c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
433310bde980SDouglas Gilbert 	if (sd_dp == NULL) {
433410bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
433510bde980SDouglas Gilbert 		if (sd_dp == NULL)
433610bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
433710bde980SDouglas Gilbert 	}
4338f66b8517SMartin Wilck 
4339f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4340f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
4341f66b8517SMartin Wilck 		/*
4342f66b8517SMartin Wilck 		 * This is the F_DELAY_OVERR case. No delay.
4343f66b8517SMartin Wilck 		 */
4344f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
4345f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
4346f66b8517SMartin Wilck 	}
4347f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4348f66b8517SMartin Wilck 		cmnd->result = scsi_result;
4349f66b8517SMartin Wilck 
4350f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
4351f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4352f66b8517SMartin Wilck 			    __func__, cmnd->result);
4353f66b8517SMartin Wilck 
435410bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
4355b333a819SDouglas Gilbert 		ktime_t kt;
4356cbf67842SDouglas Gilbert 
4357b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
435813f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4359b333a819SDouglas Gilbert 		} else
436010bde980SDouglas Gilbert 			kt = ndelay;
436110bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
436210bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
4363a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4364a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4365c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4366a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4367c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4368c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4369cbf67842SDouglas Gilbert 		}
4370c4837394SDouglas Gilbert 		if (sdebug_statistics)
4371c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
437210bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
4373c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4374c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
437510bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
437610bde980SDouglas Gilbert 			sd_dp->init_wq = true;
4377a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4378c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4379c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4380a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4381cbf67842SDouglas Gilbert 		}
4382c4837394SDouglas Gilbert 		if (sdebug_statistics)
4383c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
438410bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
43857382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
43867382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
4387a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
43887382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
43897382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
43907382f9d8SDouglas Gilbert 				    cmnd->request->tag);
43917382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
43927382f9d8SDouglas Gilbert 		}
4393cbf67842SDouglas Gilbert 	}
4394f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4395f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4396cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4397cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4398cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4399cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
44001da177e4SLinus Torvalds 	return 0;
4401cd62b7daSDouglas Gilbert 
4402cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4403f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4404f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
4405f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4406cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
4407cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4408cd62b7daSDouglas Gilbert 	return 0;
44091da177e4SLinus Torvalds }
4410cbf67842SDouglas Gilbert 
441123183910SDouglas Gilbert /* Note: The following macros create attribute files in the
441223183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
441323183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
441423183910SDouglas Gilbert    as it can when the corresponding attribute in the
441523183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
441623183910SDouglas Gilbert  */
4417773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4418773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
44199b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4420773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4421c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4422773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4423773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4424773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4425773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4426773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4427773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4428773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4429773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4430e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4431e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4432e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4433e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4434e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4435e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4436773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4437773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4438773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4439773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4440773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4441773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4442773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4443d9da891aSLaurence Oberman module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4444d9da891aSLaurence Oberman module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
4445773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4446773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4447773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4448773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4449773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4450773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4451773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4452773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
445386e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4454773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4455773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4456773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4457773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4458c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4459773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4460c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4461773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4462773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4463773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4464773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4465773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
446609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4467773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
446823183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
44699447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
4470773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
44715b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
44721da177e4SLinus Torvalds 
44731da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
44741da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
44751da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4476b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
44771da177e4SLinus Torvalds 
44781da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
44795b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
44809b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
44810759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4482cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4483c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
44845b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
44855b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4486c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4487beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
448823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
44895b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4490185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4491e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4492e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
44939b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
44949b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
44955b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
44965b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
44975b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4498760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4499760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
45005b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4501c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4502cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4503d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4504d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
4505cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4506c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
450778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
45081da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4509c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
451032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
45116f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
45125b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
451386e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
45141da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4515d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4516760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4517ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4518c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4519c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4520c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
45215b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
45225b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
45236014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
45246014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
452509ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
452609ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4527c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
45285b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
45299447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)");
45305b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
45311da177e4SLinus Torvalds 
4532760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4533760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
45341da177e4SLinus Torvalds 
45351da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
45361da177e4SLinus Torvalds {
4537c4837394SDouglas Gilbert 	int k;
4538c4837394SDouglas Gilbert 
4539760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4540760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4541760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4542c4837394SDouglas Gilbert 		return sdebug_info;
4543760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4544760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4545760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4546760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
45471da177e4SLinus Torvalds 	return sdebug_info;
45481da177e4SLinus Torvalds }
45491da177e4SLinus Torvalds 
4550cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4551fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4552fd32119bSDouglas Gilbert 				 int length)
45531da177e4SLinus Torvalds {
45541da177e4SLinus Torvalds 	char arr[16];
4555c8ed555aSAl Viro 	int opts;
45561da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
45571da177e4SLinus Torvalds 
45581da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
45591da177e4SLinus Torvalds 		return -EACCES;
45601da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
45611da177e4SLinus Torvalds 	arr[minLen] = '\0';
4562c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
45631da177e4SLinus Torvalds 		return -EINVAL;
4564773642d9SDouglas Gilbert 	sdebug_opts = opts;
4565773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4566773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4567773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4568c4837394SDouglas Gilbert 		tweak_cmnd_count();
45691da177e4SLinus Torvalds 	return length;
45701da177e4SLinus Torvalds }
4571c8ed555aSAl Viro 
4572cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4573cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4574cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4575c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4576c8ed555aSAl Viro {
4577c4837394SDouglas Gilbert 	int f, j, l;
4578c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4579cbf67842SDouglas Gilbert 
4580c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4581c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4582c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4583c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4584c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4585c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4586c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4587c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4588c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4589c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4590c4837394SDouglas Gilbert 		   num_aborts);
4591c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4592c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4593c4837394SDouglas Gilbert 		   num_host_resets);
4594c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4595c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4596458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4597458df78bSBart Van Assche 		   sdebug_statistics);
4598c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4599c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4600c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4601c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4602c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4603cbf67842SDouglas Gilbert 
4604c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4605c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4606c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4607c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4608773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4609c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4610c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4611c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4612c4837394SDouglas Gilbert 		}
4613cbf67842SDouglas Gilbert 	}
4614c8ed555aSAl Viro 	return 0;
46151da177e4SLinus Torvalds }
46161da177e4SLinus Torvalds 
461782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
46181da177e4SLinus Torvalds {
4619c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
46201da177e4SLinus Torvalds }
4621c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4622c4837394SDouglas Gilbert  * of delay is jiffies.
4623c4837394SDouglas Gilbert  */
462482069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
462582069379SAkinobu Mita 			   size_t count)
46261da177e4SLinus Torvalds {
4627c2206098SDouglas Gilbert 	int jdelay, res;
46281da177e4SLinus Torvalds 
4629b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4630cbf67842SDouglas Gilbert 		res = count;
4631c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4632c4837394SDouglas Gilbert 			int j, k;
4633c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4634cbf67842SDouglas Gilbert 
4635c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4636c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4637c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4638c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4639c4837394SDouglas Gilbert 						   sdebug_max_queue);
4640c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4641c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4642c4837394SDouglas Gilbert 					break;
4643c4837394SDouglas Gilbert 				}
4644c4837394SDouglas Gilbert 			}
4645c4837394SDouglas Gilbert 			if (res > 0) {
4646c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4647773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
46481da177e4SLinus Torvalds 			}
4649c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4650cbf67842SDouglas Gilbert 		}
4651cbf67842SDouglas Gilbert 		return res;
46521da177e4SLinus Torvalds 	}
46531da177e4SLinus Torvalds 	return -EINVAL;
46541da177e4SLinus Torvalds }
465582069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
46561da177e4SLinus Torvalds 
4657cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4658cbf67842SDouglas Gilbert {
4659773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4660cbf67842SDouglas Gilbert }
4661cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4662c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4663cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4664cbf67842SDouglas Gilbert 			    size_t count)
4665cbf67842SDouglas Gilbert {
4666c4837394SDouglas Gilbert 	int ndelay, res;
4667cbf67842SDouglas Gilbert 
4668cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4669c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4670cbf67842SDouglas Gilbert 		res = count;
4671773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4672c4837394SDouglas Gilbert 			int j, k;
4673c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4674c4837394SDouglas Gilbert 
4675c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4676c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4677c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4678c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4679c4837394SDouglas Gilbert 						   sdebug_max_queue);
4680c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4681c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4682c4837394SDouglas Gilbert 					break;
4683c4837394SDouglas Gilbert 				}
4684c4837394SDouglas Gilbert 			}
4685c4837394SDouglas Gilbert 			if (res > 0) {
4686773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4687c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4688c2206098SDouglas Gilbert 							: DEF_JDELAY;
4689cbf67842SDouglas Gilbert 			}
4690c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4691cbf67842SDouglas Gilbert 		}
4692cbf67842SDouglas Gilbert 		return res;
4693cbf67842SDouglas Gilbert 	}
4694cbf67842SDouglas Gilbert 	return -EINVAL;
4695cbf67842SDouglas Gilbert }
4696cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4697cbf67842SDouglas Gilbert 
469882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
46991da177e4SLinus Torvalds {
4700773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
47011da177e4SLinus Torvalds }
47021da177e4SLinus Torvalds 
470382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
470482069379SAkinobu Mita 			  size_t count)
47051da177e4SLinus Torvalds {
47061da177e4SLinus Torvalds 	int opts;
47071da177e4SLinus Torvalds 	char work[20];
47081da177e4SLinus Torvalds 
47099a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
47109a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
47119a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
47121da177e4SLinus Torvalds 				goto opts_done;
47131da177e4SLinus Torvalds 		} else {
47149a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
47151da177e4SLinus Torvalds 				goto opts_done;
47161da177e4SLinus Torvalds 		}
47171da177e4SLinus Torvalds 	}
47181da177e4SLinus Torvalds 	return -EINVAL;
47191da177e4SLinus Torvalds opts_done:
4720773642d9SDouglas Gilbert 	sdebug_opts = opts;
4721773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4722773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4723c4837394SDouglas Gilbert 	tweak_cmnd_count();
47241da177e4SLinus Torvalds 	return count;
47251da177e4SLinus Torvalds }
472682069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
47271da177e4SLinus Torvalds 
472882069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
47291da177e4SLinus Torvalds {
4730773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
47311da177e4SLinus Torvalds }
473282069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
473382069379SAkinobu Mita 			   size_t count)
47341da177e4SLinus Torvalds {
47351da177e4SLinus Torvalds 	int n;
47361da177e4SLinus Torvalds 
47371da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4738773642d9SDouglas Gilbert 		sdebug_ptype = n;
47391da177e4SLinus Torvalds 		return count;
47401da177e4SLinus Torvalds 	}
47411da177e4SLinus Torvalds 	return -EINVAL;
47421da177e4SLinus Torvalds }
474382069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
47441da177e4SLinus Torvalds 
474582069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
47461da177e4SLinus Torvalds {
4747773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
47481da177e4SLinus Torvalds }
474982069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
475082069379SAkinobu Mita 			    size_t count)
47511da177e4SLinus Torvalds {
47521da177e4SLinus Torvalds 	int n;
47531da177e4SLinus Torvalds 
47541da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4755773642d9SDouglas Gilbert 		sdebug_dsense = n;
47561da177e4SLinus Torvalds 		return count;
47571da177e4SLinus Torvalds 	}
47581da177e4SLinus Torvalds 	return -EINVAL;
47591da177e4SLinus Torvalds }
476082069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
47611da177e4SLinus Torvalds 
476282069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
476323183910SDouglas Gilbert {
4764773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
476523183910SDouglas Gilbert }
476682069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
476782069379SAkinobu Mita 			     size_t count)
476823183910SDouglas Gilbert {
476923183910SDouglas Gilbert 	int n;
477023183910SDouglas Gilbert 
477123183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4772cbf67842SDouglas Gilbert 		n = (n > 0);
4773773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4774773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4775cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4776cbf67842SDouglas Gilbert 				unsigned long sz =
4777773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4778cbf67842SDouglas Gilbert 					1048576;
4779cbf67842SDouglas Gilbert 
47807382f9d8SDouglas Gilbert 				fake_storep = vzalloc(sz);
4781cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4782c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4783cbf67842SDouglas Gilbert 					return -ENOMEM;
4784cbf67842SDouglas Gilbert 				}
4785cbf67842SDouglas Gilbert 			}
4786773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4787cbf67842SDouglas Gilbert 		}
478823183910SDouglas Gilbert 		return count;
478923183910SDouglas Gilbert 	}
479023183910SDouglas Gilbert 	return -EINVAL;
479123183910SDouglas Gilbert }
479282069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
479323183910SDouglas Gilbert 
479482069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4795c65b1445SDouglas Gilbert {
4796773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4797c65b1445SDouglas Gilbert }
479882069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
479982069379SAkinobu Mita 			      size_t count)
4800c65b1445SDouglas Gilbert {
4801c65b1445SDouglas Gilbert 	int n;
4802c65b1445SDouglas Gilbert 
4803c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4804773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4805c65b1445SDouglas Gilbert 		return count;
4806c65b1445SDouglas Gilbert 	}
4807c65b1445SDouglas Gilbert 	return -EINVAL;
4808c65b1445SDouglas Gilbert }
480982069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4810c65b1445SDouglas Gilbert 
481182069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
48121da177e4SLinus Torvalds {
4813773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
48141da177e4SLinus Torvalds }
481582069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
481682069379SAkinobu Mita 			      size_t count)
48171da177e4SLinus Torvalds {
48181da177e4SLinus Torvalds 	int n;
48191da177e4SLinus Torvalds 
48201da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4821773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
48221da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
48231da177e4SLinus Torvalds 		return count;
48241da177e4SLinus Torvalds 	}
48251da177e4SLinus Torvalds 	return -EINVAL;
48261da177e4SLinus Torvalds }
482782069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
48281da177e4SLinus Torvalds 
482982069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
48301da177e4SLinus Torvalds {
4831773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
48321da177e4SLinus Torvalds }
483382069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
48341da177e4SLinus Torvalds 
483582069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
48361da177e4SLinus Torvalds {
4837773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
48381da177e4SLinus Torvalds }
483982069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
48401da177e4SLinus Torvalds 
484182069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
48421da177e4SLinus Torvalds {
4843773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
48441da177e4SLinus Torvalds }
484582069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
484682069379SAkinobu Mita 			       size_t count)
48471da177e4SLinus Torvalds {
48481da177e4SLinus Torvalds 	int nth;
48491da177e4SLinus Torvalds 
48501da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4851773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4852c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4853c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4854c4837394SDouglas Gilbert 			sdebug_statistics = true;
4855c4837394SDouglas Gilbert 		}
4856c4837394SDouglas Gilbert 		tweak_cmnd_count();
48571da177e4SLinus Torvalds 		return count;
48581da177e4SLinus Torvalds 	}
48591da177e4SLinus Torvalds 	return -EINVAL;
48601da177e4SLinus Torvalds }
486182069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
48621da177e4SLinus Torvalds 
486382069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
48641da177e4SLinus Torvalds {
4865773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
48661da177e4SLinus Torvalds }
486782069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
486882069379SAkinobu Mita 			      size_t count)
48691da177e4SLinus Torvalds {
48701da177e4SLinus Torvalds 	int n;
487119c8ead7SEwan D. Milne 	bool changed;
48721da177e4SLinus Torvalds 
48731da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
48748d039e22SDouglas Gilbert 		if (n > 256) {
48758d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
48768d039e22SDouglas Gilbert 			return -EINVAL;
48778d039e22SDouglas Gilbert 		}
4878773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4879773642d9SDouglas Gilbert 		sdebug_max_luns = n;
48801da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4881773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
488219c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
488319c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
488419c8ead7SEwan D. Milne 
488519c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
488619c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
488719c8ead7SEwan D. Milne 					    host_list) {
488819c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
488919c8ead7SEwan D. Milne 						    dev_list) {
489019c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
489119c8ead7SEwan D. Milne 						dp->uas_bm);
489219c8ead7SEwan D. Milne 				}
489319c8ead7SEwan D. Milne 			}
489419c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
489519c8ead7SEwan D. Milne 		}
48961da177e4SLinus Torvalds 		return count;
48971da177e4SLinus Torvalds 	}
48981da177e4SLinus Torvalds 	return -EINVAL;
48991da177e4SLinus Torvalds }
490082069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
49011da177e4SLinus Torvalds 
490282069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
490378d4e5a0SDouglas Gilbert {
4904773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
490578d4e5a0SDouglas Gilbert }
4906cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4907cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
490882069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
490982069379SAkinobu Mita 			       size_t count)
491078d4e5a0SDouglas Gilbert {
4911c4837394SDouglas Gilbert 	int j, n, k, a;
4912c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
491378d4e5a0SDouglas Gilbert 
491478d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4915c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4916c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4917c4837394SDouglas Gilbert 		k = 0;
4918c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4919c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4920c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4921c4837394SDouglas Gilbert 			if (a > k)
4922c4837394SDouglas Gilbert 				k = a;
4923c4837394SDouglas Gilbert 		}
4924773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4925c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4926cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4927cbf67842SDouglas Gilbert 		else if (k >= n)
4928cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4929cbf67842SDouglas Gilbert 		else
4930cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4931c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
493278d4e5a0SDouglas Gilbert 		return count;
493378d4e5a0SDouglas Gilbert 	}
493478d4e5a0SDouglas Gilbert 	return -EINVAL;
493578d4e5a0SDouglas Gilbert }
493682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
493778d4e5a0SDouglas Gilbert 
493882069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
493978d4e5a0SDouglas Gilbert {
4940773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
494178d4e5a0SDouglas Gilbert }
494282069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
494378d4e5a0SDouglas Gilbert 
494482069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
49451da177e4SLinus Torvalds {
4946773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
49471da177e4SLinus Torvalds }
494882069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
49491da177e4SLinus Torvalds 
495082069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4951c65b1445SDouglas Gilbert {
4952773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4953c65b1445SDouglas Gilbert }
495482069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
495582069379SAkinobu Mita 				size_t count)
4956c65b1445SDouglas Gilbert {
4957c65b1445SDouglas Gilbert 	int n;
49580d01c5dfSDouglas Gilbert 	bool changed;
4959c65b1445SDouglas Gilbert 
4960c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4961773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4962773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
496328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
49640d01c5dfSDouglas Gilbert 		if (changed) {
49650d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
49660d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
496728898873SFUJITA Tomonori 
49684bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
49690d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
49700d01c5dfSDouglas Gilbert 					    host_list) {
49710d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
49720d01c5dfSDouglas Gilbert 						    dev_list) {
49730d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
49740d01c5dfSDouglas Gilbert 						dp->uas_bm);
49750d01c5dfSDouglas Gilbert 				}
49760d01c5dfSDouglas Gilbert 			}
49774bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
49780d01c5dfSDouglas Gilbert 		}
4979c65b1445SDouglas Gilbert 		return count;
4980c65b1445SDouglas Gilbert 	}
4981c65b1445SDouglas Gilbert 	return -EINVAL;
4982c65b1445SDouglas Gilbert }
498382069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4984c65b1445SDouglas Gilbert 
498582069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
49861da177e4SLinus Torvalds {
4987773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
49881da177e4SLinus Torvalds }
49891da177e4SLinus Torvalds 
4990fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4991fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4992fd32119bSDouglas Gilbert 
499382069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
499482069379SAkinobu Mita 			      size_t count)
49951da177e4SLinus Torvalds {
49961da177e4SLinus Torvalds 	int delta_hosts;
49971da177e4SLinus Torvalds 
4998f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
49991da177e4SLinus Torvalds 		return -EINVAL;
50001da177e4SLinus Torvalds 	if (delta_hosts > 0) {
50011da177e4SLinus Torvalds 		do {
50021da177e4SLinus Torvalds 			sdebug_add_adapter();
50031da177e4SLinus Torvalds 		} while (--delta_hosts);
50041da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
50051da177e4SLinus Torvalds 		do {
50061da177e4SLinus Torvalds 			sdebug_remove_adapter();
50071da177e4SLinus Torvalds 		} while (++delta_hosts);
50081da177e4SLinus Torvalds 	}
50091da177e4SLinus Torvalds 	return count;
50101da177e4SLinus Torvalds }
501182069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
50121da177e4SLinus Torvalds 
501382069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
501423183910SDouglas Gilbert {
5015773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
501623183910SDouglas Gilbert }
501782069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
501882069379SAkinobu Mita 				    size_t count)
501923183910SDouglas Gilbert {
502023183910SDouglas Gilbert 	int n;
502123183910SDouglas Gilbert 
502223183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5023773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
502423183910SDouglas Gilbert 		return count;
502523183910SDouglas Gilbert 	}
502623183910SDouglas Gilbert 	return -EINVAL;
502723183910SDouglas Gilbert }
502882069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
502923183910SDouglas Gilbert 
5030c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5031c4837394SDouglas Gilbert {
5032c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5033c4837394SDouglas Gilbert }
5034c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5035c4837394SDouglas Gilbert 				size_t count)
5036c4837394SDouglas Gilbert {
5037c4837394SDouglas Gilbert 	int n;
5038c4837394SDouglas Gilbert 
5039c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5040c4837394SDouglas Gilbert 		if (n > 0)
5041c4837394SDouglas Gilbert 			sdebug_statistics = true;
5042c4837394SDouglas Gilbert 		else {
5043c4837394SDouglas Gilbert 			clear_queue_stats();
5044c4837394SDouglas Gilbert 			sdebug_statistics = false;
5045c4837394SDouglas Gilbert 		}
5046c4837394SDouglas Gilbert 		return count;
5047c4837394SDouglas Gilbert 	}
5048c4837394SDouglas Gilbert 	return -EINVAL;
5049c4837394SDouglas Gilbert }
5050c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
5051c4837394SDouglas Gilbert 
505282069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
5053597136abSMartin K. Petersen {
5054773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
5055597136abSMartin K. Petersen }
505682069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
5057597136abSMartin K. Petersen 
5058c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5059c4837394SDouglas Gilbert {
5060c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5061c4837394SDouglas Gilbert }
5062c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
5063c4837394SDouglas Gilbert 
506482069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
5065c6a44287SMartin K. Petersen {
5066773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
5067c6a44287SMartin K. Petersen }
506882069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
5069c6a44287SMartin K. Petersen 
507082069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
5071c6a44287SMartin K. Petersen {
5072773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
5073c6a44287SMartin K. Petersen }
507482069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
5075c6a44287SMartin K. Petersen 
507682069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
5077c6a44287SMartin K. Petersen {
5078773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
5079c6a44287SMartin K. Petersen }
508082069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
5081c6a44287SMartin K. Petersen 
508282069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
5083c6a44287SMartin K. Petersen {
5084773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
5085c6a44287SMartin K. Petersen }
508682069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
5087c6a44287SMartin K. Petersen 
508882069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
508944d92694SMartin K. Petersen {
509044d92694SMartin K. Petersen 	ssize_t count;
509144d92694SMartin K. Petersen 
50925b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
509344d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
509444d92694SMartin K. Petersen 				 sdebug_store_sectors);
509544d92694SMartin K. Petersen 
5096c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5097c7badc90STejun Heo 			  (int)map_size, map_storep);
509844d92694SMartin K. Petersen 	buf[count++] = '\n';
5099c7badc90STejun Heo 	buf[count] = '\0';
510044d92694SMartin K. Petersen 
510144d92694SMartin K. Petersen 	return count;
510244d92694SMartin K. Petersen }
510382069379SAkinobu Mita static DRIVER_ATTR_RO(map);
510444d92694SMartin K. Petersen 
510582069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
5106d986788bSMartin Pitt {
5107773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
5108d986788bSMartin Pitt }
510982069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
511082069379SAkinobu Mita 			       size_t count)
5111d986788bSMartin Pitt {
5112d986788bSMartin Pitt 	int n;
5113d986788bSMartin Pitt 
5114d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5115773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
5116d986788bSMartin Pitt 		return count;
5117d986788bSMartin Pitt 	}
5118d986788bSMartin Pitt 	return -EINVAL;
5119d986788bSMartin Pitt }
512082069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
5121d986788bSMartin Pitt 
5122cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5123cbf67842SDouglas Gilbert {
5124773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
5125cbf67842SDouglas Gilbert }
5126185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
5127cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5128cbf67842SDouglas Gilbert 			       size_t count)
5129cbf67842SDouglas Gilbert {
5130185dd232SDouglas Gilbert 	int n;
5131cbf67842SDouglas Gilbert 
5132cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5133185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
5134185dd232SDouglas Gilbert 		return count;
5135cbf67842SDouglas Gilbert 	}
5136cbf67842SDouglas Gilbert 	return -EINVAL;
5137cbf67842SDouglas Gilbert }
5138cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
5139cbf67842SDouglas Gilbert 
5140c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
5141c2248fc9SDouglas Gilbert {
5142773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
5143c2248fc9SDouglas Gilbert }
5144c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5145c2248fc9SDouglas Gilbert 			    size_t count)
5146c2248fc9SDouglas Gilbert {
5147c2248fc9SDouglas Gilbert 	int n;
5148c2248fc9SDouglas Gilbert 
5149c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5150773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
5151c2248fc9SDouglas Gilbert 		return count;
5152c2248fc9SDouglas Gilbert 	}
5153c2248fc9SDouglas Gilbert 	return -EINVAL;
5154c2248fc9SDouglas Gilbert }
5155c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
5156c2248fc9SDouglas Gilbert 
515709ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
515809ba24c1SDouglas Gilbert {
515909ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
516009ba24c1SDouglas Gilbert }
516109ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
516209ba24c1SDouglas Gilbert 
51639b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
51649b760fd8SDouglas Gilbert {
51659b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
51669b760fd8SDouglas Gilbert }
51679b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
51689b760fd8SDouglas Gilbert 			     size_t count)
51699b760fd8SDouglas Gilbert {
51709b760fd8SDouglas Gilbert 	int ret, n;
51719b760fd8SDouglas Gilbert 
51729b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
51739b760fd8SDouglas Gilbert 	if (ret)
51749b760fd8SDouglas Gilbert 		return ret;
51759b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
51769b760fd8SDouglas Gilbert 	all_config_cdb_len();
51779b760fd8SDouglas Gilbert 	return count;
51789b760fd8SDouglas Gilbert }
51799b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
51809b760fd8SDouglas Gilbert 
5181cbf67842SDouglas Gilbert 
518282069379SAkinobu Mita /* Note: The following array creates attribute files in the
518323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
518423183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
518523183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
518623183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
518723183910SDouglas Gilbert  */
51886ecaff7fSRandy Dunlap 
518982069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
519082069379SAkinobu Mita 	&driver_attr_delay.attr,
519182069379SAkinobu Mita 	&driver_attr_opts.attr,
519282069379SAkinobu Mita 	&driver_attr_ptype.attr,
519382069379SAkinobu Mita 	&driver_attr_dsense.attr,
519482069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
519582069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
519682069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
519782069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
519882069379SAkinobu Mita 	&driver_attr_num_parts.attr,
519982069379SAkinobu Mita 	&driver_attr_every_nth.attr,
520082069379SAkinobu Mita 	&driver_attr_max_luns.attr,
520182069379SAkinobu Mita 	&driver_attr_max_queue.attr,
520282069379SAkinobu Mita 	&driver_attr_no_uld.attr,
520382069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
520482069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
520582069379SAkinobu Mita 	&driver_attr_add_host.attr,
520682069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
520782069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5208c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5209c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
521082069379SAkinobu Mita 	&driver_attr_dix.attr,
521182069379SAkinobu Mita 	&driver_attr_dif.attr,
521282069379SAkinobu Mita 	&driver_attr_guard.attr,
521382069379SAkinobu Mita 	&driver_attr_ato.attr,
521482069379SAkinobu Mita 	&driver_attr_map.attr,
521582069379SAkinobu Mita 	&driver_attr_removable.attr,
5216cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5217cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5218c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
521909ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
52209b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
522182069379SAkinobu Mita 	NULL,
522282069379SAkinobu Mita };
522382069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
52241da177e4SLinus Torvalds 
522511ddcecaSAkinobu Mita static struct device *pseudo_primary;
52268dea0d02SFUJITA Tomonori 
52271da177e4SLinus Torvalds static int __init scsi_debug_init(void)
52281da177e4SLinus Torvalds {
52295f2578e5SFUJITA Tomonori 	unsigned long sz;
52301da177e4SLinus Torvalds 	int host_to_add;
52311da177e4SLinus Torvalds 	int k;
52326ecaff7fSRandy Dunlap 	int ret;
52331da177e4SLinus Torvalds 
5234cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5235cbf67842SDouglas Gilbert 
5236773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5237c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5238773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5239773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5240c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5241cbf67842SDouglas Gilbert 
5242773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5243597136abSMartin K. Petersen 	case  512:
5244597136abSMartin K. Petersen 	case 1024:
5245597136abSMartin K. Petersen 	case 2048:
5246597136abSMartin K. Petersen 	case 4096:
5247597136abSMartin K. Petersen 		break;
5248597136abSMartin K. Petersen 	default:
5249773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5250597136abSMartin K. Petersen 		return -EINVAL;
5251597136abSMartin K. Petersen 	}
5252597136abSMartin K. Petersen 
5253773642d9SDouglas Gilbert 	switch (sdebug_dif) {
52548475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5255f46eb0e9SDouglas Gilbert 		break;
52568475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
52578475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
52588475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5259f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5260c6a44287SMartin K. Petersen 		break;
5261c6a44287SMartin K. Petersen 
5262c6a44287SMartin K. Petersen 	default:
5263c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5264c6a44287SMartin K. Petersen 		return -EINVAL;
5265c6a44287SMartin K. Petersen 	}
5266c6a44287SMartin K. Petersen 
5267aa5334c4SMaurizio Lombardi 	if (sdebug_num_tgts < 0) {
5268aa5334c4SMaurizio Lombardi 		pr_err("num_tgts must be >= 0\n");
5269aa5334c4SMaurizio Lombardi 		return -EINVAL;
5270aa5334c4SMaurizio Lombardi 	}
5271aa5334c4SMaurizio Lombardi 
5272773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5273c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5274c6a44287SMartin K. Petersen 		return -EINVAL;
5275c6a44287SMartin K. Petersen 	}
5276c6a44287SMartin K. Petersen 
5277773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5278c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5279c6a44287SMartin K. Petersen 		return -EINVAL;
5280c6a44287SMartin K. Petersen 	}
5281c6a44287SMartin K. Petersen 
5282773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5283773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5284ea61fca5SMartin K. Petersen 		return -EINVAL;
5285ea61fca5SMartin K. Petersen 	}
52868d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
52878d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
52888d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
52898d039e22SDouglas Gilbert 	}
5290ea61fca5SMartin K. Petersen 
5291773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5292773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5293ea61fca5SMartin K. Petersen 		return -EINVAL;
5294ea61fca5SMartin K. Petersen 	}
5295ea61fca5SMartin K. Petersen 
5296c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5297c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5298c4837394SDouglas Gilbert 		return -EINVAL;
5299c4837394SDouglas Gilbert 	}
5300c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5301c4837394SDouglas Gilbert 			       GFP_KERNEL);
5302c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5303c4837394SDouglas Gilbert 		return -ENOMEM;
5304c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5305c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5306c4837394SDouglas Gilbert 
5307773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5308773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5309773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5310773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
531128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
53121da177e4SLinus Torvalds 
53131da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
53141da177e4SLinus Torvalds 	sdebug_heads = 8;
53151da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5316773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
53171da177e4SLinus Torvalds 		sdebug_heads = 64;
5318773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5319fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
53201da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53211da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53221da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
53231da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
53241da177e4SLinus Torvalds 		sdebug_heads = 255;
53251da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
53261da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53271da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53281da177e4SLinus Torvalds 	}
53291da177e4SLinus Torvalds 
5330b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
53317382f9d8SDouglas Gilbert 		fake_storep = vzalloc(sz);
53321da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5333c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5334c4837394SDouglas Gilbert 			ret = -ENOMEM;
5335c4837394SDouglas Gilbert 			goto free_q_arr;
53361da177e4SLinus Torvalds 		}
5337773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5338f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5339cbf67842SDouglas Gilbert 	}
53401da177e4SLinus Torvalds 
5341773642d9SDouglas Gilbert 	if (sdebug_dix) {
5342c6a44287SMartin K. Petersen 		int dif_size;
5343c6a44287SMartin K. Petersen 
53446ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5345c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5346c6a44287SMartin K. Petersen 
5347c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5348c6a44287SMartin K. Petersen 
5349c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5350c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5351c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5352c6a44287SMartin K. Petersen 			goto free_vm;
5353c6a44287SMartin K. Petersen 		}
5354c6a44287SMartin K. Petersen 
5355c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5356c6a44287SMartin K. Petersen 	}
5357c6a44287SMartin K. Petersen 
53585b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
53595b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5360773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5361773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
53626014759cSMartin K. Petersen 
5363773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5364773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
53656014759cSMartin K. Petersen 
5366773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5367773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
53686014759cSMartin K. Petersen 
5369773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5370773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5371773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5372c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5373c4837394SDouglas Gilbert 			ret = -EINVAL;
5374c4837394SDouglas Gilbert 			goto free_vm;
537544d92694SMartin K. Petersen 		}
537644d92694SMartin K. Petersen 
5377b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
537842bc47b3SKees Cook 		map_storep = vmalloc(array_size(sizeof(long),
537942bc47b3SKees Cook 						BITS_TO_LONGS(map_size)));
538044d92694SMartin K. Petersen 
5381c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
538244d92694SMartin K. Petersen 
538344d92694SMartin K. Petersen 		if (map_storep == NULL) {
5384c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
538544d92694SMartin K. Petersen 			ret = -ENOMEM;
538644d92694SMartin K. Petersen 			goto free_vm;
538744d92694SMartin K. Petersen 		}
538844d92694SMartin K. Petersen 
5389b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
539044d92694SMartin K. Petersen 
539144d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5392773642d9SDouglas Gilbert 		if (sdebug_num_parts)
539344d92694SMartin K. Petersen 			map_region(0, 2);
539444d92694SMartin K. Petersen 	}
539544d92694SMartin K. Petersen 
53969b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
53979b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5398c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
53999b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
54006ecaff7fSRandy Dunlap 		goto free_vm;
54016ecaff7fSRandy Dunlap 	}
54026ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
54036ecaff7fSRandy Dunlap 	if (ret < 0) {
5404c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
54056ecaff7fSRandy Dunlap 		goto dev_unreg;
54066ecaff7fSRandy Dunlap 	}
54076ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
54086ecaff7fSRandy Dunlap 	if (ret < 0) {
5409c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
54106ecaff7fSRandy Dunlap 		goto bus_unreg;
54116ecaff7fSRandy Dunlap 	}
54121da177e4SLinus Torvalds 
5413773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5414773642d9SDouglas Gilbert 	sdebug_add_host = 0;
54151da177e4SLinus Torvalds 
54161da177e4SLinus Torvalds 	for (k = 0; k < host_to_add; k++) {
54171da177e4SLinus Torvalds 		if (sdebug_add_adapter()) {
5418c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
54191da177e4SLinus Torvalds 			break;
54201da177e4SLinus Torvalds 		}
54211da177e4SLinus Torvalds 	}
54221da177e4SLinus Torvalds 
5423773642d9SDouglas Gilbert 	if (sdebug_verbose)
5424773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5425c1287970STomas Winkler 
54261da177e4SLinus Torvalds 	return 0;
54276ecaff7fSRandy Dunlap 
54286ecaff7fSRandy Dunlap bus_unreg:
54296ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
54306ecaff7fSRandy Dunlap dev_unreg:
54319b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54326ecaff7fSRandy Dunlap free_vm:
543344d92694SMartin K. Petersen 	vfree(map_storep);
5434c6a44287SMartin K. Petersen 	vfree(dif_storep);
54356ecaff7fSRandy Dunlap 	vfree(fake_storep);
5436c4837394SDouglas Gilbert free_q_arr:
5437c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
54386ecaff7fSRandy Dunlap 	return ret;
54391da177e4SLinus Torvalds }
54401da177e4SLinus Torvalds 
54411da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
54421da177e4SLinus Torvalds {
5443773642d9SDouglas Gilbert 	int k = sdebug_add_host;
54441da177e4SLinus Torvalds 
54451da177e4SLinus Torvalds 	stop_all_queued();
54461da177e4SLinus Torvalds 	for (; k; k--)
54471da177e4SLinus Torvalds 		sdebug_remove_adapter();
544852ab9768SLuis Henriques 	free_all_queued();
54491da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
54501da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
54519b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54521da177e4SLinus Torvalds 
54534d2b496fSEwan D. Milne 	vfree(map_storep);
5454c6a44287SMartin K. Petersen 	vfree(dif_storep);
54551da177e4SLinus Torvalds 	vfree(fake_storep);
5456c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
54571da177e4SLinus Torvalds }
54581da177e4SLinus Torvalds 
54591da177e4SLinus Torvalds device_initcall(scsi_debug_init);
54601da177e4SLinus Torvalds module_exit(scsi_debug_exit);
54611da177e4SLinus Torvalds 
54621da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
54631da177e4SLinus Torvalds {
54641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54651da177e4SLinus Torvalds 
54661da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54671da177e4SLinus Torvalds 	kfree(sdbg_host);
54681da177e4SLinus Torvalds }
54691da177e4SLinus Torvalds 
54701da177e4SLinus Torvalds static int sdebug_add_adapter(void)
54711da177e4SLinus Torvalds {
54721da177e4SLinus Torvalds 	int k, devs_per_host;
54731da177e4SLinus Torvalds 	int error = 0;
54741da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54758b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
54761da177e4SLinus Torvalds 
547724669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
54789a051019SDouglas Gilbert 	if (sdbg_host == NULL) {
5479c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
54801da177e4SLinus Torvalds 		return -ENOMEM;
54811da177e4SLinus Torvalds 	}
54821da177e4SLinus Torvalds 
54831da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
54841da177e4SLinus Torvalds 
5485773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
54861da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
54875cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
54885cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5489c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
54901da177e4SLinus Torvalds 			error = -ENOMEM;
54911da177e4SLinus Torvalds 			goto clean;
54921da177e4SLinus Torvalds 		}
54931da177e4SLinus Torvalds 	}
54941da177e4SLinus Torvalds 
54951da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
54961da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
54971da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
54981da177e4SLinus Torvalds 
54991da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
55009b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
55011da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
5502773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
55031da177e4SLinus Torvalds 
55041da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
55051da177e4SLinus Torvalds 
55061da177e4SLinus Torvalds 	if (error)
55071da177e4SLinus Torvalds 		goto clean;
55081da177e4SLinus Torvalds 
5509773642d9SDouglas Gilbert 	++sdebug_add_host;
55101da177e4SLinus Torvalds 	return error;
55111da177e4SLinus Torvalds 
55121da177e4SLinus Torvalds clean:
55138b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55148b40228fSFUJITA Tomonori 				 dev_list) {
55151da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
55161da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
55171da177e4SLinus Torvalds 	}
55181da177e4SLinus Torvalds 
55191da177e4SLinus Torvalds 	kfree(sdbg_host);
55201da177e4SLinus Torvalds 	return error;
55211da177e4SLinus Torvalds }
55221da177e4SLinus Torvalds 
55231da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
55241da177e4SLinus Torvalds {
55251da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
55261da177e4SLinus Torvalds 
55271da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55281da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
55291da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
55301da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
55311da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
55321da177e4SLinus Torvalds 	}
55331da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55341da177e4SLinus Torvalds 
55351da177e4SLinus Torvalds 	if (!sdbg_host)
55361da177e4SLinus Torvalds 		return;
55371da177e4SLinus Torvalds 
55381da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5539773642d9SDouglas Gilbert 	--sdebug_add_host;
55401da177e4SLinus Torvalds }
55411da177e4SLinus Torvalds 
5542fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5543cbf67842SDouglas Gilbert {
5544cbf67842SDouglas Gilbert 	int num_in_q = 0;
5545cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5546cbf67842SDouglas Gilbert 
5547c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5548cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5549cbf67842SDouglas Gilbert 	if (NULL == devip) {
5550c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5551cbf67842SDouglas Gilbert 		return	-ENODEV;
5552cbf67842SDouglas Gilbert 	}
5553cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5554c40ecc12SChristoph Hellwig 
5555cbf67842SDouglas Gilbert 	if (qdepth < 1)
5556cbf67842SDouglas Gilbert 		qdepth = 1;
5557c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5558c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5559c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5560db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5561cbf67842SDouglas Gilbert 
5562773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5563c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5564c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5565cbf67842SDouglas Gilbert 	}
5566c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5567cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5568cbf67842SDouglas Gilbert }
5569cbf67842SDouglas Gilbert 
5570c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5571817fd66bSDouglas Gilbert {
5572c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5573773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5574773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5575773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5576c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5577773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5578817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5579c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5580817fd66bSDouglas Gilbert 	}
5581c4837394SDouglas Gilbert 	return false;
5582817fd66bSDouglas Gilbert }
5583817fd66bSDouglas Gilbert 
55847ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
55857ee6d1b4SBart Van Assche {
55867ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
55877ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
55887ee6d1b4SBart Van Assche }
55897ee6d1b4SBart Van Assche 
5590fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5591fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5592c2248fc9SDouglas Gilbert {
5593c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5594c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5595c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5596c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5597c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5598c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5599c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5600f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
5601c2248fc9SDouglas Gilbert 	int k, na;
5602c2248fc9SDouglas Gilbert 	int errsts = 0;
5603c2248fc9SDouglas Gilbert 	u32 flags;
5604c2248fc9SDouglas Gilbert 	u16 sa;
5605c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5606c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5607c2248fc9SDouglas Gilbert 
5608c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5609c4837394SDouglas Gilbert 	if (sdebug_statistics)
5610c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5611f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5612f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5613c2248fc9SDouglas Gilbert 		char b[120];
5614c2248fc9SDouglas Gilbert 		int n, len, sb;
5615c2248fc9SDouglas Gilbert 
5616c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5617c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5618c2248fc9SDouglas Gilbert 		if (len > 32)
5619c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5620c2248fc9SDouglas Gilbert 		else {
5621c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5622c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5623c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5624c2248fc9SDouglas Gilbert 		}
5625458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5626458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
5627c2248fc9SDouglas Gilbert 	}
56287ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
56297ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
563034d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5631f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5632f46eb0e9SDouglas Gilbert 		goto err_out;
5633c2248fc9SDouglas Gilbert 
5634c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5635c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5636c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5637f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5638f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5639c2248fc9SDouglas Gilbert 		if (NULL == devip)
5640f46eb0e9SDouglas Gilbert 			goto err_out;
5641c2248fc9SDouglas Gilbert 	}
5642c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5643c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5644c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5645c2248fc9SDouglas Gilbert 		r_oip = oip;
5646c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5647c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5648c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5649c2248fc9SDouglas Gilbert 			else
5650c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5651c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5652c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5653c2248fc9SDouglas Gilbert 					break;
5654c2248fc9SDouglas Gilbert 			}
5655c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5656c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5657c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5658c2248fc9SDouglas Gilbert 					break;
5659c2248fc9SDouglas Gilbert 			}
5660c2248fc9SDouglas Gilbert 		}
5661c2248fc9SDouglas Gilbert 		if (k > na) {
5662c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5663c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5664c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5665c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5666c2248fc9SDouglas Gilbert 			else
5667c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5668c2248fc9SDouglas Gilbert 			goto check_cond;
5669c2248fc9SDouglas Gilbert 		}
5670c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5671c2248fc9SDouglas Gilbert 	flags = oip->flags;
5672f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5673c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5674c2248fc9SDouglas Gilbert 		goto check_cond;
5675c2248fc9SDouglas Gilbert 	}
5676f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5677773642d9SDouglas Gilbert 		if (sdebug_verbose)
5678773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5679773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5680c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5681c2248fc9SDouglas Gilbert 		goto check_cond;
5682c2248fc9SDouglas Gilbert 	}
5683f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5684c2248fc9SDouglas Gilbert 		u8 rem;
5685c2248fc9SDouglas Gilbert 		int j;
5686c2248fc9SDouglas Gilbert 
5687c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5688c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5689c2248fc9SDouglas Gilbert 			if (rem) {
5690c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5691c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5692c2248fc9SDouglas Gilbert 						break;
5693c2248fc9SDouglas Gilbert 				}
5694c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5695c2248fc9SDouglas Gilbert 				goto check_cond;
5696c2248fc9SDouglas Gilbert 			}
5697c2248fc9SDouglas Gilbert 		}
5698c2248fc9SDouglas Gilbert 	}
5699f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5700b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5701b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5702f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5703c2248fc9SDouglas Gilbert 		if (errsts)
5704c2248fc9SDouglas Gilbert 			goto check_cond;
5705c2248fc9SDouglas Gilbert 	}
5706c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5707c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5708773642d9SDouglas Gilbert 		if (sdebug_verbose)
5709c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5710c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5711c2248fc9SDouglas Gilbert 				    "required");
5712c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5713c2248fc9SDouglas Gilbert 		goto fini;
5714c2248fc9SDouglas Gilbert 	}
5715773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5716c2248fc9SDouglas Gilbert 		goto fini;
5717f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5718c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5719c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5720c2248fc9SDouglas Gilbert 	}
5721f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5722f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
5723f66b8517SMartin Wilck 	else
5724f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
5725c2248fc9SDouglas Gilbert 
5726c2248fc9SDouglas Gilbert fini:
572710bde980SDouglas Gilbert 	if (F_DELAY_OVERR & flags)
5728f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
572975aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
573075aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
573180c49563SDouglas Gilbert 		/*
573275aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
573375aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
573475aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
573575aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
573680c49563SDouglas Gilbert 		 */
573780c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
57384f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
573980c49563SDouglas Gilbert 
57404f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
5741f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
574280c49563SDouglas Gilbert 	} else
5743f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
574410bde980SDouglas Gilbert 				     sdebug_ndelay);
5745c2248fc9SDouglas Gilbert check_cond:
5746f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
5747f46eb0e9SDouglas Gilbert err_out:
5748f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
5749c2248fc9SDouglas Gilbert }
5750c2248fc9SDouglas Gilbert 
57519e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5752c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5753c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
57549e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
57559e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
57569e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
57579e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
57589e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
57599e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
57609e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5761185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5762cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
57639e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
57649e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5765cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5766cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
57679e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5768c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
57699e603ca0SFUJITA Tomonori 	.this_id =		7,
577065e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5771cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
57726bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
577350c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
57749e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5775c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
57769e603ca0SFUJITA Tomonori };
57779e603ca0SFUJITA Tomonori 
57781da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
57791da177e4SLinus Torvalds {
57801da177e4SLinus Torvalds 	int error = 0;
57811da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
57821da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5783f46eb0e9SDouglas Gilbert 	int hprot;
57841da177e4SLinus Torvalds 
57851da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
57861da177e4SLinus Torvalds 
5787773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
57882a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
57894af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
57904af14d11SChristoph Hellwig 
57911da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
57921da177e4SLinus Torvalds 	if (NULL == hpnt) {
5793c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
57941da177e4SLinus Torvalds 		error = -ENODEV;
57951da177e4SLinus Torvalds 		return error;
57961da177e4SLinus Torvalds 	}
5797c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
57989b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5799c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5800c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5801c4837394SDouglas Gilbert 	}
5802c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5803c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5804c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
58051da177e4SLinus Torvalds 
58061da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
58071da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5808773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5809773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
58101da177e4SLinus Torvalds 	else
5811773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5812773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5813f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
58141da177e4SLinus Torvalds 
5815f46eb0e9SDouglas Gilbert 	hprot = 0;
5816c6a44287SMartin K. Petersen 
5817773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5818c6a44287SMartin K. Petersen 
58198475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5820f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5821773642d9SDouglas Gilbert 		if (sdebug_dix)
5822f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5823c6a44287SMartin K. Petersen 		break;
5824c6a44287SMartin K. Petersen 
58258475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5826f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5827773642d9SDouglas Gilbert 		if (sdebug_dix)
5828f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5829c6a44287SMartin K. Petersen 		break;
5830c6a44287SMartin K. Petersen 
58318475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5832f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5833773642d9SDouglas Gilbert 		if (sdebug_dix)
5834f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5835c6a44287SMartin K. Petersen 		break;
5836c6a44287SMartin K. Petersen 
5837c6a44287SMartin K. Petersen 	default:
5838773642d9SDouglas Gilbert 		if (sdebug_dix)
5839f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5840c6a44287SMartin K. Petersen 		break;
5841c6a44287SMartin K. Petersen 	}
5842c6a44287SMartin K. Petersen 
5843f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5844c6a44287SMartin K. Petersen 
5845f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5846c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5847f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5848f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5849f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5850f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5851f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5852f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5853f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5854c6a44287SMartin K. Petersen 
5855773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5856c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5857c6a44287SMartin K. Petersen 	else
5858c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5859c6a44287SMartin K. Petersen 
5860773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5861773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5862c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5863c4837394SDouglas Gilbert 		sdebug_statistics = true;
58641da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
58651da177e4SLinus Torvalds 	if (error) {
5866c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
58671da177e4SLinus Torvalds 		error = -ENODEV;
58681da177e4SLinus Torvalds 		scsi_host_put(hpnt);
58691da177e4SLinus Torvalds 	} else
58701da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
58711da177e4SLinus Torvalds 
58721da177e4SLinus Torvalds 	return error;
58731da177e4SLinus Torvalds }
58741da177e4SLinus Torvalds 
58751da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
58761da177e4SLinus Torvalds {
58771da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
58788b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
58791da177e4SLinus Torvalds 
58801da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
58811da177e4SLinus Torvalds 
58821da177e4SLinus Torvalds 	if (!sdbg_host) {
5883c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
58841da177e4SLinus Torvalds 		return -ENODEV;
58851da177e4SLinus Torvalds 	}
58861da177e4SLinus Torvalds 
58871da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
58881da177e4SLinus Torvalds 
58898b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
58908b40228fSFUJITA Tomonori 				 dev_list) {
58911da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
58921da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
58931da177e4SLinus Torvalds 	}
58941da177e4SLinus Torvalds 
58951da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
58961da177e4SLinus Torvalds 	return 0;
58971da177e4SLinus Torvalds }
58981da177e4SLinus Torvalds 
58998dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
59008dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
59011da177e4SLinus Torvalds {
59028dea0d02SFUJITA Tomonori 	return 1;
59038dea0d02SFUJITA Tomonori }
59041da177e4SLinus Torvalds 
59058dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
59068dea0d02SFUJITA Tomonori 	.name = "pseudo",
59078dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
59088dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
59098dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
591082069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
59118dea0d02SFUJITA Tomonori };
5912