xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision ae3d56d8)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
980c49563SDouglas Gilbert  * Copyright (C) 2001 - 2018 Douglas Gilbert
101da177e4SLinus Torvalds  *
11773642d9SDouglas Gilbert  * This program is free software; you can redistribute it and/or modify
12773642d9SDouglas Gilbert  * it under the terms of the GNU General Public License as published by
13773642d9SDouglas Gilbert  * the Free Software Foundation; either version 2, or (at your option)
14773642d9SDouglas Gilbert  * any later version.
151da177e4SLinus Torvalds  *
1678d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds 
20c1287970STomas Winkler 
21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22c1287970STomas Winkler 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
27b333a819SDouglas Gilbert #include <linux/jiffies.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/genhd.h>
321da177e4SLinus Torvalds #include <linux/fs.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/proc_fs.h>
351da177e4SLinus Torvalds #include <linux/vmalloc.h>
361da177e4SLinus Torvalds #include <linux/moduleparam.h>
37852e034dSJens Axboe #include <linux/scatterlist.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
40cbf67842SDouglas Gilbert #include <linux/spinlock.h>
41cbf67842SDouglas Gilbert #include <linux/interrupt.h>
42cbf67842SDouglas Gilbert #include <linux/atomic.h>
43cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
4409ba24c1SDouglas Gilbert #include <linux/uuid.h>
456ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
46c6a44287SMartin K. Petersen 
47c6a44287SMartin K. Petersen #include <net/checksum.h>
489ff26eefSFUJITA Tomonori 
4944d92694SMartin K. Petersen #include <asm/unaligned.h>
5044d92694SMartin K. Petersen 
519ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
539ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
541da177e4SLinus Torvalds #include <scsi/scsi_host.h>
551da177e4SLinus Torvalds #include <scsi/scsicam.h>
56a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
57cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
58395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
591da177e4SLinus Torvalds 
60c6a44287SMartin K. Petersen #include "sd.h"
611da177e4SLinus Torvalds #include "scsi_logging.h"
621da177e4SLinus Torvalds 
63773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6480c49563SDouglas Gilbert #define SDEBUG_VERSION "0188"	/* format to fit INQUIRY revision field */
6580c49563SDouglas Gilbert static const char *sdebug_version_date = "20180128";
66cbf67842SDouglas Gilbert 
67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
681da177e4SLinus Torvalds 
696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
971da177e4SLinus Torvalds 
986f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
996f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1006f3cbf55SDouglas Gilbert 
1011da177e4SLinus Torvalds /* Default values for driver parameters */
1021da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1031da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1041da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1051da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1061da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1071da177e4SLinus Torvalds  */
1085b94e232SMartin K. Petersen #define DEF_ATO 1
1099b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
110c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1111da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1125b94e232SMartin K. Petersen #define DEF_DIF 0
1135b94e232SMartin K. Petersen #define DEF_DIX 0
1145b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1151da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1165b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1175b94e232SMartin K. Petersen #define DEF_GUARD 0
118cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1195b94e232SMartin K. Petersen #define DEF_LBPU 0
1205b94e232SMartin K. Petersen #define DEF_LBPWS 0
1215b94e232SMartin K. Petersen #define DEF_LBPWS10 0
122be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1235b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
124cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1255b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1261da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1271da177e4SLinus Torvalds #define DEF_OPTS   0
12832c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1295b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13086e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
131b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
132d986788bSMartin Pitt #define DEF_REMOVABLE false
133760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1345b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1355b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1365b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1376014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1386014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1395b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1405b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1415b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
142c2248fc9SDouglas Gilbert #define DEF_STRICT 0
143c4837394SDouglas Gilbert #define DEF_STATISTICS false
144c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14509ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
146c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1471da177e4SLinus Torvalds 
148b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
149b01f6f83SDouglas Gilbert 
150773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
151773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
152773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
153773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
154773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
155773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
156773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
157773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
158773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
159773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
160773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
161773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
162773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
163773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
164773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
165773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1667ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
1677382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT		0x10000
168773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
169773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
170773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
171773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
172773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1737ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1747382f9d8SDouglas Gilbert 				  SDEBUG_OPT_HOST_BUSY | \
1757382f9d8SDouglas Gilbert 				  SDEBUG_OPT_CMD_ABORT)
1761da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
177fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1781da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
179773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1806f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
181773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1827382f9d8SDouglas Gilbert  *   - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
1837382f9d8SDouglas Gilbert  *     CMD_ABORT
1841da177e4SLinus Torvalds  *
1857382f9d8SDouglas Gilbert  * When "every_nth" < 0 then after "- every_nth" commands the selected
1867382f9d8SDouglas Gilbert  * error will be injected. The error will be injected on every subsequent
1877382f9d8SDouglas Gilbert  * command until some other action occurs; for example, the user writing
1887382f9d8SDouglas Gilbert  * a new value (other than -1 or 1) to every_nth:
1897382f9d8SDouglas Gilbert  *      echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
1901da177e4SLinus Torvalds  */
1911da177e4SLinus Torvalds 
192cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
193cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
194cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
195cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
196cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
197cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
198cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1990d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
20019c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
201acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
202acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
203acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
204cbf67842SDouglas Gilbert 
205773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2061da177e4SLinus Torvalds  * sector on read commands: */
2071da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20832f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2111da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2121da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2131da177e4SLinus Torvalds 
214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
216c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
220c4837394SDouglas Gilbert  */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
223cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
224cbf67842SDouglas Gilbert 
225fd32119bSDouglas Gilbert #define F_D_IN			1
226fd32119bSDouglas Gilbert #define F_D_OUT			2
227fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
228fd32119bSDouglas Gilbert #define F_D_UNKN		8
229fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
230fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
231fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
232fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
233fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
234fd32119bSDouglas Gilbert #define F_INV_OP		0x200
235fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
236fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
2374f2c8bf6SDouglas Gilbert #define F_SSU_DELAY		0x1000
2384f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY		0x2000
239fd32119bSDouglas Gilbert 
240fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24146f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
242fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2434f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
244fd32119bSDouglas Gilbert 
245fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
246fd32119bSDouglas Gilbert 
247b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
248fd32119bSDouglas Gilbert 
249fd32119bSDouglas Gilbert 
250fd32119bSDouglas Gilbert struct sdebug_dev_info {
251fd32119bSDouglas Gilbert 	struct list_head dev_list;
252fd32119bSDouglas Gilbert 	unsigned int channel;
253fd32119bSDouglas Gilbert 	unsigned int target;
254fd32119bSDouglas Gilbert 	u64 lun;
255bf476433SChristoph Hellwig 	uuid_t lu_name;
256fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
257fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
258fd32119bSDouglas Gilbert 	atomic_t num_in_q;
259c4837394SDouglas Gilbert 	atomic_t stopped;
260fd32119bSDouglas Gilbert 	bool used;
261fd32119bSDouglas Gilbert };
262fd32119bSDouglas Gilbert 
263fd32119bSDouglas Gilbert struct sdebug_host_info {
264fd32119bSDouglas Gilbert 	struct list_head host_list;
265fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
266fd32119bSDouglas Gilbert 	struct device dev;
267fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
268fd32119bSDouglas Gilbert };
269fd32119bSDouglas Gilbert 
270fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
271fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
272fd32119bSDouglas Gilbert 
27310bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
27410bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
27510bde980SDouglas Gilbert 
276fd32119bSDouglas Gilbert struct sdebug_defer {
277fd32119bSDouglas Gilbert 	struct hrtimer hrt;
278fd32119bSDouglas Gilbert 	struct execute_work ew;
279c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
280c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
281c4837394SDouglas Gilbert 	int issuing_cpu;
28210bde980SDouglas Gilbert 	bool init_hrt;
28310bde980SDouglas Gilbert 	bool init_wq;
2847382f9d8SDouglas Gilbert 	bool aborted;	/* true when blk_abort_request() already called */
28510bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
286fd32119bSDouglas Gilbert };
287fd32119bSDouglas Gilbert 
288fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
289c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
290c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
291c4837394SDouglas Gilbert 	 */
292fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
293fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
294c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
295c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
296c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
297c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
298c4837394SDouglas Gilbert 	unsigned int inj_short:1;
2997ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
3007382f9d8SDouglas Gilbert 	unsigned int inj_cmd_abort:1;
301fd32119bSDouglas Gilbert };
302fd32119bSDouglas Gilbert 
303c4837394SDouglas Gilbert struct sdebug_queue {
304c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
305c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
306c4837394SDouglas Gilbert 	spinlock_t qc_lock;
307c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
308fd32119bSDouglas Gilbert };
309fd32119bSDouglas Gilbert 
310c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
311c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
312c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
313c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
314c4837394SDouglas Gilbert 
315fd32119bSDouglas Gilbert struct opcode_info_t {
316b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
317b01f6f83SDouglas Gilbert 				/* for terminating element */
318fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
319fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
320fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
321fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
322fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3239a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3249a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
325fd32119bSDouglas Gilbert };
326fd32119bSDouglas Gilbert 
327fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
328c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
329c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
330c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
331c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
332c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
333c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
334c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
335c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
336c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
337c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
338c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
339c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
340c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
34146f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
34246f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
343c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
344c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
345c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
346481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
347c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
348c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
349c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
350c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
351c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
352c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
353c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
354c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
355c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
356c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
35780c49563SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10, 16 */
358c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
3599a051019SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last (previous + 1) */
360c2248fc9SDouglas Gilbert };
361c2248fc9SDouglas Gilbert 
362c4837394SDouglas Gilbert 
363c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
364c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
365c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
366c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
367c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
368c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
369c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
370c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
371c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
372c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
373c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
374c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
375c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
376c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
377c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
378c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
379c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
380c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
381c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
382c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
383fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
384c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
386c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
387c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
388c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
389c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
39080c49563SDouglas Gilbert 	0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
39146f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
392c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
393c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
394c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
39546f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
39646f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
397c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
398c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
399c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
400c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
401c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
403c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
404c2248fc9SDouglas Gilbert };
405c2248fc9SDouglas Gilbert 
40680c49563SDouglas Gilbert /*
40780c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
40880c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
40980c49563SDouglas Gilbert  * command completion, they can mask their return value with
41080c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
41180c49563SDouglas Gilbert  */
41280c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
41380c49563SDouglas Gilbert 
414c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
415c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
416c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
417c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
418c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
419c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
420c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
421c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
422c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
423481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
424c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
425c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
426c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
427c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
428c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
42938d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
43038d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
431c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
432c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
43338d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
434acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
43580c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
436c2248fc9SDouglas Gilbert 
43746f64e70SDouglas Gilbert /*
43846f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
43946f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
44046f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
44146f64e70SDouglas Gilbert  */
44246f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
443c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
444c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
445c2248fc9SDouglas Gilbert };
446c2248fc9SDouglas Gilbert 
44746f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
448c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
449c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
450c2248fc9SDouglas Gilbert };
451c2248fc9SDouglas Gilbert 
45246f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
45346f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
454b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
455c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
45646f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
457c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
45846f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
459b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
460c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
461c2248fc9SDouglas Gilbert };
462c2248fc9SDouglas Gilbert 
46346f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
46446f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
46546f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
46646f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
46746f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
46846f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
46946f64e70SDouglas Gilbert 		   0, 0, 0} },
47046f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
47146f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47246f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
473c2248fc9SDouglas Gilbert };
474c2248fc9SDouglas Gilbert 
47546f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
476c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
477c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47846f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
479c2248fc9SDouglas Gilbert };
480c2248fc9SDouglas Gilbert 
48146f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
48246f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
483b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
484c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
485481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
486481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
487481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
488c2248fc9SDouglas Gilbert };
489c2248fc9SDouglas Gilbert 
49046f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
49138d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
492c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
49346f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
49438d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
495c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
49646f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
497c2248fc9SDouglas Gilbert };
498c2248fc9SDouglas Gilbert 
49946f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
50046f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
501c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50246f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
503c2248fc9SDouglas Gilbert };
504c2248fc9SDouglas Gilbert 
50546f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
506c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
507c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
508c2248fc9SDouglas Gilbert };
509c2248fc9SDouglas Gilbert 
51046f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
511c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
512c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
513c2248fc9SDouglas Gilbert };
514c2248fc9SDouglas Gilbert 
51580c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5164f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
51780c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51880c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
51980c49563SDouglas Gilbert };
52080c49563SDouglas Gilbert 
521c2248fc9SDouglas Gilbert 
522c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
523c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
524c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
525c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
526c2248fc9SDouglas Gilbert /* 0 */
52746f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
528c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52946f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
530c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
531c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
532c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
53346f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
534c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
535c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
536c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
537c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53846f64e70SDouglas Gilbert /* 5 */
53946f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
54046f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
54146f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54246f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
54346f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
54446f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54546f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
546c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
547c2248fc9SDouglas Gilbert 	     0, 0, 0} },
54846f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
549c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
550c2248fc9SDouglas Gilbert 	     0, 0} },
55146f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
55246f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
55346f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
554c2248fc9SDouglas Gilbert /* 10 */
55546f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
55646f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
55746f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55880c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
5594f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
560c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
56146f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
56246f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
56346f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56446f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
565481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
566481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
567481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
56846f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
56946f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
57046f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
57146f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
57246f64e70SDouglas Gilbert /* 15 */
573c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
574c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
57546f64e70SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
576f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
577f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
57846f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
57946f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
58046f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
58146f64e70SDouglas Gilbert 	     0xff, 0xff} },
58246f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
58346f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
584c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
585c2248fc9SDouglas Gilbert 	     0} },
58646f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
58746f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
588c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
589c2248fc9SDouglas Gilbert 	     0} },
590c2248fc9SDouglas Gilbert /* 20 */
591f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
592f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
593c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
594c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
595c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
596c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
597c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
598c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
59946f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
600b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
60146f64e70SDouglas Gilbert /* 25 */
602acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
603acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
604acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
60546f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
60646f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
60746f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
60846f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
6094f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
61080c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
611b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
61280c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
61346f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
614c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
615b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
616c2248fc9SDouglas Gilbert 
617c2248fc9SDouglas Gilbert /* 30 */
618c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
619c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
620c2248fc9SDouglas Gilbert };
621c2248fc9SDouglas Gilbert 
622773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
623773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
6249b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
625c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
626773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
627773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
628773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
629773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
630773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
631773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
632773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
633773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
634773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
635c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
636d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
637d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
638cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
639c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
640773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
641773642d9SDouglas Gilbert static int sdebug_no_uld;
642773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
643773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
644773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
645773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
646773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
64786e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
648b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
649773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
650773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
651773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
652773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
653773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
654773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
655773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
656773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
657773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
658773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
659773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
660773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
661773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
66209ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
663773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
664773642d9SDouglas Gilbert static bool sdebug_clustering;
665773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
666773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
667817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
668773642d9SDouglas Gilbert static bool sdebug_verbose;
669f46eb0e9SDouglas Gilbert static bool have_dif_prot;
6704f2c8bf6SDouglas Gilbert static bool write_since_sync;
671c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
6721da177e4SLinus Torvalds 
673c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6741da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6771da177e4SLinus Torvalds    may still need them */
6781da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6791da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6801da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6831da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6866ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
68744d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6881da177e4SLinus Torvalds 
68944d92694SMartin K. Petersen static unsigned long map_size;
690cbf67842SDouglas Gilbert static int num_aborts;
691cbf67842SDouglas Gilbert static int num_dev_resets;
692cbf67842SDouglas Gilbert static int num_target_resets;
693cbf67842SDouglas Gilbert static int num_bus_resets;
694cbf67842SDouglas Gilbert static int num_host_resets;
695c6a44287SMartin K. Petersen static int dix_writes;
696c6a44287SMartin K. Petersen static int dix_reads;
697c6a44287SMartin K. Petersen static int dif_errors;
6981da177e4SLinus Torvalds 
699c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
700c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
701fd32119bSDouglas Gilbert 
7021da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
7031da177e4SLinus Torvalds 
704cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
705cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
7101da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
7111da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
7121da177e4SLinus Torvalds };
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds static const int check_condition_result =
7151da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
7161da177e4SLinus Torvalds 
717c6a44287SMartin K. Petersen static const int illegal_condition_result =
718c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
719c6a44287SMartin K. Petersen 
720cbf67842SDouglas Gilbert static const int device_qfull_result =
721cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
722cbf67842SDouglas Gilbert 
723fd32119bSDouglas Gilbert 
724760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
725760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
726760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
727760f3b03SDouglas Gilbert  */
728760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
729fd32119bSDouglas Gilbert {
730fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
731fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
732fd32119bSDouglas Gilbert }
733c65b1445SDouglas Gilbert 
73414faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
73514faa944SAkinobu Mita {
73614faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
73714faa944SAkinobu Mita 
738773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
73914faa944SAkinobu Mita }
74014faa944SAkinobu Mita 
7416ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
74214faa944SAkinobu Mita {
74349413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
74414faa944SAkinobu Mita 
74514faa944SAkinobu Mita 	return dif_storep + sector;
74614faa944SAkinobu Mita }
74714faa944SAkinobu Mita 
7488dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7498dea0d02SFUJITA Tomonori {
7508dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7518dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7528dea0d02SFUJITA Tomonori 
7538dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7548dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7558dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7568dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
757773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
758773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7598dea0d02SFUJITA Tomonori 		else
760773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
761773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
762f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7638dea0d02SFUJITA Tomonori 	}
7648dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7658dea0d02SFUJITA Tomonori }
7668dea0d02SFUJITA Tomonori 
76722017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
76822017ed2SDouglas Gilbert 
76922017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
770fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
771fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
77222017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
77322017ed2SDouglas Gilbert {
77422017ed2SDouglas Gilbert 	unsigned char *sbuff;
77522017ed2SDouglas Gilbert 	u8 sks[4];
77622017ed2SDouglas Gilbert 	int sl, asc;
77722017ed2SDouglas Gilbert 
77822017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
77922017ed2SDouglas Gilbert 	if (!sbuff) {
78022017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
78122017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
78222017ed2SDouglas Gilbert 		return;
78322017ed2SDouglas Gilbert 	}
78422017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
78522017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
786773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
78722017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
78822017ed2SDouglas Gilbert 	sks[0] = 0x80;
78922017ed2SDouglas Gilbert 	if (c_d)
79022017ed2SDouglas Gilbert 		sks[0] |= 0x40;
79122017ed2SDouglas Gilbert 	if (in_bit >= 0) {
79222017ed2SDouglas Gilbert 		sks[0] |= 0x8;
79322017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
79422017ed2SDouglas Gilbert 	}
79522017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
796773642d9SDouglas Gilbert 	if (sdebug_dsense) {
79722017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
79822017ed2SDouglas Gilbert 		sbuff[7] = sl;
79922017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
80022017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
80122017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
80222017ed2SDouglas Gilbert 	} else
80322017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
804773642d9SDouglas Gilbert 	if (sdebug_verbose)
80522017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
80622017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
80722017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
80822017ed2SDouglas Gilbert }
80922017ed2SDouglas Gilbert 
810cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
8118dea0d02SFUJITA Tomonori {
8128dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
8138dea0d02SFUJITA Tomonori 
814cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
815cbf67842SDouglas Gilbert 	if (!sbuff) {
816cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
817cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
818cbf67842SDouglas Gilbert 		return;
819cbf67842SDouglas Gilbert 	}
820cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
8218dea0d02SFUJITA Tomonori 
822773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
8238dea0d02SFUJITA Tomonori 
824773642d9SDouglas Gilbert 	if (sdebug_verbose)
825cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
826cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
827cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
8288dea0d02SFUJITA Tomonori }
8291da177e4SLinus Torvalds 
830fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
83122017ed2SDouglas Gilbert {
83222017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
83322017ed2SDouglas Gilbert }
83422017ed2SDouglas Gilbert 
8351da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
8361da177e4SLinus Torvalds {
837773642d9SDouglas Gilbert 	if (sdebug_verbose) {
838cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
839cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
840cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
841cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
842cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
843cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
844cbf67842SDouglas Gilbert 				    __func__);
845cbf67842SDouglas Gilbert 		else
846cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
847cbf67842SDouglas Gilbert 				    __func__, cmd);
8481da177e4SLinus Torvalds 	}
8491da177e4SLinus Torvalds 	return -EINVAL;
8501da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
8539b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8549b760fd8SDouglas Gilbert {
8559b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8569b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8579b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8589b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8599b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8609b760fd8SDouglas Gilbert 		break;
8619b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8629b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8639b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8649b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8659b760fd8SDouglas Gilbert 		break;
8669b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8679b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8689b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8699b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8709b760fd8SDouglas Gilbert 		break;
8719b760fd8SDouglas Gilbert 	case 16:
8729b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8739b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8749b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8759b760fd8SDouglas Gilbert 		break;
8769b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8779b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8789b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8799b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8809b760fd8SDouglas Gilbert 		break;
8819b760fd8SDouglas Gilbert 	default:
8829b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8839b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8849b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8859b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8869b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8879b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8889b760fd8SDouglas Gilbert 		break;
8899b760fd8SDouglas Gilbert 	}
8909b760fd8SDouglas Gilbert }
8919b760fd8SDouglas Gilbert 
8929b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8939b760fd8SDouglas Gilbert {
8949b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8959b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
8969b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
8979b760fd8SDouglas Gilbert 
8989b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
8999b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9009b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
9019b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
9029b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
9039b760fd8SDouglas Gilbert 		}
9049b760fd8SDouglas Gilbert 	}
9059b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
9069b760fd8SDouglas Gilbert }
9079b760fd8SDouglas Gilbert 
90819c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
90919c8ead7SEwan D. Milne {
91019c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
91119c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
91219c8ead7SEwan D. Milne 
91319c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
91419c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
91519c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
91619c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
91719c8ead7SEwan D. Milne 			    (devip->target == dp->target))
91819c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
91919c8ead7SEwan D. Milne 		}
92019c8ead7SEwan D. Milne 	}
92119c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
92219c8ead7SEwan D. Milne }
92319c8ead7SEwan D. Milne 
924f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
9251da177e4SLinus Torvalds {
926cbf67842SDouglas Gilbert 	int k;
927cbf67842SDouglas Gilbert 
928cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
929cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
930cbf67842SDouglas Gilbert 		const char *cp = NULL;
931cbf67842SDouglas Gilbert 
932cbf67842SDouglas Gilbert 		switch (k) {
933cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
934f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
935f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
936773642d9SDouglas Gilbert 			if (sdebug_verbose)
937cbf67842SDouglas Gilbert 				cp = "power on reset";
938cbf67842SDouglas Gilbert 			break;
939cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
940f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
941f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
942773642d9SDouglas Gilbert 			if (sdebug_verbose)
943cbf67842SDouglas Gilbert 				cp = "bus reset";
944cbf67842SDouglas Gilbert 			break;
945cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
946f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
947f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
948773642d9SDouglas Gilbert 			if (sdebug_verbose)
949cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
950cbf67842SDouglas Gilbert 			break;
9510d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
952f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
953f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
954773642d9SDouglas Gilbert 			if (sdebug_verbose)
9550d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
956f49accf1SEwan D. Milne 			break;
957acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
958f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
959b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
960b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
961773642d9SDouglas Gilbert 			if (sdebug_verbose)
962acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
963acafd0b9SEwan D. Milne 			break;
964acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
965f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
966acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
967acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
968773642d9SDouglas Gilbert 			if (sdebug_verbose)
969acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
970acafd0b9SEwan D. Milne 			break;
97119c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
97219c8ead7SEwan D. Milne 			/*
97319c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
97419c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
97519c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
97619c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
977773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
97819c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
97919c8ead7SEwan D. Milne 			 */
980773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
98119c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
982f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
98319c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
98419c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
985773642d9SDouglas Gilbert 			if (sdebug_verbose)
98619c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
98719c8ead7SEwan D. Milne 			break;
988cbf67842SDouglas Gilbert 		default:
989773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
990773642d9SDouglas Gilbert 			if (sdebug_verbose)
991cbf67842SDouglas Gilbert 				cp = "unknown";
992cbf67842SDouglas Gilbert 			break;
993cbf67842SDouglas Gilbert 		}
994cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
995773642d9SDouglas Gilbert 		if (sdebug_verbose)
996f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
997cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
998cbf67842SDouglas Gilbert 				   my_name, cp);
9991da177e4SLinus Torvalds 		return check_condition_result;
10001da177e4SLinus Torvalds 	}
10011da177e4SLinus Torvalds 	return 0;
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds 
1004fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
10051da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
10061da177e4SLinus Torvalds 				int arr_len)
10071da177e4SLinus Torvalds {
100821a61829SFUJITA Tomonori 	int act_len;
1009ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
10101da177e4SLinus Torvalds 
1011072d0bb3SFUJITA Tomonori 	if (!sdb->length)
10121da177e4SLinus Torvalds 		return 0;
1013ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1014773642d9SDouglas Gilbert 		return DID_ERROR << 16;
101521a61829SFUJITA Tomonori 
101621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
101721a61829SFUJITA Tomonori 				      arr, arr_len);
101821a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
101921a61829SFUJITA Tomonori 
10201da177e4SLinus Torvalds 	return 0;
10211da177e4SLinus Torvalds }
10221da177e4SLinus Torvalds 
1023fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1024fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1025fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1026fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1027fb0cc8d1SDouglas Gilbert  */
1028fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1029fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1030fb0cc8d1SDouglas Gilbert {
1031fb0cc8d1SDouglas Gilbert 	int act_len, n;
1032ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scp->sdb;
1033fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1034fb0cc8d1SDouglas Gilbert 
1035fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1036fb0cc8d1SDouglas Gilbert 		return 0;
1037ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_FROM_DEVICE)
1038fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1039fb0cc8d1SDouglas Gilbert 
1040fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1041fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1042fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1043fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1044fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1045fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
1046fb0cc8d1SDouglas Gilbert 	return 0;
1047fb0cc8d1SDouglas Gilbert }
1048fb0cc8d1SDouglas Gilbert 
1049fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1050fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1051fb0cc8d1SDouglas Gilbert  */
10521da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
105321a61829SFUJITA Tomonori 			       int arr_len)
10541da177e4SLinus Torvalds {
105521a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10561da177e4SLinus Torvalds 		return 0;
1057ae3d56d8SChristoph Hellwig 	if (scp->sc_data_direction != DMA_TO_DEVICE)
10581da177e4SLinus Torvalds 		return -1;
105921a61829SFUJITA Tomonori 
106021a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10611da177e4SLinus Torvalds }
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 
1064e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1065e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10669b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10671b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10681b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10691b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10701b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10711da177e4SLinus Torvalds 
1072cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1073760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10745a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
107509ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1076bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10771da177e4SLinus Torvalds {
1078c65b1445SDouglas Gilbert 	int num, port_a;
1079c65b1445SDouglas Gilbert 	char b[32];
10801da177e4SLinus Torvalds 
1081c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10821da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10831da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10841da177e4SLinus Torvalds 	arr[1] = 0x1;
10851da177e4SLinus Torvalds 	arr[2] = 0x0;
1086e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1087e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10881da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10891da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10901da177e4SLinus Torvalds 	arr[3] = num;
10911da177e4SLinus Torvalds 	num += 4;
1092c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
109309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
109409ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
109509ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
109609ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
109709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
109809ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
109909ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
110009ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110109ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
110209ba24c1SDouglas Gilbert 			num += 16;
110309ba24c1SDouglas Gilbert 		} else {
11041b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1105c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1106c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1107c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1108c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
11091b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1110773642d9SDouglas Gilbert 			num += 8;
111109ba24c1SDouglas Gilbert 		}
1112c65b1445SDouglas Gilbert 		/* Target relative port number */
1113c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1114c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1115c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1116c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1117c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1118c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1119c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1120c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1121c65b1445SDouglas Gilbert 	}
11221b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1123c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1124c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1125c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1126c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11271b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1128773642d9SDouglas Gilbert 	num += 8;
11291b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
11305a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11315a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11325a09e398SHannes Reinecke 	arr[num++] = 0x0;
11335a09e398SHannes Reinecke 	arr[num++] = 0x4;
11345a09e398SHannes Reinecke 	arr[num++] = 0;
11355a09e398SHannes Reinecke 	arr[num++] = 0;
1136773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1137773642d9SDouglas Gilbert 	num += 2;
11381b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1139c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1140c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1141c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1142c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11431b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1144773642d9SDouglas Gilbert 	num += 8;
1145c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1146c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1147c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1148c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1149c65b1445SDouglas Gilbert 	arr[num++] = 24;
11501b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1151c65b1445SDouglas Gilbert 	num += 12;
1152c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1153c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1154c65b1445SDouglas Gilbert 	num += 8;
1155c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1156c65b1445SDouglas Gilbert 	num += 4;
1157c65b1445SDouglas Gilbert 	return num;
1158c65b1445SDouglas Gilbert }
1159c65b1445SDouglas Gilbert 
1160c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1161c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1162c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1163c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1164c65b1445SDouglas Gilbert };
1165c65b1445SDouglas Gilbert 
1166cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1167760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1168c65b1445SDouglas Gilbert {
1169c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1170c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1171c65b1445SDouglas Gilbert }
1172c65b1445SDouglas Gilbert 
1173cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1174760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1175c65b1445SDouglas Gilbert {
1176c65b1445SDouglas Gilbert 	int num = 0;
1177c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1178c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1179c65b1445SDouglas Gilbert 	int plen, olen;
1180c65b1445SDouglas Gilbert 
1181c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1182c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1183c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1184c65b1445SDouglas Gilbert 	olen = strlen(na1);
1185c65b1445SDouglas Gilbert 	plen = olen + 1;
1186c65b1445SDouglas Gilbert 	if (plen % 4)
1187c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1188c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1189c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1190c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1191c65b1445SDouglas Gilbert 	num += plen;
1192c65b1445SDouglas Gilbert 
1193c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1194c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1195c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1196c65b1445SDouglas Gilbert 	olen = strlen(na2);
1197c65b1445SDouglas Gilbert 	plen = olen + 1;
1198c65b1445SDouglas Gilbert 	if (plen % 4)
1199c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1200c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1201c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1202c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1203c65b1445SDouglas Gilbert 	num += plen;
1204c65b1445SDouglas Gilbert 
1205c65b1445SDouglas Gilbert 	return num;
1206c65b1445SDouglas Gilbert }
1207c65b1445SDouglas Gilbert 
1208c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1209760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1210c65b1445SDouglas Gilbert {
1211c65b1445SDouglas Gilbert 	int num = 0;
1212c65b1445SDouglas Gilbert 	int port_a, port_b;
1213c65b1445SDouglas Gilbert 
1214c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1215c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1216c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1217c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1218c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1219c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1220c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1221c65b1445SDouglas Gilbert 	num += 6;
1222c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1223c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1224c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1225c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1226c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1227c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1228c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12291b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1230773642d9SDouglas Gilbert 	num += 8;
1231c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1232c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1233c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1234c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1235c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1236c65b1445SDouglas Gilbert 	num += 6;
1237c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1238c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1239c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1240c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1241c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1242c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1243c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12441b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1245773642d9SDouglas Gilbert 	num += 8;
1246c65b1445SDouglas Gilbert 
1247c65b1445SDouglas Gilbert 	return num;
1248c65b1445SDouglas Gilbert }
1249c65b1445SDouglas Gilbert 
1250c65b1445SDouglas Gilbert 
1251c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1252c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1253c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1254c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1255c65b1445SDouglas Gilbert '1','2','3','4',
1256c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1257c65b1445SDouglas Gilbert 0xec,0,0,0,
1258c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1259c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1260c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1261c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1262c65b1445SDouglas Gilbert 0x53,0x41,
1263c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1264c65b1445SDouglas Gilbert 0x20,0x20,
1265c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1266c65b1445SDouglas Gilbert 0x10,0x80,
1267c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1268c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1269c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1270c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1271c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1272c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1273c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1277c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1278c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1279c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1280c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1292c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1293c65b1445SDouglas Gilbert };
1294c65b1445SDouglas Gilbert 
1295cbf67842SDouglas Gilbert /* ATA Information VPD page */
1296760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1297c65b1445SDouglas Gilbert {
1298c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1299c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1300c65b1445SDouglas Gilbert }
1301c65b1445SDouglas Gilbert 
1302c65b1445SDouglas Gilbert 
1303c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
13041e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
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,
13071e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1308c65b1445SDouglas Gilbert };
1309c65b1445SDouglas Gilbert 
1310cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1311760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1312c65b1445SDouglas Gilbert {
1313ea61fca5SMartin K. Petersen 	unsigned int gran;
1314ea61fca5SMartin K. Petersen 
1315c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1316e308b3d1SMartin K. Petersen 
1317e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
131886e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
131986e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
132086e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
132186e6828aSLukas Herbolt 	else
1322773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1323773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1324e308b3d1SMartin K. Petersen 
1325e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1326773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1327773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
132844d92694SMartin K. Petersen 
1329e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1330773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1331e308b3d1SMartin K. Petersen 
1332773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1333e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1334773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1335e308b3d1SMartin K. Petersen 
1336e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1337773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
133844d92694SMartin K. Petersen 	}
133944d92694SMartin K. Petersen 
1340e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1341773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1342773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
134344d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
134444d92694SMartin K. Petersen 	}
134544d92694SMartin K. Petersen 
1346e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1347773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13486014759cSMartin K. Petersen 
13495b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1350773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13515b94e232SMartin K. Petersen 
13525b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
135344d92694SMartin K. Petersen 
1354c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13551da177e4SLinus Torvalds }
13561da177e4SLinus Torvalds 
13571e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1358760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1359eac6e8e4SMatthew Wilcox {
1360eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1361eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13621e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13631e49f785SDouglas Gilbert 	arr[2] = 0;
13641e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1365eac6e8e4SMatthew Wilcox 
1366eac6e8e4SMatthew Wilcox 	return 0x3c;
1367eac6e8e4SMatthew Wilcox }
13681da177e4SLinus Torvalds 
1369760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1370760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13716014759cSMartin K. Petersen {
13723f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13736014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1374773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13756014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1376773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13776014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1378773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13795b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1380760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1381760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1382760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1383760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1384760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13853f0bc3b3SMartin K. Petersen 	return 0x4;
13866014759cSMartin K. Petersen }
13876014759cSMartin K. Petersen 
13881da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1389c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13901da177e4SLinus Torvalds 
1391c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13921da177e4SLinus Torvalds {
13931da177e4SLinus Torvalds 	unsigned char pq_pdt;
13945a09e398SHannes Reinecke 	unsigned char *arr;
139501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
13965a09e398SHannes Reinecke 	int alloc_len, n, ret;
1397760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
13981da177e4SLinus Torvalds 
1399773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
14006f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
14016f3cbf55SDouglas Gilbert 	if (! arr)
14026f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1403760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1404b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1405c2248fc9SDouglas Gilbert 	if (have_wlun)
1406b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1407b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1408b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1409c65b1445SDouglas Gilbert 	else
1410773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
14111da177e4SLinus Torvalds 	arr[0] = pq_pdt;
14121da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
141322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
14145a09e398SHannes Reinecke 		kfree(arr);
14151da177e4SLinus Torvalds 		return check_condition_result;
14161da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
14175a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1418c65b1445SDouglas Gilbert 		char lu_id_str[6];
1419c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
14201da177e4SLinus Torvalds 
14215a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
14225a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1423b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
142423183910SDouglas Gilbert 			host_no = 0;
1425c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1426c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1427c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1428c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1429c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
14301da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1431c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1432c65b1445SDouglas Gilbert 			n = 4;
1433c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1434c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1435c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1436c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1437c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1438c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1439c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1440c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1441760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1442c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1443760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1444760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1445760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1446760f3b03SDouglas Gilbert 			}
1447c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14481da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1449c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14501da177e4SLinus Torvalds 			arr[3] = len;
1451c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14521da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1453c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1454760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14555a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
145609ba24c1SDouglas Gilbert 						lu_id_str, len,
145709ba24c1SDouglas Gilbert 						&devip->lu_name);
1458c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1459c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1460760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1461c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1462c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1463760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1464c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1465c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1466c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14678475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1468c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1469760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1470c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1471c6a44287SMartin K. Petersen 			else
1472c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1473c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1474c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1475c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1476c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1477c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1478c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1479c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1480c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1481c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1482c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1483760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1484760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1485c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1486760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1487773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1488760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1489c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1490760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1491760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1492eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1493760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1494760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14956014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1496760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
14971da177e4SLinus Torvalds 		} else {
149822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
14995a09e398SHannes Reinecke 			kfree(arr);
15001da177e4SLinus Torvalds 			return check_condition_result;
15011da177e4SLinus Torvalds 		}
1502773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
15035a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1504c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
15055a09e398SHannes Reinecke 		kfree(arr);
15065a09e398SHannes Reinecke 		return ret;
15071da177e4SLinus Torvalds 	}
15081da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1509773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1510773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
15111da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
15121da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1513f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1514b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
151570bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1516c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
15171da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1518c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1519e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1520e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1521e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
15229b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
15239b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
15241da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1525760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1526760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1527c65b1445SDouglas Gilbert 	n = 62;
1528760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1529760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1530760f3b03SDouglas Gilbert 		n += 2;
1531760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1532760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1533760f3b03SDouglas Gilbert 		n += 2;
15341da177e4SLinus Torvalds 	}
1535760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15365a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15371da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
15385a09e398SHannes Reinecke 	kfree(arr);
15395a09e398SHannes Reinecke 	return ret;
15401da177e4SLinus Torvalds }
15411da177e4SLinus Torvalds 
1542fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1543fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1544fd32119bSDouglas Gilbert 
15451da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
15461da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
15471da177e4SLinus Torvalds {
15481da177e4SLinus Torvalds 	unsigned char *sbuff;
154901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1550cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15512492fc09STomas Winkler 	bool dsense;
15521da177e4SLinus Torvalds 	int len = 18;
15531da177e4SLinus Torvalds 
1554c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1555c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1556cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1557c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1558c2248fc9SDouglas Gilbert 		if (dsense) {
1559c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1560c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1561c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1562c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1563c2248fc9SDouglas Gilbert 			len = 8;
1564c65b1445SDouglas Gilbert 		} else {
1565c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1566c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1567c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1568c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1569c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1570c65b1445SDouglas Gilbert 		}
1571c65b1445SDouglas Gilbert 	} else {
1572cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1573773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1574c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1575c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1576c2248fc9SDouglas Gilbert 			if (dsense) {
1577c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1578c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1579c2248fc9SDouglas Gilbert 				len = 8;
1580c2248fc9SDouglas Gilbert 			} else {
1581c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1582c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1583c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1584c2248fc9SDouglas Gilbert 			}
1585c2248fc9SDouglas Gilbert 		} else if (dsense) {
1586c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15871da177e4SLinus Torvalds 			arr[0] = 0x72;
15881da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15891da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15901da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15911da177e4SLinus Torvalds 			len = 8;
1592c2248fc9SDouglas Gilbert 		} else {
1593c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1594c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1595c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1596c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1597c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1598c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1599c65b1445SDouglas Gilbert 		}
1600c2248fc9SDouglas Gilbert 
1601c65b1445SDouglas Gilbert 	}
1602cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
16031da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
16041da177e4SLinus Torvalds }
16051da177e4SLinus Torvalds 
1606c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1607c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1608c65b1445SDouglas Gilbert {
160901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1610c4837394SDouglas Gilbert 	int power_cond, stop;
16114f2c8bf6SDouglas Gilbert 	bool changing;
1612c65b1445SDouglas Gilbert 
1613c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1614c65b1445SDouglas Gilbert 	if (power_cond) {
161522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1616c65b1445SDouglas Gilbert 		return check_condition_result;
1617c65b1445SDouglas Gilbert 	}
1618c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
16194f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1620c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
16214f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
16224f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
16234f2c8bf6SDouglas Gilbert 	else
16244f2c8bf6SDouglas Gilbert 		return 0;
1625c65b1445SDouglas Gilbert }
1626c65b1445SDouglas Gilbert 
162728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
162828898873SFUJITA Tomonori {
1629773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1630773642d9SDouglas Gilbert 
1631773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1632773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1633773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
163428898873SFUJITA Tomonori 	else
163528898873SFUJITA Tomonori 		return sdebug_store_sectors;
163628898873SFUJITA Tomonori }
163728898873SFUJITA Tomonori 
16381da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16391da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
16401da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
16411da177e4SLinus Torvalds {
16421da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1643c65b1445SDouglas Gilbert 	unsigned int capac;
16441da177e4SLinus Torvalds 
1645c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
164628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
16471da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1648c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1649c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1650773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1651773642d9SDouglas Gilbert 	} else
1652773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1653773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16541da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16551da177e4SLinus Torvalds }
16561da177e4SLinus Torvalds 
1657c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1658c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1659c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1660c65b1445SDouglas Gilbert {
166101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1662c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1663773642d9SDouglas Gilbert 	int alloc_len;
1664c65b1445SDouglas Gilbert 
1665773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1666c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
166728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1668c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1669773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1670773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1671773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1672773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
167344d92694SMartin K. Petersen 
1674be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16755b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1676760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1677760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1678760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1679760f3b03SDouglas Gilbert 		 */
1680760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1681760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1682be1dd78dSEric Sandeen 	}
168344d92694SMartin K. Petersen 
1684773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1685c6a44287SMartin K. Petersen 
1686760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1687773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1688c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1689c6a44287SMartin K. Petersen 	}
1690c6a44287SMartin K. Petersen 
1691c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1692c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1693c65b1445SDouglas Gilbert }
1694c65b1445SDouglas Gilbert 
16955a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
16965a09e398SHannes Reinecke 
16975a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
16985a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
16995a09e398SHannes Reinecke {
170001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
17015a09e398SHannes Reinecke 	unsigned char *arr;
17025a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
17035a09e398SHannes Reinecke 	int n, ret, alen, rlen;
17045a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
17055a09e398SHannes Reinecke 
1706773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
17076f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
17086f3cbf55SDouglas Gilbert 	if (! arr)
17096f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
17105a09e398SHannes Reinecke 	/*
17115a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
17125a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
17135a09e398SHannes Reinecke 	 * So we create two port groups with one port each
17145a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
17155a09e398SHannes Reinecke 	 */
17165a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
17175a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
17185a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
17195a09e398SHannes Reinecke 			(devip->channel & 0x7f);
17205a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
17215a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
17225a09e398SHannes Reinecke 
17235a09e398SHannes Reinecke 	/*
17245a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
17255a09e398SHannes Reinecke 	 */
17265a09e398SHannes Reinecke 	n = 4;
1727b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
17285a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
17295a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
17305a09e398SHannes Reinecke 	} else {
17315a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1732773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
17335a09e398SHannes Reinecke 	}
1734773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1735773642d9SDouglas Gilbert 	n += 2;
17365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17395a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17415a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1742773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1743773642d9SDouglas Gilbert 	n += 2;
17445a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
17455a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1746773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1747773642d9SDouglas Gilbert 	n += 2;
17485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17505a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17515a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17535a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1754773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1755773642d9SDouglas Gilbert 	n += 2;
17565a09e398SHannes Reinecke 
17575a09e398SHannes Reinecke 	rlen = n - 4;
1758773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17595a09e398SHannes Reinecke 
17605a09e398SHannes Reinecke 	/*
17615a09e398SHannes Reinecke 	 * Return the smallest value of either
17625a09e398SHannes Reinecke 	 * - The allocated length
17635a09e398SHannes Reinecke 	 * - The constructed command length
17645a09e398SHannes Reinecke 	 * - The maximum array size
17655a09e398SHannes Reinecke 	 */
17665a09e398SHannes Reinecke 	rlen = min(alen,n);
17675a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17685a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17695a09e398SHannes Reinecke 	kfree(arr);
17705a09e398SHannes Reinecke 	return ret;
17715a09e398SHannes Reinecke }
17725a09e398SHannes Reinecke 
1773fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1774fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
177538d5c833SDouglas Gilbert {
177638d5c833SDouglas Gilbert 	bool rctd;
177738d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
177838d5c833SDouglas Gilbert 	u16 req_sa, u;
177938d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
178038d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
178138d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
178238d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
178338d5c833SDouglas Gilbert 	u8 *arr;
178438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
178538d5c833SDouglas Gilbert 
178638d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
178738d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
178838d5c833SDouglas Gilbert 	req_opcode = cmd[3];
178938d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
179038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17916d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
179238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
179338d5c833SDouglas Gilbert 		return check_condition_result;
179438d5c833SDouglas Gilbert 	}
179538d5c833SDouglas Gilbert 	if (alloc_len > 8192)
179638d5c833SDouglas Gilbert 		a_len = 8192;
179738d5c833SDouglas Gilbert 	else
179838d5c833SDouglas Gilbert 		a_len = alloc_len;
179999531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
180038d5c833SDouglas Gilbert 	if (NULL == arr) {
180138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
180238d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
180338d5c833SDouglas Gilbert 		return check_condition_result;
180438d5c833SDouglas Gilbert 	}
180538d5c833SDouglas Gilbert 	switch (reporting_opts) {
180638d5c833SDouglas Gilbert 	case 0:	/* all commands */
180738d5c833SDouglas Gilbert 		/* count number of commands */
180838d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
180938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
181038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181138d5c833SDouglas Gilbert 				continue;
181238d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
181338d5c833SDouglas Gilbert 		}
181438d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
181538d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
181638d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
181738d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
181838d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181938d5c833SDouglas Gilbert 				continue;
182038d5c833SDouglas Gilbert 			na = oip->num_attached;
182138d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
182238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
182338d5c833SDouglas Gilbert 			if (rctd)
182438d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
182538d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
182638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
182738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
182838d5c833SDouglas Gilbert 			if (rctd)
182938d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
183038d5c833SDouglas Gilbert 			r_oip = oip;
183138d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
183238d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
183338d5c833SDouglas Gilbert 					continue;
183438d5c833SDouglas Gilbert 				offset += bump;
183538d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
183638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
183738d5c833SDouglas Gilbert 				if (rctd)
183838d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
183938d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
184038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
184138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
184238d5c833SDouglas Gilbert 						   arr + offset + 6);
184338d5c833SDouglas Gilbert 				if (rctd)
184438d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
184538d5c833SDouglas Gilbert 							   arr + offset + 8);
184638d5c833SDouglas Gilbert 			}
184738d5c833SDouglas Gilbert 			oip = r_oip;
184838d5c833SDouglas Gilbert 			offset += bump;
184938d5c833SDouglas Gilbert 		}
185038d5c833SDouglas Gilbert 		break;
185138d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
185238d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
185338d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
185438d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
185538d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
185638d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
185738d5c833SDouglas Gilbert 			supp = 1;
185838d5c833SDouglas Gilbert 			offset = 4;
185938d5c833SDouglas Gilbert 		} else {
186038d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
186138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
186238d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
186338d5c833SDouglas Gilbert 							     2, 2);
186438d5c833SDouglas Gilbert 					kfree(arr);
186538d5c833SDouglas Gilbert 					return check_condition_result;
186638d5c833SDouglas Gilbert 				}
186738d5c833SDouglas Gilbert 				req_sa = 0;
186838d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
186938d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
187038d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
187138d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
187238d5c833SDouglas Gilbert 				return check_condition_result;
187338d5c833SDouglas Gilbert 			}
187438d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
187538d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
187638d5c833SDouglas Gilbert 				supp = 3;
187738d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
187838d5c833SDouglas Gilbert 				na = oip->num_attached;
187938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
188038d5c833SDouglas Gilbert 				     ++k, ++oip) {
188138d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
188238d5c833SDouglas Gilbert 						break;
188338d5c833SDouglas Gilbert 				}
188438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
188538d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
188638d5c833SDouglas Gilbert 				na = oip->num_attached;
188738d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
188838d5c833SDouglas Gilbert 				     ++k, ++oip) {
188938d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
189038d5c833SDouglas Gilbert 						break;
189138d5c833SDouglas Gilbert 				}
189238d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
189338d5c833SDouglas Gilbert 			} else
189438d5c833SDouglas Gilbert 				supp = 3;
189538d5c833SDouglas Gilbert 			if (3 == supp) {
189638d5c833SDouglas Gilbert 				u = oip->len_mask[0];
189738d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
189838d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
189938d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
190038d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
190138d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
190238d5c833SDouglas Gilbert 				offset = 4 + u;
190338d5c833SDouglas Gilbert 			} else
190438d5c833SDouglas Gilbert 				offset = 4;
190538d5c833SDouglas Gilbert 		}
190638d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
190738d5c833SDouglas Gilbert 		if (rctd) {
190838d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
190938d5c833SDouglas Gilbert 			offset += 12;
191038d5c833SDouglas Gilbert 		}
191138d5c833SDouglas Gilbert 		break;
191238d5c833SDouglas Gilbert 	default:
191338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
191438d5c833SDouglas Gilbert 		kfree(arr);
191538d5c833SDouglas Gilbert 		return check_condition_result;
191638d5c833SDouglas Gilbert 	}
191738d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
191838d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
191938d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
192038d5c833SDouglas Gilbert 	kfree(arr);
192138d5c833SDouglas Gilbert 	return errsts;
192238d5c833SDouglas Gilbert }
192338d5c833SDouglas Gilbert 
1924fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1925fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
192638d5c833SDouglas Gilbert {
192738d5c833SDouglas Gilbert 	bool repd;
192838d5c833SDouglas Gilbert 	u32 alloc_len, len;
192938d5c833SDouglas Gilbert 	u8 arr[16];
193038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
193138d5c833SDouglas Gilbert 
193238d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
193338d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
193438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
193538d5c833SDouglas Gilbert 	if (alloc_len < 4) {
193638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
193738d5c833SDouglas Gilbert 		return check_condition_result;
193838d5c833SDouglas Gilbert 	}
193938d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
194038d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
194138d5c833SDouglas Gilbert 	if (repd) {
194238d5c833SDouglas Gilbert 		arr[3] = 0xc;
194338d5c833SDouglas Gilbert 		len = 16;
194438d5c833SDouglas Gilbert 	} else
194538d5c833SDouglas Gilbert 		len = 4;
194638d5c833SDouglas Gilbert 
194738d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
194838d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
194938d5c833SDouglas Gilbert }
195038d5c833SDouglas Gilbert 
19511da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
19521da177e4SLinus Torvalds 
19531da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
19541da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19551da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19561da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19591da177e4SLinus Torvalds 	if (1 == pcontrol)
19601da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19611da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19621da177e4SLinus Torvalds }
19631da177e4SLinus Torvalds 
19641da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
19651da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19661da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19671da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19681da177e4SLinus Torvalds 
19691da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19701da177e4SLinus Torvalds 	if (1 == pcontrol)
19711da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19721da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19731da177e4SLinus Torvalds }
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
19761da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19771da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19781da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19791da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19801da177e4SLinus Torvalds 
19811da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1982773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1983773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1984773642d9SDouglas Gilbert 	if (sdebug_removable)
19851da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19861da177e4SLinus Torvalds 	if (1 == pcontrol)
19871da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19881da177e4SLinus Torvalds 	return sizeof(format_pg);
19891da177e4SLinus Torvalds }
19901da177e4SLinus Torvalds 
1991fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1992fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1993fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1994fd32119bSDouglas Gilbert 
19951da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
19961da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1997cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1998cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1999cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
20001da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
20011da177e4SLinus Torvalds 
2002773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2003cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
20041da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
20051da177e4SLinus Torvalds 	if (1 == pcontrol)
2006cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2007cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2008cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
20091da177e4SLinus Torvalds 	return sizeof(caching_pg);
20101da177e4SLinus Torvalds }
20111da177e4SLinus Torvalds 
2012fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2013fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2014fd32119bSDouglas Gilbert 
20151da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
20161da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2017c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2018c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2019c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
20201da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
20211da177e4SLinus Torvalds 
2022773642d9SDouglas Gilbert 	if (sdebug_dsense)
20231da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2024c65b1445SDouglas Gilbert 	else
2025c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2026c6a44287SMartin K. Petersen 
2027773642d9SDouglas Gilbert 	if (sdebug_ato)
2028c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2029c6a44287SMartin K. Petersen 
20301da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
20311da177e4SLinus Torvalds 	if (1 == pcontrol)
2032c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2033c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2034c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
20351da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20361da177e4SLinus Torvalds }
20371da177e4SLinus Torvalds 
2038c65b1445SDouglas Gilbert 
20391da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
20401da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2041c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
20421da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2043c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2044c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2045c65b1445SDouglas Gilbert 
20461da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
20471da177e4SLinus Torvalds 	if (1 == pcontrol)
2048c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2049c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2050c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
20511da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
20521da177e4SLinus Torvalds }
20531da177e4SLinus Torvalds 
2054c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2055c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2056c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2057c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2058c65b1445SDouglas Gilbert 
2059c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2060c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2061c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2062c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2063c65b1445SDouglas Gilbert }
2064c65b1445SDouglas Gilbert 
2065c65b1445SDouglas Gilbert 
2066c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2067c65b1445SDouglas Gilbert 			      int target_dev_id)
2068c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2069c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2070c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2071773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2072773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2073c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2074c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2075c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2076c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2077773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2078773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2079c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2080c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2081c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2082c65b1445SDouglas Gilbert 		};
2083c65b1445SDouglas Gilbert 	int port_a, port_b;
2084c65b1445SDouglas Gilbert 
20851b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20861b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20871b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20881b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2089c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2090c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2091c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2092773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2093773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2094c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2095c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2096c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2097c65b1445SDouglas Gilbert }
2098c65b1445SDouglas Gilbert 
2099c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2100c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2101c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2102c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2103c65b1445SDouglas Gilbert 		};
2104c65b1445SDouglas Gilbert 
2105c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2106c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2107c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2108c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2109c65b1445SDouglas Gilbert }
2110c65b1445SDouglas Gilbert 
21111da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
21121da177e4SLinus Torvalds 
2113fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2114fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
21151da177e4SLinus Torvalds {
211623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
21171da177e4SLinus Torvalds 	unsigned char dev_spec;
2118760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2119c2248fc9SDouglas Gilbert 	int target = scp->device->id;
21201da177e4SLinus Torvalds 	unsigned char *ap;
21211da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
212201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2123760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
21241da177e4SLinus Torvalds 
2125760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
21261da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
21271da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
21281da177e4SLinus Torvalds 	subpcode = cmd[3];
21291da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2130760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2131760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2132760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
213323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
213423183910SDouglas Gilbert 	else
213523183910SDouglas Gilbert 		bd_len = 0;
2136773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21371da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21381da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2139cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
21401da177e4SLinus Torvalds 		return check_condition_result;
21411da177e4SLinus Torvalds 	}
2142c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2143c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2144b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2145760f3b03SDouglas Gilbert 	if (is_disk)
2146b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
214723183910SDouglas Gilbert 	else
214823183910SDouglas Gilbert 		dev_spec = 0x0;
21491da177e4SLinus Torvalds 	if (msense_6) {
21501da177e4SLinus Torvalds 		arr[2] = dev_spec;
215123183910SDouglas Gilbert 		arr[3] = bd_len;
21521da177e4SLinus Torvalds 		offset = 4;
21531da177e4SLinus Torvalds 	} else {
21541da177e4SLinus Torvalds 		arr[3] = dev_spec;
215523183910SDouglas Gilbert 		if (16 == bd_len)
215623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
215723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21581da177e4SLinus Torvalds 		offset = 8;
21591da177e4SLinus Torvalds 	}
21601da177e4SLinus Torvalds 	ap = arr + offset;
216128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
216228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
216328898873SFUJITA Tomonori 
216423183910SDouglas Gilbert 	if (8 == bd_len) {
2165773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2166773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2167773642d9SDouglas Gilbert 		else
2168773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2169773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
217023183910SDouglas Gilbert 		offset += bd_len;
217123183910SDouglas Gilbert 		ap = arr + offset;
217223183910SDouglas Gilbert 	} else if (16 == bd_len) {
2173773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2174773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
217523183910SDouglas Gilbert 		offset += bd_len;
217623183910SDouglas Gilbert 		ap = arr + offset;
217723183910SDouglas Gilbert 	}
21781da177e4SLinus Torvalds 
2179c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2180c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
218122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21821da177e4SLinus Torvalds 		return check_condition_result;
21831da177e4SLinus Torvalds 	}
2184760f3b03SDouglas Gilbert 	bad_pcode = false;
2185760f3b03SDouglas Gilbert 
21861da177e4SLinus Torvalds 	switch (pcode) {
21871da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21881da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21891da177e4SLinus Torvalds 		offset += len;
21901da177e4SLinus Torvalds 		break;
21911da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21921da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21931da177e4SLinus Torvalds 		offset += len;
21941da177e4SLinus Torvalds 		break;
21951da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2196760f3b03SDouglas Gilbert 		if (is_disk) {
21971da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
21981da177e4SLinus Torvalds 			offset += len;
2199760f3b03SDouglas Gilbert 		} else
2200760f3b03SDouglas Gilbert 			bad_pcode = true;
22011da177e4SLinus Torvalds 		break;
22021da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2203760f3b03SDouglas Gilbert 		if (is_disk) {
22041da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
22051da177e4SLinus Torvalds 			offset += len;
2206760f3b03SDouglas Gilbert 		} else
2207760f3b03SDouglas Gilbert 			bad_pcode = true;
22081da177e4SLinus Torvalds 		break;
22091da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
22101da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
22111da177e4SLinus Torvalds 		offset += len;
22121da177e4SLinus Torvalds 		break;
2213c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2214c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
221522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2216c65b1445SDouglas Gilbert 			return check_condition_result;
2217c65b1445SDouglas Gilbert 		}
2218c65b1445SDouglas Gilbert 		len = 0;
2219c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2220c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2221c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2222c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2223c65b1445SDouglas Gilbert 						  target_dev_id);
2224c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2225c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2226c65b1445SDouglas Gilbert 		offset += len;
2227c65b1445SDouglas Gilbert 		break;
22281da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
22291da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
22301da177e4SLinus Torvalds 		offset += len;
22311da177e4SLinus Torvalds 		break;
22321da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2233c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
22341da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
22351da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2236760f3b03SDouglas Gilbert 			if (is_disk) {
2237760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2238760f3b03SDouglas Gilbert 						      target);
2239760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2240760f3b03SDouglas Gilbert 						       target);
2241760f3b03SDouglas Gilbert 			}
22421da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2243c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2244c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2245c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2246c65b1445SDouglas Gilbert 						  target, target_dev_id);
2247c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2248c65b1445SDouglas Gilbert 			}
22491da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2250760f3b03SDouglas Gilbert 			offset += len;
2251c65b1445SDouglas Gilbert 		} else {
225222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2253c65b1445SDouglas Gilbert 			return check_condition_result;
2254c65b1445SDouglas Gilbert 		}
22551da177e4SLinus Torvalds 		break;
22561da177e4SLinus Torvalds 	default:
2257760f3b03SDouglas Gilbert 		bad_pcode = true;
2258760f3b03SDouglas Gilbert 		break;
2259760f3b03SDouglas Gilbert 	}
2260760f3b03SDouglas Gilbert 	if (bad_pcode) {
226122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22621da177e4SLinus Torvalds 		return check_condition_result;
22631da177e4SLinus Torvalds 	}
22641da177e4SLinus Torvalds 	if (msense_6)
22651da177e4SLinus Torvalds 		arr[0] = offset - 1;
2266773642d9SDouglas Gilbert 	else
2267773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22681da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22691da177e4SLinus Torvalds }
22701da177e4SLinus Torvalds 
2271c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2272c65b1445SDouglas Gilbert 
2273fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2274fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2275c65b1445SDouglas Gilbert {
2276c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2277c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2278c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
227901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2280c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2281c65b1445SDouglas Gilbert 
2282c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2283c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2284c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2285773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2286c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
228722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2288c65b1445SDouglas Gilbert 		return check_condition_result;
2289c65b1445SDouglas Gilbert 	}
2290c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2291c65b1445SDouglas Gilbert 	if (-1 == res)
2292773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2293773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2294cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2295cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2296cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2297773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2298773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
229923183910SDouglas Gilbert 	if (md_len > 2) {
230022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2301c65b1445SDouglas Gilbert 		return check_condition_result;
2302c65b1445SDouglas Gilbert 	}
2303c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2304c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2305c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2306c65b1445SDouglas Gilbert 	if (ps) {
230722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2308c65b1445SDouglas Gilbert 		return check_condition_result;
2309c65b1445SDouglas Gilbert 	}
2310c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2311773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2312c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2313c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2314cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2315c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2316c65b1445SDouglas Gilbert 		return check_condition_result;
2317c65b1445SDouglas Gilbert 	}
2318c65b1445SDouglas Gilbert 	switch (mpage) {
2319cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2320cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2321cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2322cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2323cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2324cbf67842SDouglas Gilbert 		}
2325cbf67842SDouglas Gilbert 		break;
2326c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2327c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2328c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2329c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2330773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2331cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2332c65b1445SDouglas Gilbert 		}
2333c65b1445SDouglas Gilbert 		break;
2334c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2335c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2336c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2337c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2338cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2339c65b1445SDouglas Gilbert 		}
2340c65b1445SDouglas Gilbert 		break;
2341c65b1445SDouglas Gilbert 	default:
2342c65b1445SDouglas Gilbert 		break;
2343c65b1445SDouglas Gilbert 	}
234422017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2345c65b1445SDouglas Gilbert 	return check_condition_result;
2346cbf67842SDouglas Gilbert set_mode_changed_ua:
2347cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2348cbf67842SDouglas Gilbert 	return 0;
2349c65b1445SDouglas Gilbert }
2350c65b1445SDouglas Gilbert 
2351c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2352c65b1445SDouglas Gilbert {
2353c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2354c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2355c65b1445SDouglas Gilbert 		};
2356c65b1445SDouglas Gilbert 
2357c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2358c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2359c65b1445SDouglas Gilbert }
2360c65b1445SDouglas Gilbert 
2361c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2362c65b1445SDouglas Gilbert {
2363c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2364c65b1445SDouglas Gilbert 		};
2365c65b1445SDouglas Gilbert 
2366c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2367c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2368c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2369c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2370c65b1445SDouglas Gilbert 	}
2371c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2372c65b1445SDouglas Gilbert }
2373c65b1445SDouglas Gilbert 
2374c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2375c65b1445SDouglas Gilbert 
2376c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2377c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2378c65b1445SDouglas Gilbert {
2379ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2380c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
238101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2382c65b1445SDouglas Gilbert 
2383c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2384c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2385c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2386c65b1445SDouglas Gilbert 	if (ppc || sp) {
238722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2388c65b1445SDouglas Gilbert 		return check_condition_result;
2389c65b1445SDouglas Gilbert 	}
2390c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
239123183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2392773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2393c65b1445SDouglas Gilbert 	arr[0] = pcode;
239423183910SDouglas Gilbert 	if (0 == subpcode) {
2395c65b1445SDouglas Gilbert 		switch (pcode) {
2396c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2397c65b1445SDouglas Gilbert 			n = 4;
2398c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2399c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2400c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2401c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2402c65b1445SDouglas Gilbert 			break;
2403c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2404c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2405c65b1445SDouglas Gilbert 			break;
2406c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2407c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2408c65b1445SDouglas Gilbert 			break;
2409c65b1445SDouglas Gilbert 		default:
241022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2411c65b1445SDouglas Gilbert 			return check_condition_result;
2412c65b1445SDouglas Gilbert 		}
241323183910SDouglas Gilbert 	} else if (0xff == subpcode) {
241423183910SDouglas Gilbert 		arr[0] |= 0x40;
241523183910SDouglas Gilbert 		arr[1] = subpcode;
241623183910SDouglas Gilbert 		switch (pcode) {
241723183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
241823183910SDouglas Gilbert 			n = 4;
241923183910SDouglas Gilbert 			arr[n++] = 0x0;
242023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
242123183910SDouglas Gilbert 			arr[n++] = 0x0;
242223183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
242323183910SDouglas Gilbert 			arr[n++] = 0xd;
242423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
242523183910SDouglas Gilbert 			arr[n++] = 0x2f;
242623183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
242723183910SDouglas Gilbert 			arr[3] = n - 4;
242823183910SDouglas Gilbert 			break;
242923183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
243023183910SDouglas Gilbert 			n = 4;
243123183910SDouglas Gilbert 			arr[n++] = 0xd;
243223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
243323183910SDouglas Gilbert 			arr[3] = n - 4;
243423183910SDouglas Gilbert 			break;
243523183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
243623183910SDouglas Gilbert 			n = 4;
243723183910SDouglas Gilbert 			arr[n++] = 0x2f;
243823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
243923183910SDouglas Gilbert 			arr[3] = n - 4;
244023183910SDouglas Gilbert 			break;
244123183910SDouglas Gilbert 		default:
244222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
244323183910SDouglas Gilbert 			return check_condition_result;
244423183910SDouglas Gilbert 		}
244523183910SDouglas Gilbert 	} else {
244622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
244723183910SDouglas Gilbert 		return check_condition_result;
244823183910SDouglas Gilbert 	}
2449773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2450c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2451c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2452c65b1445SDouglas Gilbert }
2453c65b1445SDouglas Gilbert 
2454cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
245519789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
24561da177e4SLinus Torvalds {
2457c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
245822017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24591da177e4SLinus Torvalds 		return check_condition_result;
24601da177e4SLinus Torvalds 	}
2461c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2462c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
246322017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2464cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2465c65b1445SDouglas Gilbert 		return check_condition_result;
2466c65b1445SDouglas Gilbert 	}
246719789100SFUJITA Tomonori 	return 0;
246819789100SFUJITA Tomonori }
246919789100SFUJITA Tomonori 
2470a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
24710a7e69c7SDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
24720a7e69c7SDouglas Gilbert 			    u32 num, bool do_write)
247319789100SFUJITA Tomonori {
247419789100SFUJITA Tomonori 	int ret;
2475c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2476ae3d56d8SChristoph Hellwig 	struct scsi_data_buffer *sdb = &scmd->sdb;
2477a4517511SAkinobu Mita 	enum dma_data_direction dir;
247819789100SFUJITA Tomonori 
2479c2248fc9SDouglas Gilbert 	if (do_write) {
2480a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
24814f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2482a4517511SAkinobu Mita 	} else {
2483a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2484a4517511SAkinobu Mita 	}
2485a4517511SAkinobu Mita 
2486a4517511SAkinobu Mita 	if (!sdb->length)
2487a4517511SAkinobu Mita 		return 0;
2488ae3d56d8SChristoph Hellwig 	if (scmd->sc_data_direction != dir)
2489a4517511SAkinobu Mita 		return -1;
249019789100SFUJITA Tomonori 
249119789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
249219789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
249319789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
249419789100SFUJITA Tomonori 
2495386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2496773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
24970a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2498773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2499a4517511SAkinobu Mita 		return ret;
2500a4517511SAkinobu Mita 
2501a4517511SAkinobu Mita 	if (rest) {
2502386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2503773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
25040a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
25050a7e69c7SDouglas Gilbert 			    do_write);
2506a4517511SAkinobu Mita 	}
250719789100SFUJITA Tomonori 
250819789100SFUJITA Tomonori 	return ret;
250919789100SFUJITA Tomonori }
251019789100SFUJITA Tomonori 
251138d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
251238d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
251338d5c833SDouglas Gilbert  * return false. */
2514fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
251538d5c833SDouglas Gilbert {
251638d5c833SDouglas Gilbert 	bool res;
251738d5c833SDouglas Gilbert 	u64 block, rest = 0;
251838d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2519773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
252038d5c833SDouglas Gilbert 
252138d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
252238d5c833SDouglas Gilbert 	if (block + num > store_blks)
252338d5c833SDouglas Gilbert 		rest = block + num - store_blks;
252438d5c833SDouglas Gilbert 
252538d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
252638d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
252738d5c833SDouglas Gilbert 	if (!res)
252838d5c833SDouglas Gilbert 		return res;
252938d5c833SDouglas Gilbert 	if (rest)
253038d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
253138d5c833SDouglas Gilbert 			     rest * lb_size);
253238d5c833SDouglas Gilbert 	if (!res)
253338d5c833SDouglas Gilbert 		return res;
253438d5c833SDouglas Gilbert 	arr += num * lb_size;
253538d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
253638d5c833SDouglas Gilbert 	if (rest)
253738d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
253838d5c833SDouglas Gilbert 		       rest * lb_size);
253938d5c833SDouglas Gilbert 	return res;
254038d5c833SDouglas Gilbert }
254138d5c833SDouglas Gilbert 
254251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2543beb40ea4SAkinobu Mita {
254451d648afSAkinobu Mita 	__be16 csum;
2545beb40ea4SAkinobu Mita 
2546773642d9SDouglas Gilbert 	if (sdebug_guard)
254751d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
254851d648afSAkinobu Mita 	else
2549beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
255051d648afSAkinobu Mita 
2551beb40ea4SAkinobu Mita 	return csum;
2552beb40ea4SAkinobu Mita }
2553beb40ea4SAkinobu Mita 
25546ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2555beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2556beb40ea4SAkinobu Mita {
2557773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2558beb40ea4SAkinobu Mita 
2559beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2560c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2561beb40ea4SAkinobu Mita 			(unsigned long)sector,
2562beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2563beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2564beb40ea4SAkinobu Mita 		return 0x01;
2565beb40ea4SAkinobu Mita 	}
25668475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2567beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2568c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2569c1287970STomas Winkler 			(unsigned long)sector);
2570beb40ea4SAkinobu Mita 		return 0x03;
2571beb40ea4SAkinobu Mita 	}
25728475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2573beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2574c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2575c1287970STomas Winkler 			(unsigned long)sector);
2576beb40ea4SAkinobu Mita 		return 0x03;
2577beb40ea4SAkinobu Mita 	}
2578beb40ea4SAkinobu Mita 	return 0;
2579beb40ea4SAkinobu Mita }
2580beb40ea4SAkinobu Mita 
2581bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
258265f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2583c6a44287SMartin K. Petersen {
2584be4e11beSAkinobu Mita 	size_t resid;
2585c6a44287SMartin K. Petersen 	void *paddr;
258614faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2587be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2588c6a44287SMartin K. Petersen 
2589e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2590e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2591c6a44287SMartin K. Petersen 
2592be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2593be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2594be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2595be4e11beSAkinobu Mita 
2596be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2597be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
259814faa944SAkinobu Mita 		void *start = dif_store(sector);
2599be4e11beSAkinobu Mita 		size_t rest = 0;
260014faa944SAkinobu Mita 
260114faa944SAkinobu Mita 		if (dif_store_end < start + len)
260214faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2603c6a44287SMartin K. Petersen 
2604be4e11beSAkinobu Mita 		paddr = miter.addr;
260514faa944SAkinobu Mita 
260665f72f2aSAkinobu Mita 		if (read)
260765f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
260865f72f2aSAkinobu Mita 		else
260965f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
261065f72f2aSAkinobu Mita 
261165f72f2aSAkinobu Mita 		if (rest) {
261265f72f2aSAkinobu Mita 			if (read)
261314faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
261465f72f2aSAkinobu Mita 			else
261565f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
261665f72f2aSAkinobu Mita 		}
2617c6a44287SMartin K. Petersen 
2618e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2619c6a44287SMartin K. Petersen 		resid -= len;
2620c6a44287SMartin K. Petersen 	}
2621be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2622bb8c063cSAkinobu Mita }
2623c6a44287SMartin K. Petersen 
2624bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2625bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2626bb8c063cSAkinobu Mita {
2627bb8c063cSAkinobu Mita 	unsigned int i;
26286ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2629bb8c063cSAkinobu Mita 	sector_t sector;
2630bb8c063cSAkinobu Mita 
2631c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2632bb8c063cSAkinobu Mita 		int ret;
2633bb8c063cSAkinobu Mita 
2634bb8c063cSAkinobu Mita 		sector = start_sec + i;
2635bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2636bb8c063cSAkinobu Mita 
263751d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2638bb8c063cSAkinobu Mita 			continue;
2639bb8c063cSAkinobu Mita 
2640bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2641bb8c063cSAkinobu Mita 		if (ret) {
2642bb8c063cSAkinobu Mita 			dif_errors++;
2643bb8c063cSAkinobu Mita 			return ret;
2644bb8c063cSAkinobu Mita 		}
2645bb8c063cSAkinobu Mita 	}
2646bb8c063cSAkinobu Mita 
264765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2648c6a44287SMartin K. Petersen 	dix_reads++;
2649c6a44287SMartin K. Petersen 
2650c6a44287SMartin K. Petersen 	return 0;
2651c6a44287SMartin K. Petersen }
2652c6a44287SMartin K. Petersen 
2653fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
265419789100SFUJITA Tomonori {
2655c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2656c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2657c2248fc9SDouglas Gilbert 	u64 lba;
2658c2248fc9SDouglas Gilbert 	u32 num;
2659c2248fc9SDouglas Gilbert 	u32 ei_lba;
266019789100SFUJITA Tomonori 	unsigned long iflags;
266119789100SFUJITA Tomonori 	int ret;
2662c2248fc9SDouglas Gilbert 	bool check_prot;
266319789100SFUJITA Tomonori 
2664c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2665c2248fc9SDouglas Gilbert 	case READ_16:
2666c2248fc9SDouglas Gilbert 		ei_lba = 0;
2667c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2668c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2669c2248fc9SDouglas Gilbert 		check_prot = true;
2670c2248fc9SDouglas Gilbert 		break;
2671c2248fc9SDouglas Gilbert 	case READ_10:
2672c2248fc9SDouglas Gilbert 		ei_lba = 0;
2673c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2674c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2675c2248fc9SDouglas Gilbert 		check_prot = true;
2676c2248fc9SDouglas Gilbert 		break;
2677c2248fc9SDouglas Gilbert 	case READ_6:
2678c2248fc9SDouglas Gilbert 		ei_lba = 0;
2679c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2680c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2681c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2682c2248fc9SDouglas Gilbert 		check_prot = true;
2683c2248fc9SDouglas Gilbert 		break;
2684c2248fc9SDouglas Gilbert 	case READ_12:
2685c2248fc9SDouglas Gilbert 		ei_lba = 0;
2686c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2687c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2688c2248fc9SDouglas Gilbert 		check_prot = true;
2689c2248fc9SDouglas Gilbert 		break;
2690c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2691c2248fc9SDouglas Gilbert 		ei_lba = 0;
2692c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2693c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2694c2248fc9SDouglas Gilbert 		check_prot = false;
2695c2248fc9SDouglas Gilbert 		break;
2696c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2697c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2698c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2699c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2700c2248fc9SDouglas Gilbert 		check_prot = false;
2701c2248fc9SDouglas Gilbert 		break;
2702c2248fc9SDouglas Gilbert 	}
2703f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
27048475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2705c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2706c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2707c2248fc9SDouglas Gilbert 			return check_condition_result;
2708c2248fc9SDouglas Gilbert 		}
27098475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
27108475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2711c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2712c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2713c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2714c2248fc9SDouglas Gilbert 	}
2715f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2716c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2717c2248fc9SDouglas Gilbert 
2718c4837394SDouglas Gilbert 		if (sqcp) {
2719c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2720c2248fc9SDouglas Gilbert 				num /= 2;
2721c2248fc9SDouglas Gilbert 		}
2722c4837394SDouglas Gilbert 	} else
2723c4837394SDouglas Gilbert 		sqcp = NULL;
2724c2248fc9SDouglas Gilbert 
2725c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2726f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2727c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2728c2248fc9SDouglas Gilbert 		return check_condition_result;
2729c2248fc9SDouglas Gilbert 	}
2730c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2731f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2732c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2733c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2734c2248fc9SDouglas Gilbert 		return check_condition_result;
2735c2248fc9SDouglas Gilbert 	}
273619789100SFUJITA Tomonori 
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 
2771ae3d56d8SChristoph Hellwig 	scp->sdb.resid = 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 	}
3028c2248fc9SDouglas Gilbert 
3029c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
3030f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
3031c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3032c2248fc9SDouglas Gilbert 		return check_condition_result;
3033c2248fc9SDouglas Gilbert 	}
3034c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
3035f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
3036c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
3037c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3038c2248fc9SDouglas Gilbert 		return check_condition_result;
3039c2248fc9SDouglas Gilbert 	}
30401da177e4SLinus Torvalds 
30416c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
30426c78cc06SAkinobu Mita 
3043c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3044f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3045c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3046c6a44287SMartin K. Petersen 
3047c6a44287SMartin K. Petersen 		if (prot_ret) {
30486c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
3049c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3050c6a44287SMartin K. Petersen 			return illegal_condition_result;
3051c6a44287SMartin K. Petersen 		}
3052c6a44287SMartin K. Petersen 	}
3053c6a44287SMartin K. Petersen 
30540a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, true);
3055f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
305644d92694SMartin K. Petersen 		map_region(lba, num);
30571da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3058f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3059773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3060c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3061c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3062c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3063cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3064773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
306544d92694SMartin K. Petersen 
3066f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3067c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3068c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3069c2248fc9SDouglas Gilbert 
3070c4837394SDouglas Gilbert 		if (sqcp) {
3071c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3072c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3073c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3074c2248fc9SDouglas Gilbert 				return check_condition_result;
3075c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3076c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3077c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3078c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3079c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3080c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3081c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3082c2248fc9SDouglas Gilbert 			}
3083c2248fc9SDouglas Gilbert 		}
3084c4837394SDouglas Gilbert 	}
30851da177e4SLinus Torvalds 	return 0;
30861da177e4SLinus Torvalds }
30871da177e4SLinus Torvalds 
3088481b5e5cSDouglas Gilbert /*
3089481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3090481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3091481b5e5cSDouglas Gilbert  */
3092481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3093481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3094481b5e5cSDouglas Gilbert {
3095481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3096481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3097481b5e5cSDouglas Gilbert 	u8 *up;
3098481b5e5cSDouglas Gilbert 	u8 wrprotect;
3099481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3100481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3101481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3102481b5e5cSDouglas Gilbert 	u32 ei_lba;
3103481b5e5cSDouglas Gilbert 	u64 lba;
3104481b5e5cSDouglas Gilbert 	unsigned long iflags;
3105481b5e5cSDouglas Gilbert 	int ret, res;
3106481b5e5cSDouglas Gilbert 	bool is_16;
3107481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3108481b5e5cSDouglas Gilbert 
3109481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3110481b5e5cSDouglas Gilbert 		is_16 = false;
3111481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3112481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3113481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3114481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3115481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3116481b5e5cSDouglas Gilbert 		is_16 = true;
3117481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3118481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3119481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3120481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3121481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3122481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3123481b5e5cSDouglas Gilbert 			    wrprotect) {
3124481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3125481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3126481b5e5cSDouglas Gilbert 			}
3127481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3128481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3129481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3130481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3131481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3132481b5e5cSDouglas Gilbert 		}
3133481b5e5cSDouglas Gilbert 	}
3134481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3135481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3136481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3137481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3138481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3139481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3140481b5e5cSDouglas Gilbert 				my_name, __func__);
3141481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3142481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3143481b5e5cSDouglas Gilbert 	}
3144481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3145481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3146481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3147481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3148481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3149481b5e5cSDouglas Gilbert 				my_name, __func__);
3150481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3151481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3152481b5e5cSDouglas Gilbert 	}
3153481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3154481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3155481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3156481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3157481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3158481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3159481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3160481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3161481b5e5cSDouglas Gilbert 	if (res == -1) {
3162481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3163481b5e5cSDouglas Gilbert 		goto err_out;
3164481b5e5cSDouglas Gilbert 	}
3165481b5e5cSDouglas Gilbert 
3166481b5e5cSDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
3167481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3168481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3169481b5e5cSDouglas Gilbert 	cum_lb = 0;
3170481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3171481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3172481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3173481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3174481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3175481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3176481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3177481b5e5cSDouglas Gilbert 		if (num == 0)
3178481b5e5cSDouglas Gilbert 			continue;
3179481b5e5cSDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
3180481b5e5cSDouglas Gilbert 		if (ret)
3181481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3182481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3183481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3184481b5e5cSDouglas Gilbert 
3185481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3186481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3187481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3188481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3189481b5e5cSDouglas Gilbert 				    my_name, __func__);
3190481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3191481b5e5cSDouglas Gilbert 					0);
3192481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3193481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3194481b5e5cSDouglas Gilbert 		}
3195481b5e5cSDouglas Gilbert 
3196481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3197481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3198481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3199481b5e5cSDouglas Gilbert 							 ei_lba);
3200481b5e5cSDouglas Gilbert 
3201481b5e5cSDouglas Gilbert 			if (prot_ret) {
3202481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3203481b5e5cSDouglas Gilbert 						prot_ret);
3204481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3205481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3206481b5e5cSDouglas Gilbert 			}
3207481b5e5cSDouglas Gilbert 		}
3208481b5e5cSDouglas Gilbert 
3209481b5e5cSDouglas Gilbert 		ret = do_device_access(scp, sg_off, lba, num, true);
3210481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
3211481b5e5cSDouglas Gilbert 			map_region(lba, num);
3212481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3213481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3214481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3215481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3216481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3217481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3218481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3219481b5e5cSDouglas Gilbert 
3220481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3221481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3222481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3223481b5e5cSDouglas Gilbert 
3224481b5e5cSDouglas Gilbert 			if (sqcp) {
3225481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3226481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3227481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3228481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3229481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3230481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3231481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3232481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3233481b5e5cSDouglas Gilbert 							0x10, 1);
3234481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3235481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3236481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3237481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3238481b5e5cSDouglas Gilbert 							0x10, 1);
3239481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3240481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3241481b5e5cSDouglas Gilbert 				}
3242481b5e5cSDouglas Gilbert 			}
3243481b5e5cSDouglas Gilbert 		}
3244481b5e5cSDouglas Gilbert 		sg_off += num_by;
3245481b5e5cSDouglas Gilbert 		cum_lb += num;
3246481b5e5cSDouglas Gilbert 	}
3247481b5e5cSDouglas Gilbert 	ret = 0;
3248481b5e5cSDouglas Gilbert err_out_unlock:
3249481b5e5cSDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3250481b5e5cSDouglas Gilbert err_out:
3251481b5e5cSDouglas Gilbert 	kfree(lrdp);
3252481b5e5cSDouglas Gilbert 	return ret;
3253481b5e5cSDouglas Gilbert }
3254481b5e5cSDouglas Gilbert 
3255fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3256fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
325744d92694SMartin K. Petersen {
325844d92694SMartin K. Petersen 	unsigned long iflags;
325944d92694SMartin K. Petersen 	unsigned long long i;
326044d92694SMartin K. Petersen 	int ret;
3261773642d9SDouglas Gilbert 	u64 lba_off;
326244d92694SMartin K. Petersen 
3263c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
326444d92694SMartin K. Petersen 	if (ret)
326544d92694SMartin K. Petersen 		return ret;
326644d92694SMartin K. Petersen 
326744d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
326844d92694SMartin K. Petersen 
32699ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
327044d92694SMartin K. Petersen 		unmap_region(lba, num);
327144d92694SMartin K. Petersen 		goto out;
327244d92694SMartin K. Petersen 	}
327344d92694SMartin K. Petersen 
3274773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
3275c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3276c2248fc9SDouglas Gilbert 	if (ndob) {
3277773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
3278c2248fc9SDouglas Gilbert 		ret = 0;
3279c2248fc9SDouglas Gilbert 	} else
3280773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3281773642d9SDouglas Gilbert 					  sdebug_sector_size);
328244d92694SMartin K. Petersen 
328344d92694SMartin K. Petersen 	if (-1 == ret) {
328444d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3285773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3286e33d7c56SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
3287c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3288e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
3289cbf67842SDouglas Gilbert 			    my_name, "write same",
3290e33d7c56SDouglas Gilbert 			    sdebug_sector_size, ret);
329144d92694SMartin K. Petersen 
329244d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
329344d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3294773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3295773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3296773642d9SDouglas Gilbert 		       sdebug_sector_size);
329744d92694SMartin K. Petersen 
32989ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
329944d92694SMartin K. Petersen 		map_region(lba, num);
330044d92694SMartin K. Petersen out:
330144d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
330244d92694SMartin K. Petersen 
330344d92694SMartin K. Petersen 	return 0;
330444d92694SMartin K. Petersen }
330544d92694SMartin K. Petersen 
3306fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3307fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3308c2248fc9SDouglas Gilbert {
3309c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3310c2248fc9SDouglas Gilbert 	u32 lba;
3311c2248fc9SDouglas Gilbert 	u16 num;
3312c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3313c2248fc9SDouglas Gilbert 	bool unmap = false;
3314c2248fc9SDouglas Gilbert 
3315c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3316773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3317c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3318c2248fc9SDouglas Gilbert 			return check_condition_result;
3319c2248fc9SDouglas Gilbert 		} else
3320c2248fc9SDouglas Gilbert 			unmap = true;
3321c2248fc9SDouglas Gilbert 	}
3322c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3323c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3324773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3325c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3326c2248fc9SDouglas Gilbert 		return check_condition_result;
3327c2248fc9SDouglas Gilbert 	}
3328c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3329c2248fc9SDouglas Gilbert }
3330c2248fc9SDouglas Gilbert 
3331fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3332fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3333c2248fc9SDouglas Gilbert {
3334c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3335c2248fc9SDouglas Gilbert 	u64 lba;
3336c2248fc9SDouglas Gilbert 	u32 num;
3337c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3338c2248fc9SDouglas Gilbert 	bool unmap = false;
3339c2248fc9SDouglas Gilbert 	bool ndob = false;
3340c2248fc9SDouglas Gilbert 
3341c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3342773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3343c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3344c2248fc9SDouglas Gilbert 			return check_condition_result;
3345c2248fc9SDouglas Gilbert 		} else
3346c2248fc9SDouglas Gilbert 			unmap = true;
3347c2248fc9SDouglas Gilbert 	}
3348c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3349c2248fc9SDouglas Gilbert 		ndob = true;
3350c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3351c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3352773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3353c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3354c2248fc9SDouglas Gilbert 		return check_condition_result;
3355c2248fc9SDouglas Gilbert 	}
3356c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3357c2248fc9SDouglas Gilbert }
3358c2248fc9SDouglas Gilbert 
3359acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3360acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3361acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3362fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3363fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3364acafd0b9SEwan D. Milne {
3365acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3366acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3367acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3368acafd0b9SEwan D. Milne 	u8 mode;
3369acafd0b9SEwan D. Milne 
3370acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3371acafd0b9SEwan D. Milne 	switch (mode) {
3372acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3373acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3374acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3375acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3376acafd0b9SEwan D. Milne 		break;
3377acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3378acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3379acafd0b9SEwan D. Milne 		break;
3380acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3381acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3382acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3383acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3384acafd0b9SEwan D. Milne 				    dev_list)
3385acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3386acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3387acafd0b9SEwan D. Milne 				if (devip != dp)
3388acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3389acafd0b9SEwan D. Milne 						dp->uas_bm);
3390acafd0b9SEwan D. Milne 			}
3391acafd0b9SEwan D. Milne 		break;
3392acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3393acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3394acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3395acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3396acafd0b9SEwan D. Milne 				    dev_list)
3397acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3398acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3399acafd0b9SEwan D. Milne 					dp->uas_bm);
3400acafd0b9SEwan D. Milne 		break;
3401acafd0b9SEwan D. Milne 	default:
3402acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3403acafd0b9SEwan D. Milne 		break;
3404acafd0b9SEwan D. Milne 	}
3405acafd0b9SEwan D. Milne 	return 0;
3406acafd0b9SEwan D. Milne }
3407acafd0b9SEwan D. Milne 
3408fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3409fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
341038d5c833SDouglas Gilbert {
341138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
341238d5c833SDouglas Gilbert 	u8 *arr;
341338d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
341438d5c833SDouglas Gilbert 	u64 lba;
341538d5c833SDouglas Gilbert 	u32 dnum;
3416773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
341738d5c833SDouglas Gilbert 	u8 num;
341838d5c833SDouglas Gilbert 	unsigned long iflags;
341938d5c833SDouglas Gilbert 	int ret;
3420d467d31fSDouglas Gilbert 	int retval = 0;
342138d5c833SDouglas Gilbert 
3422d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
342338d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
342438d5c833SDouglas Gilbert 	if (0 == num)
342538d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
34268475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
342738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
342838d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
342938d5c833SDouglas Gilbert 		return check_condition_result;
343038d5c833SDouglas Gilbert 	}
34318475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34328475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
343338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
343438d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
343538d5c833SDouglas Gilbert 			    "to DIF device\n");
343638d5c833SDouglas Gilbert 
343738d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
343838d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
343938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
344038d5c833SDouglas Gilbert 		return check_condition_result;
344138d5c833SDouglas Gilbert 	}
344238d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
344338d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
344438d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
344538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
344638d5c833SDouglas Gilbert 		return check_condition_result;
344738d5c833SDouglas Gilbert 	}
3448d467d31fSDouglas Gilbert 	dnum = 2 * num;
34496396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3450d467d31fSDouglas Gilbert 	if (NULL == arr) {
3451d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3452d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3453d467d31fSDouglas Gilbert 		return check_condition_result;
3454d467d31fSDouglas Gilbert 	}
345538d5c833SDouglas Gilbert 
345638d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
345738d5c833SDouglas Gilbert 
345838d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
345938d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
346038d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
346138d5c833SDouglas Gilbert 	fake_storep = arr;
34620a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, 0, dnum, true);
346338d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
346438d5c833SDouglas Gilbert 	if (ret == -1) {
3465d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3466d467d31fSDouglas Gilbert 		goto cleanup;
3467773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
346838d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
346938d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
347038d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
347138d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
347238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3473d467d31fSDouglas Gilbert 		retval = check_condition_result;
3474d467d31fSDouglas Gilbert 		goto cleanup;
347538d5c833SDouglas Gilbert 	}
347638d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
347738d5c833SDouglas Gilbert 		map_region(lba, num);
3478d467d31fSDouglas Gilbert cleanup:
347938d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3480d467d31fSDouglas Gilbert 	kfree(arr);
3481d467d31fSDouglas Gilbert 	return retval;
348238d5c833SDouglas Gilbert }
348338d5c833SDouglas Gilbert 
348444d92694SMartin K. Petersen struct unmap_block_desc {
348544d92694SMartin K. Petersen 	__be64	lba;
348644d92694SMartin K. Petersen 	__be32	blocks;
348744d92694SMartin K. Petersen 	__be32	__reserved;
348844d92694SMartin K. Petersen };
348944d92694SMartin K. Petersen 
3490fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
349144d92694SMartin K. Petersen {
349244d92694SMartin K. Petersen 	unsigned char *buf;
349344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
349444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
349544d92694SMartin K. Petersen 	int ret;
34966c78cc06SAkinobu Mita 	unsigned long iflags;
349744d92694SMartin K. Petersen 
349844d92694SMartin K. Petersen 
3499c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3500c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3501c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3502c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
350344d92694SMartin K. Petersen 
350444d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3505773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3506c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
350744d92694SMartin K. Petersen 		return check_condition_result;
3508c2248fc9SDouglas Gilbert 	}
350944d92694SMartin K. Petersen 
3510b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3511c2248fc9SDouglas Gilbert 	if (!buf) {
3512c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3513c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3514c2248fc9SDouglas Gilbert 		return check_condition_result;
3515c2248fc9SDouglas Gilbert 	}
3516c2248fc9SDouglas Gilbert 
3517c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
351844d92694SMartin K. Petersen 
351944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
352044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
352144d92694SMartin K. Petersen 
352244d92694SMartin K. Petersen 	desc = (void *)&buf[8];
352344d92694SMartin K. Petersen 
35246c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
35256c78cc06SAkinobu Mita 
352644d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
352744d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
352844d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
352944d92694SMartin K. Petersen 
3530c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
353144d92694SMartin K. Petersen 		if (ret)
353244d92694SMartin K. Petersen 			goto out;
353344d92694SMartin K. Petersen 
353444d92694SMartin K. Petersen 		unmap_region(lba, num);
353544d92694SMartin K. Petersen 	}
353644d92694SMartin K. Petersen 
353744d92694SMartin K. Petersen 	ret = 0;
353844d92694SMartin K. Petersen 
353944d92694SMartin K. Petersen out:
35406c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
354144d92694SMartin K. Petersen 	kfree(buf);
354244d92694SMartin K. Petersen 
354344d92694SMartin K. Petersen 	return ret;
354444d92694SMartin K. Petersen }
354544d92694SMartin K. Petersen 
354644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
354744d92694SMartin K. Petersen 
3548fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3549fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
355044d92694SMartin K. Petersen {
3551c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3552c2248fc9SDouglas Gilbert 	u64 lba;
3553c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3554c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
355544d92694SMartin K. Petersen 	int ret;
355644d92694SMartin K. Petersen 
3557c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3558c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
355944d92694SMartin K. Petersen 
356044d92694SMartin K. Petersen 	if (alloc_len < 24)
356144d92694SMartin K. Petersen 		return 0;
356244d92694SMartin K. Petersen 
3563c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
356444d92694SMartin K. Petersen 	if (ret)
356544d92694SMartin K. Petersen 		return ret;
356644d92694SMartin K. Petersen 
3567c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
356844d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3569c2248fc9SDouglas Gilbert 	else {
3570c2248fc9SDouglas Gilbert 		mapped = 1;
3571c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3572c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3573c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3574c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3575c2248fc9SDouglas Gilbert 		else
3576c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3577c2248fc9SDouglas Gilbert 	}
357844d92694SMartin K. Petersen 
357944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3580c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3581c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3582c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3583c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
358444d92694SMartin K. Petersen 
3585c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
358644d92694SMartin K. Petersen }
358744d92694SMartin K. Petersen 
358880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
358980c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
359080c49563SDouglas Gilbert {
35914f2c8bf6SDouglas Gilbert 	int res = 0;
359280c49563SDouglas Gilbert 	u64 lba;
359380c49563SDouglas Gilbert 	u32 num_blocks;
359480c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
359580c49563SDouglas Gilbert 
359680c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
359780c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
359880c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
359980c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
360080c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
360180c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
360280c49563SDouglas Gilbert 	}
360380c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
360480c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
360580c49563SDouglas Gilbert 		return check_condition_result;
360680c49563SDouglas Gilbert 	}
36074f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
36084f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
36094f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
36104f2c8bf6SDouglas Gilbert 		write_since_sync = false;
36114f2c8bf6SDouglas Gilbert 	return res;
361280c49563SDouglas Gilbert }
361380c49563SDouglas Gilbert 
3614fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3615fb0cc8d1SDouglas Gilbert 
36168d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
36178d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
36188d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
36198d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
36208d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
36218d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
36228d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
36238d039e22SDouglas Gilbert  */
36241da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
36251da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
36261da177e4SLinus Torvalds {
362701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
36288d039e22SDouglas Gilbert 	unsigned int alloc_len;
36298d039e22SDouglas Gilbert 	unsigned char select_report;
36308d039e22SDouglas Gilbert 	u64 lun;
36318d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3632fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
36338d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
36348d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
36358d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
36368d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3637fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3638fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3639fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
36401da177e4SLinus Torvalds 
364119c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
36428d039e22SDouglas Gilbert 
36438d039e22SDouglas Gilbert 	select_report = cmd[2];
36448d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
36458d039e22SDouglas Gilbert 
36468d039e22SDouglas Gilbert 	if (alloc_len < 4) {
36478d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
36488d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
36491da177e4SLinus Torvalds 		return check_condition_result;
36501da177e4SLinus Torvalds 	}
36518d039e22SDouglas Gilbert 
36528d039e22SDouglas Gilbert 	switch (select_report) {
36538d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3654773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36558d039e22SDouglas Gilbert 		wlun_cnt = 0;
36568d039e22SDouglas Gilbert 		break;
36578d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3658c65b1445SDouglas Gilbert 		lun_cnt = 0;
36598d039e22SDouglas Gilbert 		wlun_cnt = 1;
36608d039e22SDouglas Gilbert 		break;
36618d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
36628d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36638d039e22SDouglas Gilbert 		wlun_cnt = 1;
36648d039e22SDouglas Gilbert 		break;
36658d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
36668d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
36678d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
36688d039e22SDouglas Gilbert 	default:
36698d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
36708d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
36718d039e22SDouglas Gilbert 		return check_condition_result;
36728d039e22SDouglas Gilbert 	}
36738d039e22SDouglas Gilbert 
36748d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3675c65b1445SDouglas Gilbert 		--lun_cnt;
36768d039e22SDouglas Gilbert 
36778d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3678fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3679fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
36808d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
36818d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
36828d039e22SDouglas Gilbert 
3683fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
36848d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3685fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3686fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3687fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3688fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3689fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3690fb0cc8d1SDouglas Gilbert 			++lun_p;
3691fb0cc8d1SDouglas Gilbert 			j = 1;
3692fb0cc8d1SDouglas Gilbert 		}
3693fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3694fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3695fb0cc8d1SDouglas Gilbert 				break;
3696fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3697fb0cc8d1SDouglas Gilbert 		}
3698fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3699fb0cc8d1SDouglas Gilbert 			break;
3700fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3701fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3702fb0cc8d1SDouglas Gilbert 		if (res)
3703fb0cc8d1SDouglas Gilbert 			return res;
3704fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3705fb0cc8d1SDouglas Gilbert 	}
3706fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3707fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3708fb0cc8d1SDouglas Gilbert 		++j;
3709fb0cc8d1SDouglas Gilbert 	}
3710fb0cc8d1SDouglas Gilbert 	if (j > 0)
3711fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
37128d039e22SDouglas Gilbert 	return res;
37131da177e4SLinus Torvalds }
37141da177e4SLinus Torvalds 
3715c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3716c4837394SDouglas Gilbert {
3717c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
3718c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3719c4837394SDouglas Gilbert 
3720458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3721458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
3722458df78bSBart Van Assche 		hwq = 0;
3723458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
3724c4837394SDouglas Gilbert }
3725c4837394SDouglas Gilbert 
3726c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3727fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
37281da177e4SLinus Torvalds {
37297382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
3730c4837394SDouglas Gilbert 	int qc_idx;
3731cbf67842SDouglas Gilbert 	int retiring = 0;
37321da177e4SLinus Torvalds 	unsigned long iflags;
3733c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3734cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3735cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3736cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
37371da177e4SLinus Torvalds 
373810bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
37397382f9d8SDouglas Gilbert 	if (unlikely(aborted))
37407382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
3741c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3742c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3743c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3744cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3745c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3746c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3747c4837394SDouglas Gilbert 	}
3748c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3749c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
37501da177e4SLinus Torvalds 		return;
37511da177e4SLinus Torvalds 	}
3752c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3753c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3754cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3755b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3756c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3757c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3758c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
37591da177e4SLinus Torvalds 		return;
37601da177e4SLinus Torvalds 	}
3761cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3762f46eb0e9SDouglas Gilbert 	if (likely(devip))
3763cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3764cbf67842SDouglas Gilbert 	else
3765c1287970STomas Winkler 		pr_err("devip=NULL\n");
3766f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3767cbf67842SDouglas Gilbert 		retiring = 1;
3768cbf67842SDouglas Gilbert 
3769cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3770c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3771c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3772c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3773cbf67842SDouglas Gilbert 		return;
37741da177e4SLinus Torvalds 	}
37751da177e4SLinus Torvalds 
3776cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3777cbf67842SDouglas Gilbert 		int k, retval;
3778cbf67842SDouglas Gilbert 
3779cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3780c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3781c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3782c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3783cbf67842SDouglas Gilbert 			return;
3784cbf67842SDouglas Gilbert 		}
3785c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3786773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3787cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3788cbf67842SDouglas Gilbert 		else
3789cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3790cbf67842SDouglas Gilbert 	}
3791c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
37927382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
37937382f9d8SDouglas Gilbert 		if (sdebug_verbose)
37947382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
37957382f9d8SDouglas Gilbert 		return;
37967382f9d8SDouglas Gilbert 	}
3797cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3798cbf67842SDouglas Gilbert }
3799cbf67842SDouglas Gilbert 
3800cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3801fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3802cbf67842SDouglas Gilbert {
3803a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3804a10bc12aSDouglas Gilbert 						  hrt);
3805a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3806cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3807cbf67842SDouglas Gilbert }
38081da177e4SLinus Torvalds 
3809a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3810fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3811a10bc12aSDouglas Gilbert {
3812a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3813a10bc12aSDouglas Gilbert 						  ew.work);
3814a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3815a10bc12aSDouglas Gilbert }
3816a10bc12aSDouglas Gilbert 
381709ba24c1SDouglas Gilbert static bool got_shared_uuid;
3818bf476433SChristoph Hellwig static uuid_t shared_uuid;
381909ba24c1SDouglas Gilbert 
3820fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3821fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
38225cb2fc06SFUJITA Tomonori {
38235cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
38245cb2fc06SFUJITA Tomonori 
38255cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
38265cb2fc06SFUJITA Tomonori 	if (devip) {
382709ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3828bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
382909ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
383009ba24c1SDouglas Gilbert 			if (got_shared_uuid)
383109ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
383209ba24c1SDouglas Gilbert 			else {
3833bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
383409ba24c1SDouglas Gilbert 				got_shared_uuid = true;
383509ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
383609ba24c1SDouglas Gilbert 			}
383709ba24c1SDouglas Gilbert 		}
38385cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
38395cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
38405cb2fc06SFUJITA Tomonori 	}
38415cb2fc06SFUJITA Tomonori 	return devip;
38425cb2fc06SFUJITA Tomonori }
38435cb2fc06SFUJITA Tomonori 
3844f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
38451da177e4SLinus Torvalds {
38461da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
38471da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3848f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
38491da177e4SLinus Torvalds 
3850d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
38511da177e4SLinus Torvalds 	if (!sdbg_host) {
3852c1287970STomas Winkler 		pr_err("Host info NULL\n");
38531da177e4SLinus Torvalds 		return NULL;
38541da177e4SLinus Torvalds 	}
38551da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
38561da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
38571da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
38581da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
38591da177e4SLinus Torvalds 			return devip;
38601da177e4SLinus Torvalds 		else {
38611da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
38621da177e4SLinus Torvalds 				open_devip = devip;
38631da177e4SLinus Torvalds 		}
38641da177e4SLinus Torvalds 	}
38655cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
38665cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
38675cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3868c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
38691da177e4SLinus Torvalds 			return NULL;
38701da177e4SLinus Torvalds 		}
38711da177e4SLinus Torvalds 	}
3872a75869d1SFUJITA Tomonori 
38731da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
38741da177e4SLinus Torvalds 	open_devip->target = sdev->id;
38751da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
38761da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3877cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3878cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3879c2248fc9SDouglas Gilbert 	open_devip->used = true;
38801da177e4SLinus Torvalds 	return open_devip;
38811da177e4SLinus Torvalds }
38821da177e4SLinus Torvalds 
38838dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
38841da177e4SLinus Torvalds {
3885773642d9SDouglas Gilbert 	if (sdebug_verbose)
3886c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
38878dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
38888dea0d02SFUJITA Tomonori 	return 0;
38898dea0d02SFUJITA Tomonori }
38901da177e4SLinus Torvalds 
38918dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
38928dea0d02SFUJITA Tomonori {
3893f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3894f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3895a34c4e98SFUJITA Tomonori 
3896773642d9SDouglas Gilbert 	if (sdebug_verbose)
3897c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
38988dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3899b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3900b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3901b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3902f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3903b01f6f83SDouglas Gilbert 		if (devip == NULL)
39048dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3905f46eb0e9SDouglas Gilbert 	}
3906c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
3907773642d9SDouglas Gilbert 	if (sdebug_no_uld)
390878d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
39099b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
39108dea0d02SFUJITA Tomonori 	return 0;
39118dea0d02SFUJITA Tomonori }
39128dea0d02SFUJITA Tomonori 
39138dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
39148dea0d02SFUJITA Tomonori {
39158dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
39168dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
39178dea0d02SFUJITA Tomonori 
3918773642d9SDouglas Gilbert 	if (sdebug_verbose)
3919c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
39208dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39218dea0d02SFUJITA Tomonori 	if (devip) {
392225985edcSLucas De Marchi 		/* make this slot available for re-use */
3923c2248fc9SDouglas Gilbert 		devip->used = false;
39248dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
39258dea0d02SFUJITA Tomonori 	}
39268dea0d02SFUJITA Tomonori }
39278dea0d02SFUJITA Tomonori 
392810bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
392910bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
3930c4837394SDouglas Gilbert {
3931c4837394SDouglas Gilbert 	if (!sd_dp)
3932c4837394SDouglas Gilbert 		return;
393310bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
3934c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
393510bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
3936c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3937c4837394SDouglas Gilbert }
3938c4837394SDouglas Gilbert 
3939a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3940a10bc12aSDouglas Gilbert    returns false */
3941a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
39428dea0d02SFUJITA Tomonori {
39438dea0d02SFUJITA Tomonori 	unsigned long iflags;
3944c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
394510bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
3946c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
39478dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3948cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3949a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39508dea0d02SFUJITA Tomonori 
3951c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3952c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3953773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3954cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3955cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3956cbf67842SDouglas Gilbert 			qmax = r_qmax;
3957cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3958c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3959c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3960a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3961a10bc12aSDouglas Gilbert 					continue;
3962c4837394SDouglas Gilbert 				/* found */
3963db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3964db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3965db525fceSDouglas Gilbert 				if (devip)
3966db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3967db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3968a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
396910bde980SDouglas Gilbert 				if (sd_dp) {
397010bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
397110bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
397210bde980SDouglas Gilbert 				} else
397310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
3974c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
397510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
3976c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3977a10bc12aSDouglas Gilbert 				return true;
39788dea0d02SFUJITA Tomonori 			}
3979cbf67842SDouglas Gilbert 		}
3980c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3981c4837394SDouglas Gilbert 	}
3982a10bc12aSDouglas Gilbert 	return false;
39838dea0d02SFUJITA Tomonori }
39848dea0d02SFUJITA Tomonori 
3985a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
39868dea0d02SFUJITA Tomonori static void stop_all_queued(void)
39878dea0d02SFUJITA Tomonori {
39888dea0d02SFUJITA Tomonori 	unsigned long iflags;
3989c4837394SDouglas Gilbert 	int j, k;
399010bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
3991c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
39928dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3993cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3994a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39958dea0d02SFUJITA Tomonori 
3996c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3997c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3998c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3999c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4000c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4001c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
4002a10bc12aSDouglas Gilbert 					continue;
4003db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4004db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
4005db525fceSDouglas Gilbert 				if (devip)
4006db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4007db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4008a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
400910bde980SDouglas Gilbert 				if (sd_dp) {
401010bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
401110bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
401210bde980SDouglas Gilbert 				} else
401310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4014c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
401510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4016c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4017c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
40188dea0d02SFUJITA Tomonori 			}
40198dea0d02SFUJITA Tomonori 		}
4020c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4021c4837394SDouglas Gilbert 	}
4022cbf67842SDouglas Gilbert }
4023cbf67842SDouglas Gilbert 
4024cbf67842SDouglas Gilbert /* Free queued command memory on heap */
4025cbf67842SDouglas Gilbert static void free_all_queued(void)
4026cbf67842SDouglas Gilbert {
4027c4837394SDouglas Gilbert 	int j, k;
4028c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4029cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4030cbf67842SDouglas Gilbert 
4031c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4032c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4033c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
4034a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
4035a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
4036cbf67842SDouglas Gilbert 		}
40371da177e4SLinus Torvalds 	}
4038c4837394SDouglas Gilbert }
40391da177e4SLinus Torvalds 
40401da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
40411da177e4SLinus Torvalds {
4042a10bc12aSDouglas Gilbert 	bool ok;
4043a10bc12aSDouglas Gilbert 
40441da177e4SLinus Torvalds 	++num_aborts;
4045cbf67842SDouglas Gilbert 	if (SCpnt) {
4046a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
4047a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4048a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4049a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
4050a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
4051cbf67842SDouglas Gilbert 	}
40521da177e4SLinus Torvalds 	return SUCCESS;
40531da177e4SLinus Torvalds }
40541da177e4SLinus Torvalds 
40551da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
40561da177e4SLinus Torvalds {
40571da177e4SLinus Torvalds 	++num_dev_resets;
4058cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
4059cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
4060f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
4061f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
4062cbf67842SDouglas Gilbert 
4063773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4064cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
40651da177e4SLinus Torvalds 		if (devip)
4066cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
40671da177e4SLinus Torvalds 	}
40681da177e4SLinus Torvalds 	return SUCCESS;
40691da177e4SLinus Torvalds }
40701da177e4SLinus Torvalds 
4071cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4072cbf67842SDouglas Gilbert {
4073cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
4074cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4075cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
4076cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
4077cbf67842SDouglas Gilbert 	int k = 0;
4078cbf67842SDouglas Gilbert 
4079cbf67842SDouglas Gilbert 	++num_target_resets;
4080cbf67842SDouglas Gilbert 	if (!SCpnt)
4081cbf67842SDouglas Gilbert 		goto lie;
4082cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4083cbf67842SDouglas Gilbert 	if (!sdp)
4084cbf67842SDouglas Gilbert 		goto lie;
4085773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4086cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4087cbf67842SDouglas Gilbert 	hp = sdp->host;
4088cbf67842SDouglas Gilbert 	if (!hp)
4089cbf67842SDouglas Gilbert 		goto lie;
4090cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4091cbf67842SDouglas Gilbert 	if (sdbg_host) {
4092cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
4093cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
4094cbf67842SDouglas Gilbert 				    dev_list)
4095cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
4096cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4097cbf67842SDouglas Gilbert 				++k;
4098cbf67842SDouglas Gilbert 			}
4099cbf67842SDouglas Gilbert 	}
4100773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4101cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4102cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
4103cbf67842SDouglas Gilbert lie:
4104cbf67842SDouglas Gilbert 	return SUCCESS;
4105cbf67842SDouglas Gilbert }
4106cbf67842SDouglas Gilbert 
41071da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
41081da177e4SLinus Torvalds {
41091da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4110cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
41111da177e4SLinus Torvalds 	struct scsi_device *sdp;
41121da177e4SLinus Torvalds 	struct Scsi_Host *hp;
4113cbf67842SDouglas Gilbert 	int k = 0;
41141da177e4SLinus Torvalds 
41151da177e4SLinus Torvalds 	++num_bus_resets;
4116cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
4117cbf67842SDouglas Gilbert 		goto lie;
4118cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4119773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4120cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4121cbf67842SDouglas Gilbert 	hp = sdp->host;
4122cbf67842SDouglas Gilbert 	if (hp) {
4123d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
41241da177e4SLinus Torvalds 		if (sdbg_host) {
4125cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
41261da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
4127cbf67842SDouglas Gilbert 					    dev_list) {
4128cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4129cbf67842SDouglas Gilbert 				++k;
41301da177e4SLinus Torvalds 			}
41311da177e4SLinus Torvalds 		}
4132cbf67842SDouglas Gilbert 	}
4133773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4134cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4135cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
4136cbf67842SDouglas Gilbert lie:
41371da177e4SLinus Torvalds 	return SUCCESS;
41381da177e4SLinus Torvalds }
41391da177e4SLinus Torvalds 
41401da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
41411da177e4SLinus Torvalds {
41421da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4143cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4144cbf67842SDouglas Gilbert 	int k = 0;
41451da177e4SLinus Torvalds 
41461da177e4SLinus Torvalds 	++num_host_resets;
4147773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4148cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
41491da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
41501da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
4151cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
4152cbf67842SDouglas Gilbert 				    dev_list) {
4153cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4154cbf67842SDouglas Gilbert 			++k;
4155cbf67842SDouglas Gilbert 		}
41561da177e4SLinus Torvalds 	}
41571da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
41581da177e4SLinus Torvalds 	stop_all_queued();
4159773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4160cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
4161cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
41621da177e4SLinus Torvalds 	return SUCCESS;
41631da177e4SLinus Torvalds }
41641da177e4SLinus Torvalds 
4165f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
41665f2578e5SFUJITA Tomonori 				      unsigned long store_size)
41671da177e4SLinus Torvalds {
41681da177e4SLinus Torvalds 	struct partition *pp;
41691da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
41701da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
41711da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
41721da177e4SLinus Torvalds 
41731da177e4SLinus Torvalds 	/* assume partition table already zeroed */
4174773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
41751da177e4SLinus Torvalds 		return;
4176773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4177773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
4178c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
41791da177e4SLinus Torvalds 	}
4180c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
41811da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4182773642d9SDouglas Gilbert 			   / sdebug_num_parts;
41831da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
41841da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4185773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
41861da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
41871da177e4SLinus Torvalds 			    * heads_by_sects;
4188773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4189773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
41901da177e4SLinus Torvalds 
41911da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
41921da177e4SLinus Torvalds 	ramp[511] = 0xAA;
41931da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
41941da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
41951da177e4SLinus Torvalds 		start_sec = starts[k];
41961da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
41971da177e4SLinus Torvalds 		pp->boot_ind = 0;
41981da177e4SLinus Torvalds 
41991da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
42001da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
42011da177e4SLinus Torvalds 			   / sdebug_sectors_per;
42021da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
42031da177e4SLinus Torvalds 
42041da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
42051da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
42061da177e4SLinus Torvalds 			       / sdebug_sectors_per;
42071da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
42081da177e4SLinus Torvalds 
4209150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4210150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
42111da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
42121da177e4SLinus Torvalds 	}
42131da177e4SLinus Torvalds }
42141da177e4SLinus Torvalds 
4215c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4216c4837394SDouglas Gilbert {
4217c4837394SDouglas Gilbert 	int j;
4218c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4219c4837394SDouglas Gilbert 
4220c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4221c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4222c4837394SDouglas Gilbert }
4223c4837394SDouglas Gilbert 
4224c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4225c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4226c4837394SDouglas Gilbert  */
4227c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4228c4837394SDouglas Gilbert {
4229c4837394SDouglas Gilbert 	int count, modulo;
4230c4837394SDouglas Gilbert 
4231c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4232c4837394SDouglas Gilbert 	if (modulo < 2)
4233c4837394SDouglas Gilbert 		return;
4234c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4235c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4236c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4237c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4238c4837394SDouglas Gilbert }
4239c4837394SDouglas Gilbert 
4240c4837394SDouglas Gilbert static void clear_queue_stats(void)
4241c4837394SDouglas Gilbert {
4242c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4243c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4244c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4245c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4246c4837394SDouglas Gilbert }
4247c4837394SDouglas Gilbert 
4248c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4249c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4250c4837394SDouglas Gilbert {
4251f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4252f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
4253f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
4254f9ba7af8SMartin Wilck 				= sqcp->inj_dif
42557382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
42567382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
4257c4837394SDouglas Gilbert 		return;
4258f9ba7af8SMartin Wilck 	}
4259c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4260c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4261c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4262c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4263c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
42647ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
42657382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
4266c4837394SDouglas Gilbert }
4267c4837394SDouglas Gilbert 
4268c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4269c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4270c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4271c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4272c4837394SDouglas Gilbert  */
4273fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4274f66b8517SMartin Wilck 			 int scsi_result,
4275f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
4276f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
4277f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
42781da177e4SLinus Torvalds {
4279cbf67842SDouglas Gilbert 	unsigned long iflags;
4280cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4281c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4282c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4283299b6c07STomas Winkler 	struct scsi_device *sdp;
4284a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
42851da177e4SLinus Torvalds 
4286b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4287b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4288f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4289f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
42901da177e4SLinus Torvalds 	}
4291299b6c07STomas Winkler 	sdp = cmnd->device;
4292299b6c07STomas Winkler 
4293cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4294cd62b7daSDouglas Gilbert 		goto respond_in_thread;
42951da177e4SLinus Torvalds 
4296cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4297c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4298c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4299c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4300c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4301c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4302c4837394SDouglas Gilbert 	}
4303cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4304cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4305cbf67842SDouglas Gilbert 	inject = 0;
4306f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4307cd62b7daSDouglas Gilbert 		if (scsi_result) {
4308c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4309cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4310cd62b7daSDouglas Gilbert 		} else
4311cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4312c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4313773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4314f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4315cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4316cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4317773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4318cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4319cbf67842SDouglas Gilbert 			inject = 1;
4320cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
43211da177e4SLinus Torvalds 		}
4322cbf67842SDouglas Gilbert 	}
4323cbf67842SDouglas Gilbert 
4324c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4325f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4326c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4327cd62b7daSDouglas Gilbert 		if (scsi_result)
4328cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4329773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4330cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4331773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4332cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4333cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4334773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4335cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4336cbf67842SDouglas Gilbert 						    "report: host busy"));
4337cd62b7daSDouglas Gilbert 		if (scsi_result)
4338cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4339cd62b7daSDouglas Gilbert 		else
4340cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
43411da177e4SLinus Torvalds 	}
4342c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4343cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4344c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
43451da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4346c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4347a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4348c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4349c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4350c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
435110bde980SDouglas Gilbert 	if (sd_dp == NULL) {
435210bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
435310bde980SDouglas Gilbert 		if (sd_dp == NULL)
435410bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
435510bde980SDouglas Gilbert 	}
4356f66b8517SMartin Wilck 
4357f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4358f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
4359f66b8517SMartin Wilck 		/*
4360f66b8517SMartin Wilck 		 * This is the F_DELAY_OVERR case. No delay.
4361f66b8517SMartin Wilck 		 */
4362f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
4363f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
4364f66b8517SMartin Wilck 	}
4365f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4366f66b8517SMartin Wilck 		cmnd->result = scsi_result;
4367f66b8517SMartin Wilck 
4368f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
4369f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4370f66b8517SMartin Wilck 			    __func__, cmnd->result);
4371f66b8517SMartin Wilck 
437210bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
4373b333a819SDouglas Gilbert 		ktime_t kt;
4374cbf67842SDouglas Gilbert 
4375b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
437613f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4377b333a819SDouglas Gilbert 		} else
437810bde980SDouglas Gilbert 			kt = ndelay;
437910bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
438010bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
4381a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4382a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4383c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4384a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4385c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4386c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4387cbf67842SDouglas Gilbert 		}
4388c4837394SDouglas Gilbert 		if (sdebug_statistics)
4389c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
439010bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
4391c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4392c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
439310bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
439410bde980SDouglas Gilbert 			sd_dp->init_wq = true;
4395a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4396c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4397c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4398a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4399cbf67842SDouglas Gilbert 		}
4400c4837394SDouglas Gilbert 		if (sdebug_statistics)
4401c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
440210bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
44037382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
44047382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
4405a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
44067382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
44077382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
44087382f9d8SDouglas Gilbert 				    cmnd->request->tag);
44097382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
44107382f9d8SDouglas Gilbert 		}
4411cbf67842SDouglas Gilbert 	}
4412f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4413f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4414cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4415cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4416cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4417cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
44181da177e4SLinus Torvalds 	return 0;
4419cd62b7daSDouglas Gilbert 
4420cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4421f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4422f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
4423f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4424cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
4425cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4426cd62b7daSDouglas Gilbert 	return 0;
44271da177e4SLinus Torvalds }
4428cbf67842SDouglas Gilbert 
442923183910SDouglas Gilbert /* Note: The following macros create attribute files in the
443023183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
443123183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
443223183910SDouglas Gilbert    as it can when the corresponding attribute in the
443323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
443423183910SDouglas Gilbert  */
4435773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4436773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
44379b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4438773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4439c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4440773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4441773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4442773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4443773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4444773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4445773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4446773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4447773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4448e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4449e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4450e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4451e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4452e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4453e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4454773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4455773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4456773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4457773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4458773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4459773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4460773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4461d9da891aSLaurence Oberman module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4462d9da891aSLaurence Oberman module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
4463773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4464773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4465773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4466773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4467773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4468773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4469773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4470773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
447186e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4472773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4473773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4474773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4475773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4476c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4477773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4478c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4479773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4480773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4481773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4482773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4483773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
448409ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4485773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
448623183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4487773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
44885b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
44891da177e4SLinus Torvalds 
44901da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
44911da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
44921da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4493b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
44941da177e4SLinus Torvalds 
44951da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
44965b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
44979b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
44980759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4499cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4500c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
45015b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
45025b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4503c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4504beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
450523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
45065b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4507185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4508e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4509e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
45109b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
45119b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
45125b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
45135b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
45145b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4515760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4516760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
45175b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4518c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4519cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4520d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4521d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
4522cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4523c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
452478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
45251da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4526c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
452732c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
45286f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
45295b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
453086e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
45311da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4532d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4533760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4534ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4535c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4536c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4537c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
45385b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
45395b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
45406014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
45416014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
454209ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
454309ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4544c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
45455b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
45465b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
45471da177e4SLinus Torvalds 
4548760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4549760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
45501da177e4SLinus Torvalds 
45511da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
45521da177e4SLinus Torvalds {
4553c4837394SDouglas Gilbert 	int k;
4554c4837394SDouglas Gilbert 
4555760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4556760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4557760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4558c4837394SDouglas Gilbert 		return sdebug_info;
4559760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4560760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4561760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4562760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
45631da177e4SLinus Torvalds 	return sdebug_info;
45641da177e4SLinus Torvalds }
45651da177e4SLinus Torvalds 
4566cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4567fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4568fd32119bSDouglas Gilbert 				 int length)
45691da177e4SLinus Torvalds {
45701da177e4SLinus Torvalds 	char arr[16];
4571c8ed555aSAl Viro 	int opts;
45721da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
45731da177e4SLinus Torvalds 
45741da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
45751da177e4SLinus Torvalds 		return -EACCES;
45761da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
45771da177e4SLinus Torvalds 	arr[minLen] = '\0';
4578c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
45791da177e4SLinus Torvalds 		return -EINVAL;
4580773642d9SDouglas Gilbert 	sdebug_opts = opts;
4581773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4582773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4583773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4584c4837394SDouglas Gilbert 		tweak_cmnd_count();
45851da177e4SLinus Torvalds 	return length;
45861da177e4SLinus Torvalds }
4587c8ed555aSAl Viro 
4588cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4589cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4590cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4591c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4592c8ed555aSAl Viro {
4593c4837394SDouglas Gilbert 	int f, j, l;
4594c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4595cbf67842SDouglas Gilbert 
4596c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4597c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4598c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4599c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4600c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4601c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4602c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4603c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4604c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4605c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4606c4837394SDouglas Gilbert 		   num_aborts);
4607c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4608c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4609c4837394SDouglas Gilbert 		   num_host_resets);
4610c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4611c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4612458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4613458df78bSBart Van Assche 		   sdebug_statistics);
4614c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4615c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4616c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4617c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4618c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4619cbf67842SDouglas Gilbert 
4620c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4621c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4622c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4623c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4624773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4625c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4626c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4627c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4628c4837394SDouglas Gilbert 		}
4629cbf67842SDouglas Gilbert 	}
4630c8ed555aSAl Viro 	return 0;
46311da177e4SLinus Torvalds }
46321da177e4SLinus Torvalds 
463382069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
46341da177e4SLinus Torvalds {
4635c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
46361da177e4SLinus Torvalds }
4637c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4638c4837394SDouglas Gilbert  * of delay is jiffies.
4639c4837394SDouglas Gilbert  */
464082069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
464182069379SAkinobu Mita 			   size_t count)
46421da177e4SLinus Torvalds {
4643c2206098SDouglas Gilbert 	int jdelay, res;
46441da177e4SLinus Torvalds 
4645b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4646cbf67842SDouglas Gilbert 		res = count;
4647c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4648c4837394SDouglas Gilbert 			int j, k;
4649c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4650cbf67842SDouglas Gilbert 
4651c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4652c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4653c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4654c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4655c4837394SDouglas Gilbert 						   sdebug_max_queue);
4656c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4657c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4658c4837394SDouglas Gilbert 					break;
4659c4837394SDouglas Gilbert 				}
4660c4837394SDouglas Gilbert 			}
4661c4837394SDouglas Gilbert 			if (res > 0) {
4662c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4663773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
46641da177e4SLinus Torvalds 			}
4665c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4666cbf67842SDouglas Gilbert 		}
4667cbf67842SDouglas Gilbert 		return res;
46681da177e4SLinus Torvalds 	}
46691da177e4SLinus Torvalds 	return -EINVAL;
46701da177e4SLinus Torvalds }
467182069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
46721da177e4SLinus Torvalds 
4673cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4674cbf67842SDouglas Gilbert {
4675773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4676cbf67842SDouglas Gilbert }
4677cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4678c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4679cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4680cbf67842SDouglas Gilbert 			    size_t count)
4681cbf67842SDouglas Gilbert {
4682c4837394SDouglas Gilbert 	int ndelay, res;
4683cbf67842SDouglas Gilbert 
4684cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4685c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4686cbf67842SDouglas Gilbert 		res = count;
4687773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4688c4837394SDouglas Gilbert 			int j, k;
4689c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4690c4837394SDouglas Gilbert 
4691c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4692c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4693c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4694c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4695c4837394SDouglas Gilbert 						   sdebug_max_queue);
4696c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4697c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4698c4837394SDouglas Gilbert 					break;
4699c4837394SDouglas Gilbert 				}
4700c4837394SDouglas Gilbert 			}
4701c4837394SDouglas Gilbert 			if (res > 0) {
4702773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4703c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4704c2206098SDouglas Gilbert 							: DEF_JDELAY;
4705cbf67842SDouglas Gilbert 			}
4706c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4707cbf67842SDouglas Gilbert 		}
4708cbf67842SDouglas Gilbert 		return res;
4709cbf67842SDouglas Gilbert 	}
4710cbf67842SDouglas Gilbert 	return -EINVAL;
4711cbf67842SDouglas Gilbert }
4712cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4713cbf67842SDouglas Gilbert 
471482069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
47151da177e4SLinus Torvalds {
4716773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
47171da177e4SLinus Torvalds }
47181da177e4SLinus Torvalds 
471982069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
472082069379SAkinobu Mita 			  size_t count)
47211da177e4SLinus Torvalds {
47221da177e4SLinus Torvalds 	int opts;
47231da177e4SLinus Torvalds 	char work[20];
47241da177e4SLinus Torvalds 
47259a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
47269a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
47279a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
47281da177e4SLinus Torvalds 				goto opts_done;
47291da177e4SLinus Torvalds 		} else {
47309a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
47311da177e4SLinus Torvalds 				goto opts_done;
47321da177e4SLinus Torvalds 		}
47331da177e4SLinus Torvalds 	}
47341da177e4SLinus Torvalds 	return -EINVAL;
47351da177e4SLinus Torvalds opts_done:
4736773642d9SDouglas Gilbert 	sdebug_opts = opts;
4737773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4738773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4739c4837394SDouglas Gilbert 	tweak_cmnd_count();
47401da177e4SLinus Torvalds 	return count;
47411da177e4SLinus Torvalds }
474282069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
47431da177e4SLinus Torvalds 
474482069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
47451da177e4SLinus Torvalds {
4746773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
47471da177e4SLinus Torvalds }
474882069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
474982069379SAkinobu Mita 			   size_t count)
47501da177e4SLinus Torvalds {
47511da177e4SLinus Torvalds 	int n;
47521da177e4SLinus Torvalds 
47531da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4754773642d9SDouglas Gilbert 		sdebug_ptype = n;
47551da177e4SLinus Torvalds 		return count;
47561da177e4SLinus Torvalds 	}
47571da177e4SLinus Torvalds 	return -EINVAL;
47581da177e4SLinus Torvalds }
475982069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
47601da177e4SLinus Torvalds 
476182069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
47621da177e4SLinus Torvalds {
4763773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
47641da177e4SLinus Torvalds }
476582069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
476682069379SAkinobu Mita 			    size_t count)
47671da177e4SLinus Torvalds {
47681da177e4SLinus Torvalds 	int n;
47691da177e4SLinus Torvalds 
47701da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4771773642d9SDouglas Gilbert 		sdebug_dsense = n;
47721da177e4SLinus Torvalds 		return count;
47731da177e4SLinus Torvalds 	}
47741da177e4SLinus Torvalds 	return -EINVAL;
47751da177e4SLinus Torvalds }
477682069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
47771da177e4SLinus Torvalds 
477882069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
477923183910SDouglas Gilbert {
4780773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
478123183910SDouglas Gilbert }
478282069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
478382069379SAkinobu Mita 			     size_t count)
478423183910SDouglas Gilbert {
478523183910SDouglas Gilbert 	int n;
478623183910SDouglas Gilbert 
478723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4788cbf67842SDouglas Gilbert 		n = (n > 0);
4789773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4790773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4791cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4792cbf67842SDouglas Gilbert 				unsigned long sz =
4793773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4794cbf67842SDouglas Gilbert 					1048576;
4795cbf67842SDouglas Gilbert 
47967382f9d8SDouglas Gilbert 				fake_storep = vzalloc(sz);
4797cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4798c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4799cbf67842SDouglas Gilbert 					return -ENOMEM;
4800cbf67842SDouglas Gilbert 				}
4801cbf67842SDouglas Gilbert 			}
4802773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4803cbf67842SDouglas Gilbert 		}
480423183910SDouglas Gilbert 		return count;
480523183910SDouglas Gilbert 	}
480623183910SDouglas Gilbert 	return -EINVAL;
480723183910SDouglas Gilbert }
480882069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
480923183910SDouglas Gilbert 
481082069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4811c65b1445SDouglas Gilbert {
4812773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4813c65b1445SDouglas Gilbert }
481482069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
481582069379SAkinobu Mita 			      size_t count)
4816c65b1445SDouglas Gilbert {
4817c65b1445SDouglas Gilbert 	int n;
4818c65b1445SDouglas Gilbert 
4819c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4820773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4821c65b1445SDouglas Gilbert 		return count;
4822c65b1445SDouglas Gilbert 	}
4823c65b1445SDouglas Gilbert 	return -EINVAL;
4824c65b1445SDouglas Gilbert }
482582069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4826c65b1445SDouglas Gilbert 
482782069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
48281da177e4SLinus Torvalds {
4829773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
48301da177e4SLinus Torvalds }
483182069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
483282069379SAkinobu Mita 			      size_t count)
48331da177e4SLinus Torvalds {
48341da177e4SLinus Torvalds 	int n;
48351da177e4SLinus Torvalds 
48361da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4837773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
48381da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
48391da177e4SLinus Torvalds 		return count;
48401da177e4SLinus Torvalds 	}
48411da177e4SLinus Torvalds 	return -EINVAL;
48421da177e4SLinus Torvalds }
484382069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
48441da177e4SLinus Torvalds 
484582069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
48461da177e4SLinus Torvalds {
4847773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
48481da177e4SLinus Torvalds }
484982069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
48501da177e4SLinus Torvalds 
485182069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
48521da177e4SLinus Torvalds {
4853773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
48541da177e4SLinus Torvalds }
485582069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
48561da177e4SLinus Torvalds 
485782069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
48581da177e4SLinus Torvalds {
4859773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
48601da177e4SLinus Torvalds }
486182069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
486282069379SAkinobu Mita 			       size_t count)
48631da177e4SLinus Torvalds {
48641da177e4SLinus Torvalds 	int nth;
48651da177e4SLinus Torvalds 
48661da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4867773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4868c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4869c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4870c4837394SDouglas Gilbert 			sdebug_statistics = true;
4871c4837394SDouglas Gilbert 		}
4872c4837394SDouglas Gilbert 		tweak_cmnd_count();
48731da177e4SLinus Torvalds 		return count;
48741da177e4SLinus Torvalds 	}
48751da177e4SLinus Torvalds 	return -EINVAL;
48761da177e4SLinus Torvalds }
487782069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
48781da177e4SLinus Torvalds 
487982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
48801da177e4SLinus Torvalds {
4881773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
48821da177e4SLinus Torvalds }
488382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
488482069379SAkinobu Mita 			      size_t count)
48851da177e4SLinus Torvalds {
48861da177e4SLinus Torvalds 	int n;
488719c8ead7SEwan D. Milne 	bool changed;
48881da177e4SLinus Torvalds 
48891da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
48908d039e22SDouglas Gilbert 		if (n > 256) {
48918d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
48928d039e22SDouglas Gilbert 			return -EINVAL;
48938d039e22SDouglas Gilbert 		}
4894773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4895773642d9SDouglas Gilbert 		sdebug_max_luns = n;
48961da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4897773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
489819c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
489919c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
490019c8ead7SEwan D. Milne 
490119c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
490219c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
490319c8ead7SEwan D. Milne 					    host_list) {
490419c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
490519c8ead7SEwan D. Milne 						    dev_list) {
490619c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
490719c8ead7SEwan D. Milne 						dp->uas_bm);
490819c8ead7SEwan D. Milne 				}
490919c8ead7SEwan D. Milne 			}
491019c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
491119c8ead7SEwan D. Milne 		}
49121da177e4SLinus Torvalds 		return count;
49131da177e4SLinus Torvalds 	}
49141da177e4SLinus Torvalds 	return -EINVAL;
49151da177e4SLinus Torvalds }
491682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
49171da177e4SLinus Torvalds 
491882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
491978d4e5a0SDouglas Gilbert {
4920773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
492178d4e5a0SDouglas Gilbert }
4922cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4923cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
492482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
492582069379SAkinobu Mita 			       size_t count)
492678d4e5a0SDouglas Gilbert {
4927c4837394SDouglas Gilbert 	int j, n, k, a;
4928c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
492978d4e5a0SDouglas Gilbert 
493078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4931c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4932c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4933c4837394SDouglas Gilbert 		k = 0;
4934c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4935c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4936c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4937c4837394SDouglas Gilbert 			if (a > k)
4938c4837394SDouglas Gilbert 				k = a;
4939c4837394SDouglas Gilbert 		}
4940773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4941c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4942cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4943cbf67842SDouglas Gilbert 		else if (k >= n)
4944cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4945cbf67842SDouglas Gilbert 		else
4946cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4947c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
494878d4e5a0SDouglas Gilbert 		return count;
494978d4e5a0SDouglas Gilbert 	}
495078d4e5a0SDouglas Gilbert 	return -EINVAL;
495178d4e5a0SDouglas Gilbert }
495282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
495378d4e5a0SDouglas Gilbert 
495482069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
495578d4e5a0SDouglas Gilbert {
4956773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
495778d4e5a0SDouglas Gilbert }
495882069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
495978d4e5a0SDouglas Gilbert 
496082069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
49611da177e4SLinus Torvalds {
4962773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
49631da177e4SLinus Torvalds }
496482069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
49651da177e4SLinus Torvalds 
496682069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4967c65b1445SDouglas Gilbert {
4968773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4969c65b1445SDouglas Gilbert }
497082069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
497182069379SAkinobu Mita 				size_t count)
4972c65b1445SDouglas Gilbert {
4973c65b1445SDouglas Gilbert 	int n;
49740d01c5dfSDouglas Gilbert 	bool changed;
4975c65b1445SDouglas Gilbert 
4976c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4977773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4978773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
497928898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
49800d01c5dfSDouglas Gilbert 		if (changed) {
49810d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
49820d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
498328898873SFUJITA Tomonori 
49844bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
49850d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
49860d01c5dfSDouglas Gilbert 					    host_list) {
49870d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
49880d01c5dfSDouglas Gilbert 						    dev_list) {
49890d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
49900d01c5dfSDouglas Gilbert 						dp->uas_bm);
49910d01c5dfSDouglas Gilbert 				}
49920d01c5dfSDouglas Gilbert 			}
49934bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
49940d01c5dfSDouglas Gilbert 		}
4995c65b1445SDouglas Gilbert 		return count;
4996c65b1445SDouglas Gilbert 	}
4997c65b1445SDouglas Gilbert 	return -EINVAL;
4998c65b1445SDouglas Gilbert }
499982069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
5000c65b1445SDouglas Gilbert 
500182069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
50021da177e4SLinus Torvalds {
5003773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
50041da177e4SLinus Torvalds }
50051da177e4SLinus Torvalds 
5006fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
5007fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
5008fd32119bSDouglas Gilbert 
500982069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
501082069379SAkinobu Mita 			      size_t count)
50111da177e4SLinus Torvalds {
50121da177e4SLinus Torvalds 	int delta_hosts;
50131da177e4SLinus Torvalds 
5014f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
50151da177e4SLinus Torvalds 		return -EINVAL;
50161da177e4SLinus Torvalds 	if (delta_hosts > 0) {
50171da177e4SLinus Torvalds 		do {
50181da177e4SLinus Torvalds 			sdebug_add_adapter();
50191da177e4SLinus Torvalds 		} while (--delta_hosts);
50201da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
50211da177e4SLinus Torvalds 		do {
50221da177e4SLinus Torvalds 			sdebug_remove_adapter();
50231da177e4SLinus Torvalds 		} while (++delta_hosts);
50241da177e4SLinus Torvalds 	}
50251da177e4SLinus Torvalds 	return count;
50261da177e4SLinus Torvalds }
502782069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
50281da177e4SLinus Torvalds 
502982069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
503023183910SDouglas Gilbert {
5031773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
503223183910SDouglas Gilbert }
503382069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
503482069379SAkinobu Mita 				    size_t count)
503523183910SDouglas Gilbert {
503623183910SDouglas Gilbert 	int n;
503723183910SDouglas Gilbert 
503823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5039773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
504023183910SDouglas Gilbert 		return count;
504123183910SDouglas Gilbert 	}
504223183910SDouglas Gilbert 	return -EINVAL;
504323183910SDouglas Gilbert }
504482069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
504523183910SDouglas Gilbert 
5046c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5047c4837394SDouglas Gilbert {
5048c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5049c4837394SDouglas Gilbert }
5050c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5051c4837394SDouglas Gilbert 				size_t count)
5052c4837394SDouglas Gilbert {
5053c4837394SDouglas Gilbert 	int n;
5054c4837394SDouglas Gilbert 
5055c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5056c4837394SDouglas Gilbert 		if (n > 0)
5057c4837394SDouglas Gilbert 			sdebug_statistics = true;
5058c4837394SDouglas Gilbert 		else {
5059c4837394SDouglas Gilbert 			clear_queue_stats();
5060c4837394SDouglas Gilbert 			sdebug_statistics = false;
5061c4837394SDouglas Gilbert 		}
5062c4837394SDouglas Gilbert 		return count;
5063c4837394SDouglas Gilbert 	}
5064c4837394SDouglas Gilbert 	return -EINVAL;
5065c4837394SDouglas Gilbert }
5066c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
5067c4837394SDouglas Gilbert 
506882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
5069597136abSMartin K. Petersen {
5070773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
5071597136abSMartin K. Petersen }
507282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
5073597136abSMartin K. Petersen 
5074c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5075c4837394SDouglas Gilbert {
5076c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5077c4837394SDouglas Gilbert }
5078c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
5079c4837394SDouglas Gilbert 
508082069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
5081c6a44287SMartin K. Petersen {
5082773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
5083c6a44287SMartin K. Petersen }
508482069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
5085c6a44287SMartin K. Petersen 
508682069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
5087c6a44287SMartin K. Petersen {
5088773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
5089c6a44287SMartin K. Petersen }
509082069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
5091c6a44287SMartin K. Petersen 
509282069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
5093c6a44287SMartin K. Petersen {
5094773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
5095c6a44287SMartin K. Petersen }
509682069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
5097c6a44287SMartin K. Petersen 
509882069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
5099c6a44287SMartin K. Petersen {
5100773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
5101c6a44287SMartin K. Petersen }
510282069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
5103c6a44287SMartin K. Petersen 
510482069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
510544d92694SMartin K. Petersen {
510644d92694SMartin K. Petersen 	ssize_t count;
510744d92694SMartin K. Petersen 
51085b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
510944d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
511044d92694SMartin K. Petersen 				 sdebug_store_sectors);
511144d92694SMartin K. Petersen 
5112c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5113c7badc90STejun Heo 			  (int)map_size, map_storep);
511444d92694SMartin K. Petersen 	buf[count++] = '\n';
5115c7badc90STejun Heo 	buf[count] = '\0';
511644d92694SMartin K. Petersen 
511744d92694SMartin K. Petersen 	return count;
511844d92694SMartin K. Petersen }
511982069379SAkinobu Mita static DRIVER_ATTR_RO(map);
512044d92694SMartin K. Petersen 
512182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
5122d986788bSMartin Pitt {
5123773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
5124d986788bSMartin Pitt }
512582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
512682069379SAkinobu Mita 			       size_t count)
5127d986788bSMartin Pitt {
5128d986788bSMartin Pitt 	int n;
5129d986788bSMartin Pitt 
5130d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5131773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
5132d986788bSMartin Pitt 		return count;
5133d986788bSMartin Pitt 	}
5134d986788bSMartin Pitt 	return -EINVAL;
5135d986788bSMartin Pitt }
513682069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
5137d986788bSMartin Pitt 
5138cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5139cbf67842SDouglas Gilbert {
5140773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
5141cbf67842SDouglas Gilbert }
5142185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
5143cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5144cbf67842SDouglas Gilbert 			       size_t count)
5145cbf67842SDouglas Gilbert {
5146185dd232SDouglas Gilbert 	int n;
5147cbf67842SDouglas Gilbert 
5148cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5149185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
5150185dd232SDouglas Gilbert 		return count;
5151cbf67842SDouglas Gilbert 	}
5152cbf67842SDouglas Gilbert 	return -EINVAL;
5153cbf67842SDouglas Gilbert }
5154cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
5155cbf67842SDouglas Gilbert 
5156c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
5157c2248fc9SDouglas Gilbert {
5158773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
5159c2248fc9SDouglas Gilbert }
5160c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5161c2248fc9SDouglas Gilbert 			    size_t count)
5162c2248fc9SDouglas Gilbert {
5163c2248fc9SDouglas Gilbert 	int n;
5164c2248fc9SDouglas Gilbert 
5165c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5166773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
5167c2248fc9SDouglas Gilbert 		return count;
5168c2248fc9SDouglas Gilbert 	}
5169c2248fc9SDouglas Gilbert 	return -EINVAL;
5170c2248fc9SDouglas Gilbert }
5171c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
5172c2248fc9SDouglas Gilbert 
517309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
517409ba24c1SDouglas Gilbert {
517509ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
517609ba24c1SDouglas Gilbert }
517709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
517809ba24c1SDouglas Gilbert 
51799b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
51809b760fd8SDouglas Gilbert {
51819b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
51829b760fd8SDouglas Gilbert }
51839b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
51849b760fd8SDouglas Gilbert 			     size_t count)
51859b760fd8SDouglas Gilbert {
51869b760fd8SDouglas Gilbert 	int ret, n;
51879b760fd8SDouglas Gilbert 
51889b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
51899b760fd8SDouglas Gilbert 	if (ret)
51909b760fd8SDouglas Gilbert 		return ret;
51919b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
51929b760fd8SDouglas Gilbert 	all_config_cdb_len();
51939b760fd8SDouglas Gilbert 	return count;
51949b760fd8SDouglas Gilbert }
51959b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
51969b760fd8SDouglas Gilbert 
5197cbf67842SDouglas Gilbert 
519882069379SAkinobu Mita /* Note: The following array creates attribute files in the
519923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
520023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
520123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
520223183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
520323183910SDouglas Gilbert  */
52046ecaff7fSRandy Dunlap 
520582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
520682069379SAkinobu Mita 	&driver_attr_delay.attr,
520782069379SAkinobu Mita 	&driver_attr_opts.attr,
520882069379SAkinobu Mita 	&driver_attr_ptype.attr,
520982069379SAkinobu Mita 	&driver_attr_dsense.attr,
521082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
521182069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
521282069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
521382069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
521482069379SAkinobu Mita 	&driver_attr_num_parts.attr,
521582069379SAkinobu Mita 	&driver_attr_every_nth.attr,
521682069379SAkinobu Mita 	&driver_attr_max_luns.attr,
521782069379SAkinobu Mita 	&driver_attr_max_queue.attr,
521882069379SAkinobu Mita 	&driver_attr_no_uld.attr,
521982069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
522082069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
522182069379SAkinobu Mita 	&driver_attr_add_host.attr,
522282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
522382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5224c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5225c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
522682069379SAkinobu Mita 	&driver_attr_dix.attr,
522782069379SAkinobu Mita 	&driver_attr_dif.attr,
522882069379SAkinobu Mita 	&driver_attr_guard.attr,
522982069379SAkinobu Mita 	&driver_attr_ato.attr,
523082069379SAkinobu Mita 	&driver_attr_map.attr,
523182069379SAkinobu Mita 	&driver_attr_removable.attr,
5232cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5233cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5234c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
523509ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
52369b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
523782069379SAkinobu Mita 	NULL,
523882069379SAkinobu Mita };
523982069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
52401da177e4SLinus Torvalds 
524111ddcecaSAkinobu Mita static struct device *pseudo_primary;
52428dea0d02SFUJITA Tomonori 
52431da177e4SLinus Torvalds static int __init scsi_debug_init(void)
52441da177e4SLinus Torvalds {
52455f2578e5SFUJITA Tomonori 	unsigned long sz;
52461da177e4SLinus Torvalds 	int host_to_add;
52471da177e4SLinus Torvalds 	int k;
52486ecaff7fSRandy Dunlap 	int ret;
52491da177e4SLinus Torvalds 
5250cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5251cbf67842SDouglas Gilbert 
5252773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5253c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5254773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5255773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5256c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5257cbf67842SDouglas Gilbert 
5258773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5259597136abSMartin K. Petersen 	case  512:
5260597136abSMartin K. Petersen 	case 1024:
5261597136abSMartin K. Petersen 	case 2048:
5262597136abSMartin K. Petersen 	case 4096:
5263597136abSMartin K. Petersen 		break;
5264597136abSMartin K. Petersen 	default:
5265773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5266597136abSMartin K. Petersen 		return -EINVAL;
5267597136abSMartin K. Petersen 	}
5268597136abSMartin K. Petersen 
5269773642d9SDouglas Gilbert 	switch (sdebug_dif) {
52708475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5271f46eb0e9SDouglas Gilbert 		break;
52728475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
52738475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
52748475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5275f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5276c6a44287SMartin K. Petersen 		break;
5277c6a44287SMartin K. Petersen 
5278c6a44287SMartin K. Petersen 	default:
5279c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5280c6a44287SMartin K. Petersen 		return -EINVAL;
5281c6a44287SMartin K. Petersen 	}
5282c6a44287SMartin K. Petersen 
5283773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5284c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5285c6a44287SMartin K. Petersen 		return -EINVAL;
5286c6a44287SMartin K. Petersen 	}
5287c6a44287SMartin K. Petersen 
5288773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5289c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5290c6a44287SMartin K. Petersen 		return -EINVAL;
5291c6a44287SMartin K. Petersen 	}
5292c6a44287SMartin K. Petersen 
5293773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5294773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5295ea61fca5SMartin K. Petersen 		return -EINVAL;
5296ea61fca5SMartin K. Petersen 	}
52978d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
52988d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
52998d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
53008d039e22SDouglas Gilbert 	}
5301ea61fca5SMartin K. Petersen 
5302773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5303773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5304ea61fca5SMartin K. Petersen 		return -EINVAL;
5305ea61fca5SMartin K. Petersen 	}
5306ea61fca5SMartin K. Petersen 
5307c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5308c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5309c4837394SDouglas Gilbert 		return -EINVAL;
5310c4837394SDouglas Gilbert 	}
5311c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5312c4837394SDouglas Gilbert 			       GFP_KERNEL);
5313c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5314c4837394SDouglas Gilbert 		return -ENOMEM;
5315c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5316c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5317c4837394SDouglas Gilbert 
5318773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5319773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5320773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5321773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
532228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
53231da177e4SLinus Torvalds 
53241da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
53251da177e4SLinus Torvalds 	sdebug_heads = 8;
53261da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5327773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
53281da177e4SLinus Torvalds 		sdebug_heads = 64;
5329773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5330fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
53311da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53321da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53331da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
53341da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
53351da177e4SLinus Torvalds 		sdebug_heads = 255;
53361da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
53371da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53381da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53391da177e4SLinus Torvalds 	}
53401da177e4SLinus Torvalds 
5341b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
53427382f9d8SDouglas Gilbert 		fake_storep = vzalloc(sz);
53431da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5344c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5345c4837394SDouglas Gilbert 			ret = -ENOMEM;
5346c4837394SDouglas Gilbert 			goto free_q_arr;
53471da177e4SLinus Torvalds 		}
5348773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5349f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5350cbf67842SDouglas Gilbert 	}
53511da177e4SLinus Torvalds 
5352773642d9SDouglas Gilbert 	if (sdebug_dix) {
5353c6a44287SMartin K. Petersen 		int dif_size;
5354c6a44287SMartin K. Petersen 
53556ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5356c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5357c6a44287SMartin K. Petersen 
5358c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5359c6a44287SMartin K. Petersen 
5360c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5361c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5362c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5363c6a44287SMartin K. Petersen 			goto free_vm;
5364c6a44287SMartin K. Petersen 		}
5365c6a44287SMartin K. Petersen 
5366c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5367c6a44287SMartin K. Petersen 	}
5368c6a44287SMartin K. Petersen 
53695b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
53705b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5371773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5372773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
53736014759cSMartin K. Petersen 
5374773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5375773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
53766014759cSMartin K. Petersen 
5377773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5378773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
53796014759cSMartin K. Petersen 
5380773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5381773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5382773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5383c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5384c4837394SDouglas Gilbert 			ret = -EINVAL;
5385c4837394SDouglas Gilbert 			goto free_vm;
538644d92694SMartin K. Petersen 		}
538744d92694SMartin K. Petersen 
5388b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
538942bc47b3SKees Cook 		map_storep = vmalloc(array_size(sizeof(long),
539042bc47b3SKees Cook 						BITS_TO_LONGS(map_size)));
539144d92694SMartin K. Petersen 
5392c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
539344d92694SMartin K. Petersen 
539444d92694SMartin K. Petersen 		if (map_storep == NULL) {
5395c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
539644d92694SMartin K. Petersen 			ret = -ENOMEM;
539744d92694SMartin K. Petersen 			goto free_vm;
539844d92694SMartin K. Petersen 		}
539944d92694SMartin K. Petersen 
5400b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
540144d92694SMartin K. Petersen 
540244d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5403773642d9SDouglas Gilbert 		if (sdebug_num_parts)
540444d92694SMartin K. Petersen 			map_region(0, 2);
540544d92694SMartin K. Petersen 	}
540644d92694SMartin K. Petersen 
54079b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
54089b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5409c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
54109b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
54116ecaff7fSRandy Dunlap 		goto free_vm;
54126ecaff7fSRandy Dunlap 	}
54136ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
54146ecaff7fSRandy Dunlap 	if (ret < 0) {
5415c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
54166ecaff7fSRandy Dunlap 		goto dev_unreg;
54176ecaff7fSRandy Dunlap 	}
54186ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
54196ecaff7fSRandy Dunlap 	if (ret < 0) {
5420c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
54216ecaff7fSRandy Dunlap 		goto bus_unreg;
54226ecaff7fSRandy Dunlap 	}
54231da177e4SLinus Torvalds 
5424773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5425773642d9SDouglas Gilbert 	sdebug_add_host = 0;
54261da177e4SLinus Torvalds 
54271da177e4SLinus Torvalds 	for (k = 0; k < host_to_add; k++) {
54281da177e4SLinus Torvalds 		if (sdebug_add_adapter()) {
5429c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
54301da177e4SLinus Torvalds 			break;
54311da177e4SLinus Torvalds 		}
54321da177e4SLinus Torvalds 	}
54331da177e4SLinus Torvalds 
5434773642d9SDouglas Gilbert 	if (sdebug_verbose)
5435773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5436c1287970STomas Winkler 
54371da177e4SLinus Torvalds 	return 0;
54386ecaff7fSRandy Dunlap 
54396ecaff7fSRandy Dunlap bus_unreg:
54406ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
54416ecaff7fSRandy Dunlap dev_unreg:
54429b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54436ecaff7fSRandy Dunlap free_vm:
544444d92694SMartin K. Petersen 	vfree(map_storep);
5445c6a44287SMartin K. Petersen 	vfree(dif_storep);
54466ecaff7fSRandy Dunlap 	vfree(fake_storep);
5447c4837394SDouglas Gilbert free_q_arr:
5448c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
54496ecaff7fSRandy Dunlap 	return ret;
54501da177e4SLinus Torvalds }
54511da177e4SLinus Torvalds 
54521da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
54531da177e4SLinus Torvalds {
5454773642d9SDouglas Gilbert 	int k = sdebug_add_host;
54551da177e4SLinus Torvalds 
54561da177e4SLinus Torvalds 	stop_all_queued();
54571da177e4SLinus Torvalds 	for (; k; k--)
54581da177e4SLinus Torvalds 		sdebug_remove_adapter();
545952ab9768SLuis Henriques 	free_all_queued();
54601da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
54611da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
54629b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54631da177e4SLinus Torvalds 
54644d2b496fSEwan D. Milne 	vfree(map_storep);
5465c6a44287SMartin K. Petersen 	vfree(dif_storep);
54661da177e4SLinus Torvalds 	vfree(fake_storep);
5467c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
54681da177e4SLinus Torvalds }
54691da177e4SLinus Torvalds 
54701da177e4SLinus Torvalds device_initcall(scsi_debug_init);
54711da177e4SLinus Torvalds module_exit(scsi_debug_exit);
54721da177e4SLinus Torvalds 
54731da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
54741da177e4SLinus Torvalds {
54751da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54761da177e4SLinus Torvalds 
54771da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54781da177e4SLinus Torvalds 	kfree(sdbg_host);
54791da177e4SLinus Torvalds }
54801da177e4SLinus Torvalds 
54811da177e4SLinus Torvalds static int sdebug_add_adapter(void)
54821da177e4SLinus Torvalds {
54831da177e4SLinus Torvalds 	int k, devs_per_host;
54841da177e4SLinus Torvalds 	int error = 0;
54851da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54868b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
54871da177e4SLinus Torvalds 
548824669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
54899a051019SDouglas Gilbert 	if (sdbg_host == NULL) {
5490c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
54911da177e4SLinus Torvalds 		return -ENOMEM;
54921da177e4SLinus Torvalds 	}
54931da177e4SLinus Torvalds 
54941da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
54951da177e4SLinus Torvalds 
5496773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
54971da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
54985cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
54995cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5500c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
55011da177e4SLinus Torvalds 			error = -ENOMEM;
55021da177e4SLinus Torvalds 			goto clean;
55031da177e4SLinus Torvalds 		}
55041da177e4SLinus Torvalds 	}
55051da177e4SLinus Torvalds 
55061da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55071da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
55081da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55091da177e4SLinus Torvalds 
55101da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
55119b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
55121da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
5513773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
55141da177e4SLinus Torvalds 
55151da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
55161da177e4SLinus Torvalds 
55171da177e4SLinus Torvalds 	if (error)
55181da177e4SLinus Torvalds 		goto clean;
55191da177e4SLinus Torvalds 
5520773642d9SDouglas Gilbert 	++sdebug_add_host;
55211da177e4SLinus Torvalds 	return error;
55221da177e4SLinus Torvalds 
55231da177e4SLinus Torvalds clean:
55248b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55258b40228fSFUJITA Tomonori 				 dev_list) {
55261da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
55271da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
55281da177e4SLinus Torvalds 	}
55291da177e4SLinus Torvalds 
55301da177e4SLinus Torvalds 	kfree(sdbg_host);
55311da177e4SLinus Torvalds 	return error;
55321da177e4SLinus Torvalds }
55331da177e4SLinus Torvalds 
55341da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
55351da177e4SLinus Torvalds {
55361da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
55371da177e4SLinus Torvalds 
55381da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55391da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
55401da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
55411da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
55421da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
55431da177e4SLinus Torvalds 	}
55441da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55451da177e4SLinus Torvalds 
55461da177e4SLinus Torvalds 	if (!sdbg_host)
55471da177e4SLinus Torvalds 		return;
55481da177e4SLinus Torvalds 
55491da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5550773642d9SDouglas Gilbert 	--sdebug_add_host;
55511da177e4SLinus Torvalds }
55521da177e4SLinus Torvalds 
5553fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5554cbf67842SDouglas Gilbert {
5555cbf67842SDouglas Gilbert 	int num_in_q = 0;
5556cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5557cbf67842SDouglas Gilbert 
5558c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5559cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5560cbf67842SDouglas Gilbert 	if (NULL == devip) {
5561c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5562cbf67842SDouglas Gilbert 		return	-ENODEV;
5563cbf67842SDouglas Gilbert 	}
5564cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5565c40ecc12SChristoph Hellwig 
5566cbf67842SDouglas Gilbert 	if (qdepth < 1)
5567cbf67842SDouglas Gilbert 		qdepth = 1;
5568c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5569c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5570c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5571db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5572cbf67842SDouglas Gilbert 
5573773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5574c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5575c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5576cbf67842SDouglas Gilbert 	}
5577c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5578cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5579cbf67842SDouglas Gilbert }
5580cbf67842SDouglas Gilbert 
5581c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5582817fd66bSDouglas Gilbert {
5583c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5584773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5585773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5586773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5587c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5588773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5589817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5590c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5591817fd66bSDouglas Gilbert 	}
5592c4837394SDouglas Gilbert 	return false;
5593817fd66bSDouglas Gilbert }
5594817fd66bSDouglas Gilbert 
55957ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
55967ee6d1b4SBart Van Assche {
55977ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
55987ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
55997ee6d1b4SBart Van Assche }
56007ee6d1b4SBart Van Assche 
5601fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5602fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5603c2248fc9SDouglas Gilbert {
5604c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5605c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5606c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5607c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5608c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5609c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5610c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5611f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
5612c2248fc9SDouglas Gilbert 	int k, na;
5613c2248fc9SDouglas Gilbert 	int errsts = 0;
5614c2248fc9SDouglas Gilbert 	u32 flags;
5615c2248fc9SDouglas Gilbert 	u16 sa;
5616c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5617c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5618c2248fc9SDouglas Gilbert 
5619c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5620c4837394SDouglas Gilbert 	if (sdebug_statistics)
5621c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5622f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5623f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5624c2248fc9SDouglas Gilbert 		char b[120];
5625c2248fc9SDouglas Gilbert 		int n, len, sb;
5626c2248fc9SDouglas Gilbert 
5627c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5628c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5629c2248fc9SDouglas Gilbert 		if (len > 32)
5630c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5631c2248fc9SDouglas Gilbert 		else {
5632c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5633c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5634c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5635c2248fc9SDouglas Gilbert 		}
5636458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5637458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
5638c2248fc9SDouglas Gilbert 	}
56397ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
56407ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
564134d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5642f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5643f46eb0e9SDouglas Gilbert 		goto err_out;
5644c2248fc9SDouglas Gilbert 
5645c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5646c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5647c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5648f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5649f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5650c2248fc9SDouglas Gilbert 		if (NULL == devip)
5651f46eb0e9SDouglas Gilbert 			goto err_out;
5652c2248fc9SDouglas Gilbert 	}
5653c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5654c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5655c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5656c2248fc9SDouglas Gilbert 		r_oip = oip;
5657c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5658c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5659c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5660c2248fc9SDouglas Gilbert 			else
5661c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5662c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5663c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5664c2248fc9SDouglas Gilbert 					break;
5665c2248fc9SDouglas Gilbert 			}
5666c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5667c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5668c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5669c2248fc9SDouglas Gilbert 					break;
5670c2248fc9SDouglas Gilbert 			}
5671c2248fc9SDouglas Gilbert 		}
5672c2248fc9SDouglas Gilbert 		if (k > na) {
5673c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5674c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5675c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5676c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5677c2248fc9SDouglas Gilbert 			else
5678c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5679c2248fc9SDouglas Gilbert 			goto check_cond;
5680c2248fc9SDouglas Gilbert 		}
5681c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5682c2248fc9SDouglas Gilbert 	flags = oip->flags;
5683f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5684c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5685c2248fc9SDouglas Gilbert 		goto check_cond;
5686c2248fc9SDouglas Gilbert 	}
5687f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5688773642d9SDouglas Gilbert 		if (sdebug_verbose)
5689773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5690773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5691c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5692c2248fc9SDouglas Gilbert 		goto check_cond;
5693c2248fc9SDouglas Gilbert 	}
5694f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5695c2248fc9SDouglas Gilbert 		u8 rem;
5696c2248fc9SDouglas Gilbert 		int j;
5697c2248fc9SDouglas Gilbert 
5698c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5699c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5700c2248fc9SDouglas Gilbert 			if (rem) {
5701c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5702c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5703c2248fc9SDouglas Gilbert 						break;
5704c2248fc9SDouglas Gilbert 				}
5705c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5706c2248fc9SDouglas Gilbert 				goto check_cond;
5707c2248fc9SDouglas Gilbert 			}
5708c2248fc9SDouglas Gilbert 		}
5709c2248fc9SDouglas Gilbert 	}
5710f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5711b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5712b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5713f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5714c2248fc9SDouglas Gilbert 		if (errsts)
5715c2248fc9SDouglas Gilbert 			goto check_cond;
5716c2248fc9SDouglas Gilbert 	}
5717c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5718c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5719773642d9SDouglas Gilbert 		if (sdebug_verbose)
5720c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5721c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5722c2248fc9SDouglas Gilbert 				    "required");
5723c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5724c2248fc9SDouglas Gilbert 		goto fini;
5725c2248fc9SDouglas Gilbert 	}
5726773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5727c2248fc9SDouglas Gilbert 		goto fini;
5728f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5729c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5730c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5731c2248fc9SDouglas Gilbert 	}
5732f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5733f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
5734f66b8517SMartin Wilck 	else
5735f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
5736c2248fc9SDouglas Gilbert 
5737c2248fc9SDouglas Gilbert fini:
573810bde980SDouglas Gilbert 	if (F_DELAY_OVERR & flags)
5739f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
574075aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
574175aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
574280c49563SDouglas Gilbert 		/*
574375aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
574475aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
574575aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
574675aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
574780c49563SDouglas Gilbert 		 */
574880c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
57494f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
575080c49563SDouglas Gilbert 
57514f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
5752f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
575380c49563SDouglas Gilbert 	} else
5754f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
575510bde980SDouglas Gilbert 				     sdebug_ndelay);
5756c2248fc9SDouglas Gilbert check_cond:
5757f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
5758f46eb0e9SDouglas Gilbert err_out:
5759f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
5760c2248fc9SDouglas Gilbert }
5761c2248fc9SDouglas Gilbert 
57629e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5763c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5764c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
57659e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
57669e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
57679e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
57689e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
57699e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
57709e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
57719e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5772185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5773cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
57749e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
57759e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5776cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5777cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
57789e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5779c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
57809e603ca0SFUJITA Tomonori 	.this_id =		7,
578165e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5782cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
57836bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
578450c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
57859e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5786c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
57879e603ca0SFUJITA Tomonori };
57889e603ca0SFUJITA Tomonori 
57891da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
57901da177e4SLinus Torvalds {
57911da177e4SLinus Torvalds 	int error = 0;
57921da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
57931da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5794f46eb0e9SDouglas Gilbert 	int hprot;
57951da177e4SLinus Torvalds 
57961da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
57971da177e4SLinus Torvalds 
5798773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
57992a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
58004af14d11SChristoph Hellwig 		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
58014af14d11SChristoph Hellwig 
58021da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
58031da177e4SLinus Torvalds 	if (NULL == hpnt) {
5804c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
58051da177e4SLinus Torvalds 		error = -ENODEV;
58061da177e4SLinus Torvalds 		return error;
58071da177e4SLinus Torvalds 	}
5808c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
58099b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5810c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5811c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5812c4837394SDouglas Gilbert 	}
5813c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5814c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5815c4837394SDouglas Gilbert 	hpnt->nr_hw_queues = submit_queues;
58161da177e4SLinus Torvalds 
58171da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
58181da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5819773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5820773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
58211da177e4SLinus Torvalds 	else
5822773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5823773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5824f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
58251da177e4SLinus Torvalds 
5826f46eb0e9SDouglas Gilbert 	hprot = 0;
5827c6a44287SMartin K. Petersen 
5828773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5829c6a44287SMartin K. Petersen 
58308475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5831f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5832773642d9SDouglas Gilbert 		if (sdebug_dix)
5833f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5834c6a44287SMartin K. Petersen 		break;
5835c6a44287SMartin K. Petersen 
58368475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5837f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5838773642d9SDouglas Gilbert 		if (sdebug_dix)
5839f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5840c6a44287SMartin K. Petersen 		break;
5841c6a44287SMartin K. Petersen 
58428475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5843f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5844773642d9SDouglas Gilbert 		if (sdebug_dix)
5845f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5846c6a44287SMartin K. Petersen 		break;
5847c6a44287SMartin K. Petersen 
5848c6a44287SMartin K. Petersen 	default:
5849773642d9SDouglas Gilbert 		if (sdebug_dix)
5850f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5851c6a44287SMartin K. Petersen 		break;
5852c6a44287SMartin K. Petersen 	}
5853c6a44287SMartin K. Petersen 
5854f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5855c6a44287SMartin K. Petersen 
5856f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5857c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5858f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5859f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5860f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5861f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5862f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5863f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5864f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5865c6a44287SMartin K. Petersen 
5866773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5867c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5868c6a44287SMartin K. Petersen 	else
5869c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5870c6a44287SMartin K. Petersen 
5871773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5872773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5873c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5874c4837394SDouglas Gilbert 		sdebug_statistics = true;
58751da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
58761da177e4SLinus Torvalds 	if (error) {
5877c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
58781da177e4SLinus Torvalds 		error = -ENODEV;
58791da177e4SLinus Torvalds 		scsi_host_put(hpnt);
58801da177e4SLinus Torvalds 	} else
58811da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
58821da177e4SLinus Torvalds 
58831da177e4SLinus Torvalds 	return error;
58841da177e4SLinus Torvalds }
58851da177e4SLinus Torvalds 
58861da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
58871da177e4SLinus Torvalds {
58881da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
58898b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
58901da177e4SLinus Torvalds 
58911da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
58921da177e4SLinus Torvalds 
58931da177e4SLinus Torvalds 	if (!sdbg_host) {
5894c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
58951da177e4SLinus Torvalds 		return -ENODEV;
58961da177e4SLinus Torvalds 	}
58971da177e4SLinus Torvalds 
58981da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
58991da177e4SLinus Torvalds 
59008b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
59018b40228fSFUJITA Tomonori 				 dev_list) {
59021da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
59031da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
59041da177e4SLinus Torvalds 	}
59051da177e4SLinus Torvalds 
59061da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
59071da177e4SLinus Torvalds 	return 0;
59081da177e4SLinus Torvalds }
59091da177e4SLinus Torvalds 
59108dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
59118dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
59121da177e4SLinus Torvalds {
59138dea0d02SFUJITA Tomonori 	return 1;
59148dea0d02SFUJITA Tomonori }
59151da177e4SLinus Torvalds 
59168dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
59178dea0d02SFUJITA Tomonori 	.name = "pseudo",
59188dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
59198dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
59208dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
592182069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
59228dea0d02SFUJITA Tomonori };
5923