xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 50c2e910)
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 *);
433c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
43438d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
435acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
43680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
437c2248fc9SDouglas Gilbert 
43846f64e70SDouglas Gilbert /*
43946f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
44046f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
44146f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
44246f64e70SDouglas Gilbert  */
44346f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
444c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
445c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
446c2248fc9SDouglas Gilbert };
447c2248fc9SDouglas Gilbert 
44846f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
449c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
450c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
451c2248fc9SDouglas Gilbert };
452c2248fc9SDouglas Gilbert 
45346f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
45446f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
455b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
456c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
45746f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
458c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
45946f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
460b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
461c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
462c2248fc9SDouglas Gilbert };
463c2248fc9SDouglas Gilbert 
46446f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
46546f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
46646f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
46746f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
46846f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
46946f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
47046f64e70SDouglas Gilbert 		   0, 0, 0} },
47146f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
47246f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47346f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
474c2248fc9SDouglas Gilbert };
475c2248fc9SDouglas Gilbert 
47646f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
477c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
478c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47946f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
480c2248fc9SDouglas Gilbert };
481c2248fc9SDouglas Gilbert 
48246f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
48346f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
484b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
485c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
486481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
487481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
488481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
489c2248fc9SDouglas Gilbert };
490c2248fc9SDouglas Gilbert 
49146f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
49238d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
493c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
49446f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
49538d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
496c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
49746f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
498c2248fc9SDouglas Gilbert };
499c2248fc9SDouglas Gilbert 
50046f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
50146f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
502c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50346f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
504c2248fc9SDouglas Gilbert };
505c2248fc9SDouglas Gilbert 
50646f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
507c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
508c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
509c2248fc9SDouglas Gilbert };
510c2248fc9SDouglas Gilbert 
51146f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
512c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
513c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
514c2248fc9SDouglas Gilbert };
515c2248fc9SDouglas Gilbert 
51680c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5174f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
51880c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51980c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
52080c49563SDouglas Gilbert };
52180c49563SDouglas Gilbert 
522c2248fc9SDouglas Gilbert 
523c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
524c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
525c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
526c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
527c2248fc9SDouglas Gilbert /* 0 */
52846f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
529c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53046f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
531c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
532c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
533c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
53446f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
535c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
536c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
537c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
538c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53946f64e70SDouglas Gilbert /* 5 */
54046f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
54146f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
54246f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54346f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
54446f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
54546f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54646f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
547c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
548c2248fc9SDouglas Gilbert 	     0, 0, 0} },
54946f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
550c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
551c2248fc9SDouglas Gilbert 	     0, 0} },
55246f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
55346f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
55446f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
555c2248fc9SDouglas Gilbert /* 10 */
55646f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
55746f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
55846f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55980c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
5604f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
561c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
56246f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
56346f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
56446f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56546f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
566481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
567481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
568481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
56946f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
57046f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
57146f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
57246f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
57346f64e70SDouglas Gilbert /* 15 */
574c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
575c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
57646f64e70SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
577f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
578f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
57946f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
58046f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
58146f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
58246f64e70SDouglas Gilbert 	     0xff, 0xff} },
58346f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
58446f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
585c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
586c2248fc9SDouglas Gilbert 	     0} },
58746f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
58846f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
589c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
590c2248fc9SDouglas Gilbert 	     0} },
591c2248fc9SDouglas Gilbert /* 20 */
592f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
593f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
594c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
595c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
596c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
597c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
598c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
599c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
60046f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
601b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
60246f64e70SDouglas Gilbert /* 25 */
60346f64e70SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
604b7e24581SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
60546f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },		/* XDWRITEREAD(10) */
606acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
607acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
608acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
60946f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
61046f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
61146f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
61246f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
6134f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
61480c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
615b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
61680c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
61746f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
618c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
619b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
620c2248fc9SDouglas Gilbert 
621c2248fc9SDouglas Gilbert /* 30 */
622c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
623c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
624c2248fc9SDouglas Gilbert };
625c2248fc9SDouglas Gilbert 
626773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
627773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
6289b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
629c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
630773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
631773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
632773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
633773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
634773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
635773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
636773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
637773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
638773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
639c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
640d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
641d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
642cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
643c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
644773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
645773642d9SDouglas Gilbert static int sdebug_no_uld;
646773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
647773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
648773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
649773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
650773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
65186e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
652b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
653773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
654773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
655773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
656773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
657773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
658773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
659773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
660773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
661773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
662773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
663773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
664773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
665773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
66609ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
667773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
668773642d9SDouglas Gilbert static bool sdebug_clustering;
669773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
670773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
671817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
672773642d9SDouglas Gilbert static bool sdebug_verbose;
673f46eb0e9SDouglas Gilbert static bool have_dif_prot;
6744f2c8bf6SDouglas Gilbert static bool write_since_sync;
675c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
6761da177e4SLinus Torvalds 
677c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6781da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6791da177e4SLinus Torvalds 
6801da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6811da177e4SLinus Torvalds    may still need them */
6821da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6831da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6841da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6871da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6906ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
69144d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6921da177e4SLinus Torvalds 
69344d92694SMartin K. Petersen static unsigned long map_size;
694cbf67842SDouglas Gilbert static int num_aborts;
695cbf67842SDouglas Gilbert static int num_dev_resets;
696cbf67842SDouglas Gilbert static int num_target_resets;
697cbf67842SDouglas Gilbert static int num_bus_resets;
698cbf67842SDouglas Gilbert static int num_host_resets;
699c6a44287SMartin K. Petersen static int dix_writes;
700c6a44287SMartin K. Petersen static int dix_reads;
701c6a44287SMartin K. Petersen static int dif_errors;
7021da177e4SLinus Torvalds 
703c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
704c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
705fd32119bSDouglas Gilbert 
7061da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
7071da177e4SLinus Torvalds 
708cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
709cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
7141da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
7151da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
7161da177e4SLinus Torvalds };
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds static const int check_condition_result =
7191da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
7201da177e4SLinus Torvalds 
721c6a44287SMartin K. Petersen static const int illegal_condition_result =
722c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
723c6a44287SMartin K. Petersen 
724cbf67842SDouglas Gilbert static const int device_qfull_result =
725cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
726cbf67842SDouglas Gilbert 
727fd32119bSDouglas Gilbert 
728760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
729760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
730760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
731760f3b03SDouglas Gilbert  */
732760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
733fd32119bSDouglas Gilbert {
734fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
735fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
736fd32119bSDouglas Gilbert }
737c65b1445SDouglas Gilbert 
73814faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
73914faa944SAkinobu Mita {
74014faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
74114faa944SAkinobu Mita 
742773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
74314faa944SAkinobu Mita }
74414faa944SAkinobu Mita 
7456ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
74614faa944SAkinobu Mita {
74749413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
74814faa944SAkinobu Mita 
74914faa944SAkinobu Mita 	return dif_storep + sector;
75014faa944SAkinobu Mita }
75114faa944SAkinobu Mita 
7528dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7538dea0d02SFUJITA Tomonori {
7548dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7558dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7568dea0d02SFUJITA Tomonori 
7578dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7588dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7598dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7608dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
761773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
762773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7638dea0d02SFUJITA Tomonori 		else
764773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
765773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
766f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7678dea0d02SFUJITA Tomonori 	}
7688dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7698dea0d02SFUJITA Tomonori }
7708dea0d02SFUJITA Tomonori 
77122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
77222017ed2SDouglas Gilbert 
77322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
774fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
775fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
77622017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
77722017ed2SDouglas Gilbert {
77822017ed2SDouglas Gilbert 	unsigned char *sbuff;
77922017ed2SDouglas Gilbert 	u8 sks[4];
78022017ed2SDouglas Gilbert 	int sl, asc;
78122017ed2SDouglas Gilbert 
78222017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
78322017ed2SDouglas Gilbert 	if (!sbuff) {
78422017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
78522017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
78622017ed2SDouglas Gilbert 		return;
78722017ed2SDouglas Gilbert 	}
78822017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
78922017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
790773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
79122017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
79222017ed2SDouglas Gilbert 	sks[0] = 0x80;
79322017ed2SDouglas Gilbert 	if (c_d)
79422017ed2SDouglas Gilbert 		sks[0] |= 0x40;
79522017ed2SDouglas Gilbert 	if (in_bit >= 0) {
79622017ed2SDouglas Gilbert 		sks[0] |= 0x8;
79722017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
79822017ed2SDouglas Gilbert 	}
79922017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
800773642d9SDouglas Gilbert 	if (sdebug_dsense) {
80122017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
80222017ed2SDouglas Gilbert 		sbuff[7] = sl;
80322017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
80422017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
80522017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
80622017ed2SDouglas Gilbert 	} else
80722017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
808773642d9SDouglas Gilbert 	if (sdebug_verbose)
80922017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
81022017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
81122017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
81222017ed2SDouglas Gilbert }
81322017ed2SDouglas Gilbert 
814cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
8158dea0d02SFUJITA Tomonori {
8168dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
8178dea0d02SFUJITA Tomonori 
818cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
819cbf67842SDouglas Gilbert 	if (!sbuff) {
820cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
821cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
822cbf67842SDouglas Gilbert 		return;
823cbf67842SDouglas Gilbert 	}
824cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
8258dea0d02SFUJITA Tomonori 
826773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
8278dea0d02SFUJITA Tomonori 
828773642d9SDouglas Gilbert 	if (sdebug_verbose)
829cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
830cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
831cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
8328dea0d02SFUJITA Tomonori }
8331da177e4SLinus Torvalds 
834fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
83522017ed2SDouglas Gilbert {
83622017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
83722017ed2SDouglas Gilbert }
83822017ed2SDouglas Gilbert 
8391da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
8401da177e4SLinus Torvalds {
841773642d9SDouglas Gilbert 	if (sdebug_verbose) {
842cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
843cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
844cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
845cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
846cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
847cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
848cbf67842SDouglas Gilbert 				    __func__);
849cbf67842SDouglas Gilbert 		else
850cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
851cbf67842SDouglas Gilbert 				    __func__, cmd);
8521da177e4SLinus Torvalds 	}
8531da177e4SLinus Torvalds 	return -EINVAL;
8541da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8551da177e4SLinus Torvalds }
8561da177e4SLinus Torvalds 
8579b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8589b760fd8SDouglas Gilbert {
8599b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8609b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8619b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8629b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8639b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8649b760fd8SDouglas Gilbert 		break;
8659b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8669b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8679b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8689b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8699b760fd8SDouglas Gilbert 		break;
8709b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8719b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8729b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8739b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8749b760fd8SDouglas Gilbert 		break;
8759b760fd8SDouglas Gilbert 	case 16:
8769b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8779b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8789b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8799b760fd8SDouglas Gilbert 		break;
8809b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8819b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8829b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8839b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8849b760fd8SDouglas Gilbert 		break;
8859b760fd8SDouglas Gilbert 	default:
8869b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8879b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8889b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8899b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8909b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8919b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8929b760fd8SDouglas Gilbert 		break;
8939b760fd8SDouglas Gilbert 	}
8949b760fd8SDouglas Gilbert }
8959b760fd8SDouglas Gilbert 
8969b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8979b760fd8SDouglas Gilbert {
8989b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8999b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
9009b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
9019b760fd8SDouglas Gilbert 
9029b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
9039b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9049b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
9059b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
9069b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
9079b760fd8SDouglas Gilbert 		}
9089b760fd8SDouglas Gilbert 	}
9099b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
9109b760fd8SDouglas Gilbert }
9119b760fd8SDouglas Gilbert 
91219c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
91319c8ead7SEwan D. Milne {
91419c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
91519c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
91619c8ead7SEwan D. Milne 
91719c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
91819c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
91919c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
92019c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
92119c8ead7SEwan D. Milne 			    (devip->target == dp->target))
92219c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
92319c8ead7SEwan D. Milne 		}
92419c8ead7SEwan D. Milne 	}
92519c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
92619c8ead7SEwan D. Milne }
92719c8ead7SEwan D. Milne 
928f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
9291da177e4SLinus Torvalds {
930cbf67842SDouglas Gilbert 	int k;
931cbf67842SDouglas Gilbert 
932cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
933cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
934cbf67842SDouglas Gilbert 		const char *cp = NULL;
935cbf67842SDouglas Gilbert 
936cbf67842SDouglas Gilbert 		switch (k) {
937cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
938f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
939f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
940773642d9SDouglas Gilbert 			if (sdebug_verbose)
941cbf67842SDouglas Gilbert 				cp = "power on reset";
942cbf67842SDouglas Gilbert 			break;
943cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
944f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
945f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
946773642d9SDouglas Gilbert 			if (sdebug_verbose)
947cbf67842SDouglas Gilbert 				cp = "bus reset";
948cbf67842SDouglas Gilbert 			break;
949cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
950f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
951f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
952773642d9SDouglas Gilbert 			if (sdebug_verbose)
953cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
954cbf67842SDouglas Gilbert 			break;
9550d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
956f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
957f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
958773642d9SDouglas Gilbert 			if (sdebug_verbose)
9590d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
960f49accf1SEwan D. Milne 			break;
961acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
962f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
963b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
964b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
965773642d9SDouglas Gilbert 			if (sdebug_verbose)
966acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
967acafd0b9SEwan D. Milne 			break;
968acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
969f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
970acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
971acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
972773642d9SDouglas Gilbert 			if (sdebug_verbose)
973acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
974acafd0b9SEwan D. Milne 			break;
97519c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
97619c8ead7SEwan D. Milne 			/*
97719c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
97819c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
97919c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
98019c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
981773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
98219c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
98319c8ead7SEwan D. Milne 			 */
984773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
98519c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
986f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
98719c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
98819c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
989773642d9SDouglas Gilbert 			if (sdebug_verbose)
99019c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
99119c8ead7SEwan D. Milne 			break;
992cbf67842SDouglas Gilbert 		default:
993773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
994773642d9SDouglas Gilbert 			if (sdebug_verbose)
995cbf67842SDouglas Gilbert 				cp = "unknown";
996cbf67842SDouglas Gilbert 			break;
997cbf67842SDouglas Gilbert 		}
998cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
999773642d9SDouglas Gilbert 		if (sdebug_verbose)
1000f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
1001cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1002cbf67842SDouglas Gilbert 				   my_name, cp);
10031da177e4SLinus Torvalds 		return check_condition_result;
10041da177e4SLinus Torvalds 	}
10051da177e4SLinus Torvalds 	return 0;
10061da177e4SLinus Torvalds }
10071da177e4SLinus Torvalds 
1008fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
10091da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
10101da177e4SLinus Torvalds 				int arr_len)
10111da177e4SLinus Torvalds {
101221a61829SFUJITA Tomonori 	int act_len;
1013072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
10141da177e4SLinus Torvalds 
1015072d0bb3SFUJITA Tomonori 	if (!sdb->length)
10161da177e4SLinus Torvalds 		return 0;
1017072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1018773642d9SDouglas Gilbert 		return DID_ERROR << 16;
101921a61829SFUJITA Tomonori 
102021a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
102121a61829SFUJITA Tomonori 				      arr, arr_len);
102221a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
102321a61829SFUJITA Tomonori 
10241da177e4SLinus Torvalds 	return 0;
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds 
1027fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1028fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1029fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1030fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1031fb0cc8d1SDouglas Gilbert  */
1032fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1033fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1034fb0cc8d1SDouglas Gilbert {
1035fb0cc8d1SDouglas Gilbert 	int act_len, n;
1036fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
1037fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1038fb0cc8d1SDouglas Gilbert 
1039fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1040fb0cc8d1SDouglas Gilbert 		return 0;
1041fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1042fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1043fb0cc8d1SDouglas Gilbert 
1044fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1045fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1046fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1047fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1048fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1049fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
1050fb0cc8d1SDouglas Gilbert 	return 0;
1051fb0cc8d1SDouglas Gilbert }
1052fb0cc8d1SDouglas Gilbert 
1053fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1054fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1055fb0cc8d1SDouglas Gilbert  */
10561da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
105721a61829SFUJITA Tomonori 			       int arr_len)
10581da177e4SLinus Torvalds {
105921a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10601da177e4SLinus Torvalds 		return 0;
1061072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
10621da177e4SLinus Torvalds 		return -1;
106321a61829SFUJITA Tomonori 
106421a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10651da177e4SLinus Torvalds }
10661da177e4SLinus Torvalds 
10671da177e4SLinus Torvalds 
1068e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1069e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10709b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10711b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10721b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10731b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10741b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10751da177e4SLinus Torvalds 
1076cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1077760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10785a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
107909ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1080bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10811da177e4SLinus Torvalds {
1082c65b1445SDouglas Gilbert 	int num, port_a;
1083c65b1445SDouglas Gilbert 	char b[32];
10841da177e4SLinus Torvalds 
1085c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10861da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10871da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10881da177e4SLinus Torvalds 	arr[1] = 0x1;
10891da177e4SLinus Torvalds 	arr[2] = 0x0;
1090e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1091e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10921da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10931da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10941da177e4SLinus Torvalds 	arr[3] = num;
10951da177e4SLinus Torvalds 	num += 4;
1096c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
109709ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
109809ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
109909ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
110009ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
110109ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110209ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
110309ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
110409ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110509ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
110609ba24c1SDouglas Gilbert 			num += 16;
110709ba24c1SDouglas Gilbert 		} else {
11081b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1109c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1110c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1111c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1112c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
11131b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1114773642d9SDouglas Gilbert 			num += 8;
111509ba24c1SDouglas Gilbert 		}
1116c65b1445SDouglas Gilbert 		/* Target relative port number */
1117c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1118c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1119c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1120c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1121c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1122c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1123c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1124c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1125c65b1445SDouglas Gilbert 	}
11261b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1127c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1128c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1129c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1130c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11311b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1132773642d9SDouglas Gilbert 	num += 8;
11331b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
11345a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11355a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11365a09e398SHannes Reinecke 	arr[num++] = 0x0;
11375a09e398SHannes Reinecke 	arr[num++] = 0x4;
11385a09e398SHannes Reinecke 	arr[num++] = 0;
11395a09e398SHannes Reinecke 	arr[num++] = 0;
1140773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1141773642d9SDouglas Gilbert 	num += 2;
11421b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1143c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1144c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1145c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1146c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11471b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1148773642d9SDouglas Gilbert 	num += 8;
1149c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1150c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1151c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1152c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1153c65b1445SDouglas Gilbert 	arr[num++] = 24;
11541b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1155c65b1445SDouglas Gilbert 	num += 12;
1156c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1157c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1158c65b1445SDouglas Gilbert 	num += 8;
1159c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1160c65b1445SDouglas Gilbert 	num += 4;
1161c65b1445SDouglas Gilbert 	return num;
1162c65b1445SDouglas Gilbert }
1163c65b1445SDouglas Gilbert 
1164c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1165c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1166c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1167c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1168c65b1445SDouglas Gilbert };
1169c65b1445SDouglas Gilbert 
1170cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1171760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1172c65b1445SDouglas Gilbert {
1173c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1174c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1175c65b1445SDouglas Gilbert }
1176c65b1445SDouglas Gilbert 
1177cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1178760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1179c65b1445SDouglas Gilbert {
1180c65b1445SDouglas Gilbert 	int num = 0;
1181c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1182c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1183c65b1445SDouglas Gilbert 	int plen, olen;
1184c65b1445SDouglas Gilbert 
1185c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1186c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1187c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1188c65b1445SDouglas Gilbert 	olen = strlen(na1);
1189c65b1445SDouglas Gilbert 	plen = olen + 1;
1190c65b1445SDouglas Gilbert 	if (plen % 4)
1191c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1192c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1193c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1194c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1195c65b1445SDouglas Gilbert 	num += plen;
1196c65b1445SDouglas Gilbert 
1197c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1198c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1199c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1200c65b1445SDouglas Gilbert 	olen = strlen(na2);
1201c65b1445SDouglas Gilbert 	plen = olen + 1;
1202c65b1445SDouglas Gilbert 	if (plen % 4)
1203c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1204c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1205c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1206c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1207c65b1445SDouglas Gilbert 	num += plen;
1208c65b1445SDouglas Gilbert 
1209c65b1445SDouglas Gilbert 	return num;
1210c65b1445SDouglas Gilbert }
1211c65b1445SDouglas Gilbert 
1212c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1213760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1214c65b1445SDouglas Gilbert {
1215c65b1445SDouglas Gilbert 	int num = 0;
1216c65b1445SDouglas Gilbert 	int port_a, port_b;
1217c65b1445SDouglas Gilbert 
1218c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1219c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1220c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1221c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1222c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1223c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1224c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1225c65b1445SDouglas Gilbert 	num += 6;
1226c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1227c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1228c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1229c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1230c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1231c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1232c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12331b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1234773642d9SDouglas Gilbert 	num += 8;
1235c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1236c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1237c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1238c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1239c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1240c65b1445SDouglas Gilbert 	num += 6;
1241c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1242c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1243c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1244c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1245c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1246c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1247c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12481b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1249773642d9SDouglas Gilbert 	num += 8;
1250c65b1445SDouglas Gilbert 
1251c65b1445SDouglas Gilbert 	return num;
1252c65b1445SDouglas Gilbert }
1253c65b1445SDouglas Gilbert 
1254c65b1445SDouglas Gilbert 
1255c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1256c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1257c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1258c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1259c65b1445SDouglas Gilbert '1','2','3','4',
1260c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1261c65b1445SDouglas Gilbert 0xec,0,0,0,
1262c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1263c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1264c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1265c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1266c65b1445SDouglas Gilbert 0x53,0x41,
1267c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1268c65b1445SDouglas Gilbert 0x20,0x20,
1269c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1270c65b1445SDouglas Gilbert 0x10,0x80,
1271c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1272c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1273c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1274c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1275c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1276c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1277c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1278c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1279c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1280c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1281c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1282c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1283c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1284c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1293c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1294c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1295c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1296c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1297c65b1445SDouglas Gilbert };
1298c65b1445SDouglas Gilbert 
1299cbf67842SDouglas Gilbert /* ATA Information VPD page */
1300760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1301c65b1445SDouglas Gilbert {
1302c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1303c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1304c65b1445SDouglas Gilbert }
1305c65b1445SDouglas Gilbert 
1306c65b1445SDouglas Gilbert 
1307c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
13081e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
13091e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13101e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13111e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1312c65b1445SDouglas Gilbert };
1313c65b1445SDouglas Gilbert 
1314cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1315760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1316c65b1445SDouglas Gilbert {
1317ea61fca5SMartin K. Petersen 	unsigned int gran;
1318ea61fca5SMartin K. Petersen 
1319c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1320e308b3d1SMartin K. Petersen 
1321e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
132286e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
132386e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
132486e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
132586e6828aSLukas Herbolt 	else
1326773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1327773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1328e308b3d1SMartin K. Petersen 
1329e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1330773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1331773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
133244d92694SMartin K. Petersen 
1333e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1334773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1335e308b3d1SMartin K. Petersen 
1336773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1337e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1338773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1339e308b3d1SMartin K. Petersen 
1340e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1341773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
134244d92694SMartin K. Petersen 	}
134344d92694SMartin K. Petersen 
1344e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1345773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1346773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
134744d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
134844d92694SMartin K. Petersen 	}
134944d92694SMartin K. Petersen 
1350e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1351773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13526014759cSMartin K. Petersen 
13535b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1354773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13555b94e232SMartin K. Petersen 
13565b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
135744d92694SMartin K. Petersen 
1358c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13591da177e4SLinus Torvalds }
13601da177e4SLinus Torvalds 
13611e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1362760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1363eac6e8e4SMatthew Wilcox {
1364eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1365eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13661e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13671e49f785SDouglas Gilbert 	arr[2] = 0;
13681e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1369eac6e8e4SMatthew Wilcox 
1370eac6e8e4SMatthew Wilcox 	return 0x3c;
1371eac6e8e4SMatthew Wilcox }
13721da177e4SLinus Torvalds 
1373760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1374760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13756014759cSMartin K. Petersen {
13763f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13776014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1378773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13796014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1380773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13816014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1382773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13835b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1384760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1385760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1386760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1387760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1388760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13893f0bc3b3SMartin K. Petersen 	return 0x4;
13906014759cSMartin K. Petersen }
13916014759cSMartin K. Petersen 
13921da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1393c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13941da177e4SLinus Torvalds 
1395c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13961da177e4SLinus Torvalds {
13971da177e4SLinus Torvalds 	unsigned char pq_pdt;
13985a09e398SHannes Reinecke 	unsigned char *arr;
139901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
14005a09e398SHannes Reinecke 	int alloc_len, n, ret;
1401760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
14021da177e4SLinus Torvalds 
1403773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
14046f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
14056f3cbf55SDouglas Gilbert 	if (! arr)
14066f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1407760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1408b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1409c2248fc9SDouglas Gilbert 	if (have_wlun)
1410b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1411b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1412b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1413c65b1445SDouglas Gilbert 	else
1414773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
14151da177e4SLinus Torvalds 	arr[0] = pq_pdt;
14161da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
141722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
14185a09e398SHannes Reinecke 		kfree(arr);
14191da177e4SLinus Torvalds 		return check_condition_result;
14201da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
14215a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1422c65b1445SDouglas Gilbert 		char lu_id_str[6];
1423c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
14241da177e4SLinus Torvalds 
14255a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
14265a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1427b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
142823183910SDouglas Gilbert 			host_no = 0;
1429c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1430c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1431c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1432c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1433c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
14341da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1435c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1436c65b1445SDouglas Gilbert 			n = 4;
1437c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1438c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1439c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1440c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1441c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1442c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1443c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1444c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1445760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1446c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1447760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1448760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1449760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1450760f3b03SDouglas Gilbert 			}
1451c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14521da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1453c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14541da177e4SLinus Torvalds 			arr[3] = len;
1455c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14561da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1457c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1458760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14595a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
146009ba24c1SDouglas Gilbert 						lu_id_str, len,
146109ba24c1SDouglas Gilbert 						&devip->lu_name);
1462c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1463c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1464760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1465c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1466c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1467760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1468c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1469c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1470c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14718475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1472c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1473760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1474c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1475c6a44287SMartin K. Petersen 			else
1476c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1477c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1478c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1479c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1480c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1481c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1482c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1483c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1484c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1485c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1486c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1487760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1488760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1489c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1490760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1491773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1492760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1493c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1494760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1495760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1496eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1497760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1498760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14996014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1500760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
15011da177e4SLinus Torvalds 		} else {
150222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
15035a09e398SHannes Reinecke 			kfree(arr);
15041da177e4SLinus Torvalds 			return check_condition_result;
15051da177e4SLinus Torvalds 		}
1506773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
15075a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1508c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
15095a09e398SHannes Reinecke 		kfree(arr);
15105a09e398SHannes Reinecke 		return ret;
15111da177e4SLinus Torvalds 	}
15121da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1513773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1514773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
15151da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
15161da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1517f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1518b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
151970bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1520c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
15211da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1522c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1523e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1524e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1525e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
15269b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
15279b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
15281da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1529760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1530760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1531c65b1445SDouglas Gilbert 	n = 62;
1532760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1533760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1534760f3b03SDouglas Gilbert 		n += 2;
1535760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1536760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1537760f3b03SDouglas Gilbert 		n += 2;
15381da177e4SLinus Torvalds 	}
1539760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15405a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15411da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
15425a09e398SHannes Reinecke 	kfree(arr);
15435a09e398SHannes Reinecke 	return ret;
15441da177e4SLinus Torvalds }
15451da177e4SLinus Torvalds 
1546fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1547fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1548fd32119bSDouglas Gilbert 
15491da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
15501da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
15511da177e4SLinus Torvalds {
15521da177e4SLinus Torvalds 	unsigned char *sbuff;
155301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1554cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15552492fc09STomas Winkler 	bool dsense;
15561da177e4SLinus Torvalds 	int len = 18;
15571da177e4SLinus Torvalds 
1558c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1559c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1560cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1561c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1562c2248fc9SDouglas Gilbert 		if (dsense) {
1563c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1564c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1565c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1566c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1567c2248fc9SDouglas Gilbert 			len = 8;
1568c65b1445SDouglas Gilbert 		} else {
1569c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1570c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1571c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1572c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1573c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1574c65b1445SDouglas Gilbert 		}
1575c65b1445SDouglas Gilbert 	} else {
1576cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1577773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1578c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1579c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1580c2248fc9SDouglas Gilbert 			if (dsense) {
1581c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1582c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1583c2248fc9SDouglas Gilbert 				len = 8;
1584c2248fc9SDouglas Gilbert 			} else {
1585c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1586c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1587c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1588c2248fc9SDouglas Gilbert 			}
1589c2248fc9SDouglas Gilbert 		} else if (dsense) {
1590c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15911da177e4SLinus Torvalds 			arr[0] = 0x72;
15921da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15931da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15941da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15951da177e4SLinus Torvalds 			len = 8;
1596c2248fc9SDouglas Gilbert 		} else {
1597c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1598c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1599c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1600c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1601c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1602c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1603c65b1445SDouglas Gilbert 		}
1604c2248fc9SDouglas Gilbert 
1605c65b1445SDouglas Gilbert 	}
1606cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
16071da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
16081da177e4SLinus Torvalds }
16091da177e4SLinus Torvalds 
1610c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1611c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1612c65b1445SDouglas Gilbert {
161301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1614c4837394SDouglas Gilbert 	int power_cond, stop;
16154f2c8bf6SDouglas Gilbert 	bool changing;
1616c65b1445SDouglas Gilbert 
1617c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1618c65b1445SDouglas Gilbert 	if (power_cond) {
161922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1620c65b1445SDouglas Gilbert 		return check_condition_result;
1621c65b1445SDouglas Gilbert 	}
1622c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
16234f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1624c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
16254f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
16264f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
16274f2c8bf6SDouglas Gilbert 	else
16284f2c8bf6SDouglas Gilbert 		return 0;
1629c65b1445SDouglas Gilbert }
1630c65b1445SDouglas Gilbert 
163128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
163228898873SFUJITA Tomonori {
1633773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1634773642d9SDouglas Gilbert 
1635773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1636773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1637773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
163828898873SFUJITA Tomonori 	else
163928898873SFUJITA Tomonori 		return sdebug_store_sectors;
164028898873SFUJITA Tomonori }
164128898873SFUJITA Tomonori 
16421da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16431da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
16441da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
16451da177e4SLinus Torvalds {
16461da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1647c65b1445SDouglas Gilbert 	unsigned int capac;
16481da177e4SLinus Torvalds 
1649c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
165028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
16511da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1652c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1653c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1654773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1655773642d9SDouglas Gilbert 	} else
1656773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1657773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16581da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16591da177e4SLinus Torvalds }
16601da177e4SLinus Torvalds 
1661c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1662c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1663c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1664c65b1445SDouglas Gilbert {
166501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1666c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1667773642d9SDouglas Gilbert 	int alloc_len;
1668c65b1445SDouglas Gilbert 
1669773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1670c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
167128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1672c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1673773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1674773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1675773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1676773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
167744d92694SMartin K. Petersen 
1678be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16795b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1680760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1681760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1682760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1683760f3b03SDouglas Gilbert 		 */
1684760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1685760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1686be1dd78dSEric Sandeen 	}
168744d92694SMartin K. Petersen 
1688773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1689c6a44287SMartin K. Petersen 
1690760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1691773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1692c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1693c6a44287SMartin K. Petersen 	}
1694c6a44287SMartin K. Petersen 
1695c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1696c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1697c65b1445SDouglas Gilbert }
1698c65b1445SDouglas Gilbert 
16995a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
17005a09e398SHannes Reinecke 
17015a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
17025a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
17035a09e398SHannes Reinecke {
170401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
17055a09e398SHannes Reinecke 	unsigned char *arr;
17065a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
17075a09e398SHannes Reinecke 	int n, ret, alen, rlen;
17085a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
17095a09e398SHannes Reinecke 
1710773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
17116f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
17126f3cbf55SDouglas Gilbert 	if (! arr)
17136f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
17145a09e398SHannes Reinecke 	/*
17155a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
17165a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
17175a09e398SHannes Reinecke 	 * So we create two port groups with one port each
17185a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
17195a09e398SHannes Reinecke 	 */
17205a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
17215a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
17225a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
17235a09e398SHannes Reinecke 			(devip->channel & 0x7f);
17245a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
17255a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
17265a09e398SHannes Reinecke 
17275a09e398SHannes Reinecke 	/*
17285a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
17295a09e398SHannes Reinecke 	 */
17305a09e398SHannes Reinecke 	n = 4;
1731b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
17325a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
17335a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
17345a09e398SHannes Reinecke 	} else {
17355a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1736773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
17375a09e398SHannes Reinecke 	}
1738773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1739773642d9SDouglas Gilbert 	n += 2;
17405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17415a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17435a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17455a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1746773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1747773642d9SDouglas Gilbert 	n += 2;
17485a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
17495a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1750773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1751773642d9SDouglas Gilbert 	n += 2;
17525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17535a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17545a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17555a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17565a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17575a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1758773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1759773642d9SDouglas Gilbert 	n += 2;
17605a09e398SHannes Reinecke 
17615a09e398SHannes Reinecke 	rlen = n - 4;
1762773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17635a09e398SHannes Reinecke 
17645a09e398SHannes Reinecke 	/*
17655a09e398SHannes Reinecke 	 * Return the smallest value of either
17665a09e398SHannes Reinecke 	 * - The allocated length
17675a09e398SHannes Reinecke 	 * - The constructed command length
17685a09e398SHannes Reinecke 	 * - The maximum array size
17695a09e398SHannes Reinecke 	 */
17705a09e398SHannes Reinecke 	rlen = min(alen,n);
17715a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17725a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17735a09e398SHannes Reinecke 	kfree(arr);
17745a09e398SHannes Reinecke 	return ret;
17755a09e398SHannes Reinecke }
17765a09e398SHannes Reinecke 
1777fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1778fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
177938d5c833SDouglas Gilbert {
178038d5c833SDouglas Gilbert 	bool rctd;
178138d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
178238d5c833SDouglas Gilbert 	u16 req_sa, u;
178338d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
178438d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
178538d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
178638d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
178738d5c833SDouglas Gilbert 	u8 *arr;
178838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
178938d5c833SDouglas Gilbert 
179038d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
179138d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
179238d5c833SDouglas Gilbert 	req_opcode = cmd[3];
179338d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
179438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17956d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
179638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
179738d5c833SDouglas Gilbert 		return check_condition_result;
179838d5c833SDouglas Gilbert 	}
179938d5c833SDouglas Gilbert 	if (alloc_len > 8192)
180038d5c833SDouglas Gilbert 		a_len = 8192;
180138d5c833SDouglas Gilbert 	else
180238d5c833SDouglas Gilbert 		a_len = alloc_len;
180399531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
180438d5c833SDouglas Gilbert 	if (NULL == arr) {
180538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
180638d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
180738d5c833SDouglas Gilbert 		return check_condition_result;
180838d5c833SDouglas Gilbert 	}
180938d5c833SDouglas Gilbert 	switch (reporting_opts) {
181038d5c833SDouglas Gilbert 	case 0:	/* all commands */
181138d5c833SDouglas Gilbert 		/* count number of commands */
181238d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
181338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
181438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181538d5c833SDouglas Gilbert 				continue;
181638d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
181738d5c833SDouglas Gilbert 		}
181838d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
181938d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
182038d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
182138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
182238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
182338d5c833SDouglas Gilbert 				continue;
182438d5c833SDouglas Gilbert 			na = oip->num_attached;
182538d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
182638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
182738d5c833SDouglas Gilbert 			if (rctd)
182838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
182938d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
183038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
183138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
183238d5c833SDouglas Gilbert 			if (rctd)
183338d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
183438d5c833SDouglas Gilbert 			r_oip = oip;
183538d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
183638d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
183738d5c833SDouglas Gilbert 					continue;
183838d5c833SDouglas Gilbert 				offset += bump;
183938d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
184038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
184138d5c833SDouglas Gilbert 				if (rctd)
184238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
184338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
184438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
184538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
184638d5c833SDouglas Gilbert 						   arr + offset + 6);
184738d5c833SDouglas Gilbert 				if (rctd)
184838d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
184938d5c833SDouglas Gilbert 							   arr + offset + 8);
185038d5c833SDouglas Gilbert 			}
185138d5c833SDouglas Gilbert 			oip = r_oip;
185238d5c833SDouglas Gilbert 			offset += bump;
185338d5c833SDouglas Gilbert 		}
185438d5c833SDouglas Gilbert 		break;
185538d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
185638d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
185738d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
185838d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
185938d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
186038d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
186138d5c833SDouglas Gilbert 			supp = 1;
186238d5c833SDouglas Gilbert 			offset = 4;
186338d5c833SDouglas Gilbert 		} else {
186438d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
186538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
186638d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
186738d5c833SDouglas Gilbert 							     2, 2);
186838d5c833SDouglas Gilbert 					kfree(arr);
186938d5c833SDouglas Gilbert 					return check_condition_result;
187038d5c833SDouglas Gilbert 				}
187138d5c833SDouglas Gilbert 				req_sa = 0;
187238d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
187338d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
187438d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
187538d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
187638d5c833SDouglas Gilbert 				return check_condition_result;
187738d5c833SDouglas Gilbert 			}
187838d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
187938d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
188038d5c833SDouglas Gilbert 				supp = 3;
188138d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
188238d5c833SDouglas Gilbert 				na = oip->num_attached;
188338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
188438d5c833SDouglas Gilbert 				     ++k, ++oip) {
188538d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
188638d5c833SDouglas Gilbert 						break;
188738d5c833SDouglas Gilbert 				}
188838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
188938d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
189038d5c833SDouglas Gilbert 				na = oip->num_attached;
189138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
189238d5c833SDouglas Gilbert 				     ++k, ++oip) {
189338d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
189438d5c833SDouglas Gilbert 						break;
189538d5c833SDouglas Gilbert 				}
189638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
189738d5c833SDouglas Gilbert 			} else
189838d5c833SDouglas Gilbert 				supp = 3;
189938d5c833SDouglas Gilbert 			if (3 == supp) {
190038d5c833SDouglas Gilbert 				u = oip->len_mask[0];
190138d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
190238d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
190338d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
190438d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
190538d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
190638d5c833SDouglas Gilbert 				offset = 4 + u;
190738d5c833SDouglas Gilbert 			} else
190838d5c833SDouglas Gilbert 				offset = 4;
190938d5c833SDouglas Gilbert 		}
191038d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
191138d5c833SDouglas Gilbert 		if (rctd) {
191238d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
191338d5c833SDouglas Gilbert 			offset += 12;
191438d5c833SDouglas Gilbert 		}
191538d5c833SDouglas Gilbert 		break;
191638d5c833SDouglas Gilbert 	default:
191738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
191838d5c833SDouglas Gilbert 		kfree(arr);
191938d5c833SDouglas Gilbert 		return check_condition_result;
192038d5c833SDouglas Gilbert 	}
192138d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
192238d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
192338d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
192438d5c833SDouglas Gilbert 	kfree(arr);
192538d5c833SDouglas Gilbert 	return errsts;
192638d5c833SDouglas Gilbert }
192738d5c833SDouglas Gilbert 
1928fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1929fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
193038d5c833SDouglas Gilbert {
193138d5c833SDouglas Gilbert 	bool repd;
193238d5c833SDouglas Gilbert 	u32 alloc_len, len;
193338d5c833SDouglas Gilbert 	u8 arr[16];
193438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
193538d5c833SDouglas Gilbert 
193638d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
193738d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
193838d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
193938d5c833SDouglas Gilbert 	if (alloc_len < 4) {
194038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
194138d5c833SDouglas Gilbert 		return check_condition_result;
194238d5c833SDouglas Gilbert 	}
194338d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
194438d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
194538d5c833SDouglas Gilbert 	if (repd) {
194638d5c833SDouglas Gilbert 		arr[3] = 0xc;
194738d5c833SDouglas Gilbert 		len = 16;
194838d5c833SDouglas Gilbert 	} else
194938d5c833SDouglas Gilbert 		len = 4;
195038d5c833SDouglas Gilbert 
195138d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
195238d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
195338d5c833SDouglas Gilbert }
195438d5c833SDouglas Gilbert 
19551da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
19581da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19591da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19601da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19631da177e4SLinus Torvalds 	if (1 == pcontrol)
19641da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19651da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19661da177e4SLinus Torvalds }
19671da177e4SLinus Torvalds 
19681da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
19691da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19701da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19711da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19721da177e4SLinus Torvalds 
19731da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19741da177e4SLinus Torvalds 	if (1 == pcontrol)
19751da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19761da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19771da177e4SLinus Torvalds }
19781da177e4SLinus Torvalds 
19791da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
19801da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19811da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19821da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19831da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19841da177e4SLinus Torvalds 
19851da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1986773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1987773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1988773642d9SDouglas Gilbert 	if (sdebug_removable)
19891da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19901da177e4SLinus Torvalds 	if (1 == pcontrol)
19911da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19921da177e4SLinus Torvalds 	return sizeof(format_pg);
19931da177e4SLinus Torvalds }
19941da177e4SLinus Torvalds 
1995fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1996fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1997fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1998fd32119bSDouglas Gilbert 
19991da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
20001da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
2001cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2002cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2003cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
20041da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
20051da177e4SLinus Torvalds 
2006773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2007cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
20081da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
20091da177e4SLinus Torvalds 	if (1 == pcontrol)
2010cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2011cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2012cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
20131da177e4SLinus Torvalds 	return sizeof(caching_pg);
20141da177e4SLinus Torvalds }
20151da177e4SLinus Torvalds 
2016fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2017fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2018fd32119bSDouglas Gilbert 
20191da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
20201da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2021c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2022c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2023c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
20241da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
20251da177e4SLinus Torvalds 
2026773642d9SDouglas Gilbert 	if (sdebug_dsense)
20271da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2028c65b1445SDouglas Gilbert 	else
2029c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2030c6a44287SMartin K. Petersen 
2031773642d9SDouglas Gilbert 	if (sdebug_ato)
2032c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2033c6a44287SMartin K. Petersen 
20341da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
20351da177e4SLinus Torvalds 	if (1 == pcontrol)
2036c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2037c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2038c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
20391da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20401da177e4SLinus Torvalds }
20411da177e4SLinus Torvalds 
2042c65b1445SDouglas Gilbert 
20431da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
20441da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2045c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
20461da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2047c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2048c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2049c65b1445SDouglas Gilbert 
20501da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
20511da177e4SLinus Torvalds 	if (1 == pcontrol)
2052c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2053c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2054c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
20551da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
20561da177e4SLinus Torvalds }
20571da177e4SLinus Torvalds 
2058c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2059c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2060c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2061c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2062c65b1445SDouglas Gilbert 
2063c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2064c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2065c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2066c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2067c65b1445SDouglas Gilbert }
2068c65b1445SDouglas Gilbert 
2069c65b1445SDouglas Gilbert 
2070c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2071c65b1445SDouglas Gilbert 			      int target_dev_id)
2072c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2073c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2074c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2075773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2076773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2077c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2078c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2079c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2080c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2081773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2082773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2083c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2084c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2085c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2086c65b1445SDouglas Gilbert 		};
2087c65b1445SDouglas Gilbert 	int port_a, port_b;
2088c65b1445SDouglas Gilbert 
20891b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20911b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20921b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2093c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2094c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2095c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2096773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2097773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2098c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2099c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2100c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2101c65b1445SDouglas Gilbert }
2102c65b1445SDouglas Gilbert 
2103c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2104c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2105c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2106c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2107c65b1445SDouglas Gilbert 		};
2108c65b1445SDouglas Gilbert 
2109c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2110c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2111c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2112c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2113c65b1445SDouglas Gilbert }
2114c65b1445SDouglas Gilbert 
21151da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
21161da177e4SLinus Torvalds 
2117fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2118fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
21191da177e4SLinus Torvalds {
212023183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
21211da177e4SLinus Torvalds 	unsigned char dev_spec;
2122760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2123c2248fc9SDouglas Gilbert 	int target = scp->device->id;
21241da177e4SLinus Torvalds 	unsigned char *ap;
21251da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
212601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2127760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
21281da177e4SLinus Torvalds 
2129760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
21301da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
21311da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
21321da177e4SLinus Torvalds 	subpcode = cmd[3];
21331da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2134760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2135760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2136760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
213723183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
213823183910SDouglas Gilbert 	else
213923183910SDouglas Gilbert 		bd_len = 0;
2140773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21411da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21421da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2143cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
21441da177e4SLinus Torvalds 		return check_condition_result;
21451da177e4SLinus Torvalds 	}
2146c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2147c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2148b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2149760f3b03SDouglas Gilbert 	if (is_disk)
2150b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
215123183910SDouglas Gilbert 	else
215223183910SDouglas Gilbert 		dev_spec = 0x0;
21531da177e4SLinus Torvalds 	if (msense_6) {
21541da177e4SLinus Torvalds 		arr[2] = dev_spec;
215523183910SDouglas Gilbert 		arr[3] = bd_len;
21561da177e4SLinus Torvalds 		offset = 4;
21571da177e4SLinus Torvalds 	} else {
21581da177e4SLinus Torvalds 		arr[3] = dev_spec;
215923183910SDouglas Gilbert 		if (16 == bd_len)
216023183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
216123183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21621da177e4SLinus Torvalds 		offset = 8;
21631da177e4SLinus Torvalds 	}
21641da177e4SLinus Torvalds 	ap = arr + offset;
216528898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
216628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
216728898873SFUJITA Tomonori 
216823183910SDouglas Gilbert 	if (8 == bd_len) {
2169773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2170773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2171773642d9SDouglas Gilbert 		else
2172773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2173773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
217423183910SDouglas Gilbert 		offset += bd_len;
217523183910SDouglas Gilbert 		ap = arr + offset;
217623183910SDouglas Gilbert 	} else if (16 == bd_len) {
2177773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2178773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
217923183910SDouglas Gilbert 		offset += bd_len;
218023183910SDouglas Gilbert 		ap = arr + offset;
218123183910SDouglas Gilbert 	}
21821da177e4SLinus Torvalds 
2183c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2184c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
218522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21861da177e4SLinus Torvalds 		return check_condition_result;
21871da177e4SLinus Torvalds 	}
2188760f3b03SDouglas Gilbert 	bad_pcode = false;
2189760f3b03SDouglas Gilbert 
21901da177e4SLinus Torvalds 	switch (pcode) {
21911da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21921da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21931da177e4SLinus Torvalds 		offset += len;
21941da177e4SLinus Torvalds 		break;
21951da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21961da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21971da177e4SLinus Torvalds 		offset += len;
21981da177e4SLinus Torvalds 		break;
21991da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2200760f3b03SDouglas Gilbert 		if (is_disk) {
22011da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
22021da177e4SLinus Torvalds 			offset += len;
2203760f3b03SDouglas Gilbert 		} else
2204760f3b03SDouglas Gilbert 			bad_pcode = true;
22051da177e4SLinus Torvalds 		break;
22061da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2207760f3b03SDouglas Gilbert 		if (is_disk) {
22081da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
22091da177e4SLinus Torvalds 			offset += len;
2210760f3b03SDouglas Gilbert 		} else
2211760f3b03SDouglas Gilbert 			bad_pcode = true;
22121da177e4SLinus Torvalds 		break;
22131da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
22141da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
22151da177e4SLinus Torvalds 		offset += len;
22161da177e4SLinus Torvalds 		break;
2217c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2218c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
221922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2220c65b1445SDouglas Gilbert 			return check_condition_result;
2221c65b1445SDouglas Gilbert 		}
2222c65b1445SDouglas Gilbert 		len = 0;
2223c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2224c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2225c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2226c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2227c65b1445SDouglas Gilbert 						  target_dev_id);
2228c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2229c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2230c65b1445SDouglas Gilbert 		offset += len;
2231c65b1445SDouglas Gilbert 		break;
22321da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
22331da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
22341da177e4SLinus Torvalds 		offset += len;
22351da177e4SLinus Torvalds 		break;
22361da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2237c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
22381da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
22391da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2240760f3b03SDouglas Gilbert 			if (is_disk) {
2241760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2242760f3b03SDouglas Gilbert 						      target);
2243760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2244760f3b03SDouglas Gilbert 						       target);
2245760f3b03SDouglas Gilbert 			}
22461da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2247c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2248c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2249c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2250c65b1445SDouglas Gilbert 						  target, target_dev_id);
2251c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2252c65b1445SDouglas Gilbert 			}
22531da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2254760f3b03SDouglas Gilbert 			offset += len;
2255c65b1445SDouglas Gilbert 		} else {
225622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2257c65b1445SDouglas Gilbert 			return check_condition_result;
2258c65b1445SDouglas Gilbert 		}
22591da177e4SLinus Torvalds 		break;
22601da177e4SLinus Torvalds 	default:
2261760f3b03SDouglas Gilbert 		bad_pcode = true;
2262760f3b03SDouglas Gilbert 		break;
2263760f3b03SDouglas Gilbert 	}
2264760f3b03SDouglas Gilbert 	if (bad_pcode) {
226522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22661da177e4SLinus Torvalds 		return check_condition_result;
22671da177e4SLinus Torvalds 	}
22681da177e4SLinus Torvalds 	if (msense_6)
22691da177e4SLinus Torvalds 		arr[0] = offset - 1;
2270773642d9SDouglas Gilbert 	else
2271773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22721da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22731da177e4SLinus Torvalds }
22741da177e4SLinus Torvalds 
2275c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2276c65b1445SDouglas Gilbert 
2277fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2278fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2279c65b1445SDouglas Gilbert {
2280c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2281c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2282c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
228301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2284c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2285c65b1445SDouglas Gilbert 
2286c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2287c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2288c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2289773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2290c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
229122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2292c65b1445SDouglas Gilbert 		return check_condition_result;
2293c65b1445SDouglas Gilbert 	}
2294c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2295c65b1445SDouglas Gilbert 	if (-1 == res)
2296773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2297773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2298cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2299cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2300cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2301773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2302773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
230323183910SDouglas Gilbert 	if (md_len > 2) {
230422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2305c65b1445SDouglas Gilbert 		return check_condition_result;
2306c65b1445SDouglas Gilbert 	}
2307c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2308c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2309c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2310c65b1445SDouglas Gilbert 	if (ps) {
231122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2312c65b1445SDouglas Gilbert 		return check_condition_result;
2313c65b1445SDouglas Gilbert 	}
2314c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2315773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2316c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2317c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2318cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2319c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2320c65b1445SDouglas Gilbert 		return check_condition_result;
2321c65b1445SDouglas Gilbert 	}
2322c65b1445SDouglas Gilbert 	switch (mpage) {
2323cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2324cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2325cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2326cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2327cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2328cbf67842SDouglas Gilbert 		}
2329cbf67842SDouglas Gilbert 		break;
2330c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2331c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2332c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2333c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2334773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2335cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2336c65b1445SDouglas Gilbert 		}
2337c65b1445SDouglas Gilbert 		break;
2338c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2339c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2340c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2341c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2342cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2343c65b1445SDouglas Gilbert 		}
2344c65b1445SDouglas Gilbert 		break;
2345c65b1445SDouglas Gilbert 	default:
2346c65b1445SDouglas Gilbert 		break;
2347c65b1445SDouglas Gilbert 	}
234822017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2349c65b1445SDouglas Gilbert 	return check_condition_result;
2350cbf67842SDouglas Gilbert set_mode_changed_ua:
2351cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2352cbf67842SDouglas Gilbert 	return 0;
2353c65b1445SDouglas Gilbert }
2354c65b1445SDouglas Gilbert 
2355c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2356c65b1445SDouglas Gilbert {
2357c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2358c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2359c65b1445SDouglas Gilbert 		};
2360c65b1445SDouglas Gilbert 
2361c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2362c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2363c65b1445SDouglas Gilbert }
2364c65b1445SDouglas Gilbert 
2365c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2366c65b1445SDouglas Gilbert {
2367c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2368c65b1445SDouglas Gilbert 		};
2369c65b1445SDouglas Gilbert 
2370c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2371c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2372c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2373c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2374c65b1445SDouglas Gilbert 	}
2375c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2376c65b1445SDouglas Gilbert }
2377c65b1445SDouglas Gilbert 
2378c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2379c65b1445SDouglas Gilbert 
2380c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2381c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2382c65b1445SDouglas Gilbert {
2383ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2384c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
238501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2386c65b1445SDouglas Gilbert 
2387c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2388c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2389c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2390c65b1445SDouglas Gilbert 	if (ppc || sp) {
239122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2392c65b1445SDouglas Gilbert 		return check_condition_result;
2393c65b1445SDouglas Gilbert 	}
2394c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
239523183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2396773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2397c65b1445SDouglas Gilbert 	arr[0] = pcode;
239823183910SDouglas Gilbert 	if (0 == subpcode) {
2399c65b1445SDouglas Gilbert 		switch (pcode) {
2400c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2401c65b1445SDouglas Gilbert 			n = 4;
2402c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2403c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2404c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2405c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2406c65b1445SDouglas Gilbert 			break;
2407c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2408c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2409c65b1445SDouglas Gilbert 			break;
2410c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2411c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2412c65b1445SDouglas Gilbert 			break;
2413c65b1445SDouglas Gilbert 		default:
241422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2415c65b1445SDouglas Gilbert 			return check_condition_result;
2416c65b1445SDouglas Gilbert 		}
241723183910SDouglas Gilbert 	} else if (0xff == subpcode) {
241823183910SDouglas Gilbert 		arr[0] |= 0x40;
241923183910SDouglas Gilbert 		arr[1] = subpcode;
242023183910SDouglas Gilbert 		switch (pcode) {
242123183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
242223183910SDouglas Gilbert 			n = 4;
242323183910SDouglas Gilbert 			arr[n++] = 0x0;
242423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
242523183910SDouglas Gilbert 			arr[n++] = 0x0;
242623183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
242723183910SDouglas Gilbert 			arr[n++] = 0xd;
242823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
242923183910SDouglas Gilbert 			arr[n++] = 0x2f;
243023183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
243123183910SDouglas Gilbert 			arr[3] = n - 4;
243223183910SDouglas Gilbert 			break;
243323183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
243423183910SDouglas Gilbert 			n = 4;
243523183910SDouglas Gilbert 			arr[n++] = 0xd;
243623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
243723183910SDouglas Gilbert 			arr[3] = n - 4;
243823183910SDouglas Gilbert 			break;
243923183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
244023183910SDouglas Gilbert 			n = 4;
244123183910SDouglas Gilbert 			arr[n++] = 0x2f;
244223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
244323183910SDouglas Gilbert 			arr[3] = n - 4;
244423183910SDouglas Gilbert 			break;
244523183910SDouglas Gilbert 		default:
244622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
244723183910SDouglas Gilbert 			return check_condition_result;
244823183910SDouglas Gilbert 		}
244923183910SDouglas Gilbert 	} else {
245022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
245123183910SDouglas Gilbert 		return check_condition_result;
245223183910SDouglas Gilbert 	}
2453773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2454c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2455c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2456c65b1445SDouglas Gilbert }
2457c65b1445SDouglas Gilbert 
2458cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
245919789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
24601da177e4SLinus Torvalds {
2461c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
246222017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24631da177e4SLinus Torvalds 		return check_condition_result;
24641da177e4SLinus Torvalds 	}
2465c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2466c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
246722017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2468cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2469c65b1445SDouglas Gilbert 		return check_condition_result;
2470c65b1445SDouglas Gilbert 	}
247119789100SFUJITA Tomonori 	return 0;
247219789100SFUJITA Tomonori }
247319789100SFUJITA Tomonori 
2474a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
24750a7e69c7SDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
24760a7e69c7SDouglas Gilbert 			    u32 num, bool do_write)
247719789100SFUJITA Tomonori {
247819789100SFUJITA Tomonori 	int ret;
2479c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2480a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2481a4517511SAkinobu Mita 	enum dma_data_direction dir;
248219789100SFUJITA Tomonori 
2483c2248fc9SDouglas Gilbert 	if (do_write) {
2484a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2485a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
24864f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2487a4517511SAkinobu Mita 	} else {
2488a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2489a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2490a4517511SAkinobu Mita 	}
2491a4517511SAkinobu Mita 
2492a4517511SAkinobu Mita 	if (!sdb->length)
2493a4517511SAkinobu Mita 		return 0;
2494a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2495a4517511SAkinobu Mita 		return -1;
249619789100SFUJITA Tomonori 
249719789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
249819789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
249919789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
250019789100SFUJITA Tomonori 
2501386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2502773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
25030a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2504773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2505a4517511SAkinobu Mita 		return ret;
2506a4517511SAkinobu Mita 
2507a4517511SAkinobu Mita 	if (rest) {
2508386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2509773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
25100a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
25110a7e69c7SDouglas Gilbert 			    do_write);
2512a4517511SAkinobu Mita 	}
251319789100SFUJITA Tomonori 
251419789100SFUJITA Tomonori 	return ret;
251519789100SFUJITA Tomonori }
251619789100SFUJITA Tomonori 
251738d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
251838d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
251938d5c833SDouglas Gilbert  * return false. */
2520fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
252138d5c833SDouglas Gilbert {
252238d5c833SDouglas Gilbert 	bool res;
252338d5c833SDouglas Gilbert 	u64 block, rest = 0;
252438d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2525773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
252638d5c833SDouglas Gilbert 
252738d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
252838d5c833SDouglas Gilbert 	if (block + num > store_blks)
252938d5c833SDouglas Gilbert 		rest = block + num - store_blks;
253038d5c833SDouglas Gilbert 
253138d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
253238d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
253338d5c833SDouglas Gilbert 	if (!res)
253438d5c833SDouglas Gilbert 		return res;
253538d5c833SDouglas Gilbert 	if (rest)
253638d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
253738d5c833SDouglas Gilbert 			     rest * lb_size);
253838d5c833SDouglas Gilbert 	if (!res)
253938d5c833SDouglas Gilbert 		return res;
254038d5c833SDouglas Gilbert 	arr += num * lb_size;
254138d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
254238d5c833SDouglas Gilbert 	if (rest)
254338d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
254438d5c833SDouglas Gilbert 		       rest * lb_size);
254538d5c833SDouglas Gilbert 	return res;
254638d5c833SDouglas Gilbert }
254738d5c833SDouglas Gilbert 
254851d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2549beb40ea4SAkinobu Mita {
255051d648afSAkinobu Mita 	__be16 csum;
2551beb40ea4SAkinobu Mita 
2552773642d9SDouglas Gilbert 	if (sdebug_guard)
255351d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
255451d648afSAkinobu Mita 	else
2555beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
255651d648afSAkinobu Mita 
2557beb40ea4SAkinobu Mita 	return csum;
2558beb40ea4SAkinobu Mita }
2559beb40ea4SAkinobu Mita 
25606ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2561beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2562beb40ea4SAkinobu Mita {
2563773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2564beb40ea4SAkinobu Mita 
2565beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2566c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2567beb40ea4SAkinobu Mita 			(unsigned long)sector,
2568beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2569beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2570beb40ea4SAkinobu Mita 		return 0x01;
2571beb40ea4SAkinobu Mita 	}
25728475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2573beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2574c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2575c1287970STomas Winkler 			(unsigned long)sector);
2576beb40ea4SAkinobu Mita 		return 0x03;
2577beb40ea4SAkinobu Mita 	}
25788475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2579beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2580c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2581c1287970STomas Winkler 			(unsigned long)sector);
2582beb40ea4SAkinobu Mita 		return 0x03;
2583beb40ea4SAkinobu Mita 	}
2584beb40ea4SAkinobu Mita 	return 0;
2585beb40ea4SAkinobu Mita }
2586beb40ea4SAkinobu Mita 
2587bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
258865f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2589c6a44287SMartin K. Petersen {
2590be4e11beSAkinobu Mita 	size_t resid;
2591c6a44287SMartin K. Petersen 	void *paddr;
259214faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2593be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2594c6a44287SMartin K. Petersen 
2595e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2596e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2597c6a44287SMartin K. Petersen 
2598be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2599be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2600be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2601be4e11beSAkinobu Mita 
2602be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2603be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
260414faa944SAkinobu Mita 		void *start = dif_store(sector);
2605be4e11beSAkinobu Mita 		size_t rest = 0;
260614faa944SAkinobu Mita 
260714faa944SAkinobu Mita 		if (dif_store_end < start + len)
260814faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2609c6a44287SMartin K. Petersen 
2610be4e11beSAkinobu Mita 		paddr = miter.addr;
261114faa944SAkinobu Mita 
261265f72f2aSAkinobu Mita 		if (read)
261365f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
261465f72f2aSAkinobu Mita 		else
261565f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
261665f72f2aSAkinobu Mita 
261765f72f2aSAkinobu Mita 		if (rest) {
261865f72f2aSAkinobu Mita 			if (read)
261914faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
262065f72f2aSAkinobu Mita 			else
262165f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
262265f72f2aSAkinobu Mita 		}
2623c6a44287SMartin K. Petersen 
2624e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2625c6a44287SMartin K. Petersen 		resid -= len;
2626c6a44287SMartin K. Petersen 	}
2627be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2628bb8c063cSAkinobu Mita }
2629c6a44287SMartin K. Petersen 
2630bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2631bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2632bb8c063cSAkinobu Mita {
2633bb8c063cSAkinobu Mita 	unsigned int i;
26346ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2635bb8c063cSAkinobu Mita 	sector_t sector;
2636bb8c063cSAkinobu Mita 
2637c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2638bb8c063cSAkinobu Mita 		int ret;
2639bb8c063cSAkinobu Mita 
2640bb8c063cSAkinobu Mita 		sector = start_sec + i;
2641bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2642bb8c063cSAkinobu Mita 
264351d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2644bb8c063cSAkinobu Mita 			continue;
2645bb8c063cSAkinobu Mita 
2646bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2647bb8c063cSAkinobu Mita 		if (ret) {
2648bb8c063cSAkinobu Mita 			dif_errors++;
2649bb8c063cSAkinobu Mita 			return ret;
2650bb8c063cSAkinobu Mita 		}
2651bb8c063cSAkinobu Mita 	}
2652bb8c063cSAkinobu Mita 
265365f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2654c6a44287SMartin K. Petersen 	dix_reads++;
2655c6a44287SMartin K. Petersen 
2656c6a44287SMartin K. Petersen 	return 0;
2657c6a44287SMartin K. Petersen }
2658c6a44287SMartin K. Petersen 
2659fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
266019789100SFUJITA Tomonori {
2661c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2662c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2663c2248fc9SDouglas Gilbert 	u64 lba;
2664c2248fc9SDouglas Gilbert 	u32 num;
2665c2248fc9SDouglas Gilbert 	u32 ei_lba;
266619789100SFUJITA Tomonori 	unsigned long iflags;
266719789100SFUJITA Tomonori 	int ret;
2668c2248fc9SDouglas Gilbert 	bool check_prot;
266919789100SFUJITA Tomonori 
2670c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2671c2248fc9SDouglas Gilbert 	case READ_16:
2672c2248fc9SDouglas Gilbert 		ei_lba = 0;
2673c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2674c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2675c2248fc9SDouglas Gilbert 		check_prot = true;
2676c2248fc9SDouglas Gilbert 		break;
2677c2248fc9SDouglas Gilbert 	case READ_10:
2678c2248fc9SDouglas Gilbert 		ei_lba = 0;
2679c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2680c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2681c2248fc9SDouglas Gilbert 		check_prot = true;
2682c2248fc9SDouglas Gilbert 		break;
2683c2248fc9SDouglas Gilbert 	case READ_6:
2684c2248fc9SDouglas Gilbert 		ei_lba = 0;
2685c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2686c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2687c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2688c2248fc9SDouglas Gilbert 		check_prot = true;
2689c2248fc9SDouglas Gilbert 		break;
2690c2248fc9SDouglas Gilbert 	case READ_12:
2691c2248fc9SDouglas Gilbert 		ei_lba = 0;
2692c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2693c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2694c2248fc9SDouglas Gilbert 		check_prot = true;
2695c2248fc9SDouglas Gilbert 		break;
2696c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2697c2248fc9SDouglas Gilbert 		ei_lba = 0;
2698c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2699c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2700c2248fc9SDouglas Gilbert 		check_prot = false;
2701c2248fc9SDouglas Gilbert 		break;
2702c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2703c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2704c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2705c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2706c2248fc9SDouglas Gilbert 		check_prot = false;
2707c2248fc9SDouglas Gilbert 		break;
2708c2248fc9SDouglas Gilbert 	}
2709f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
27108475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2711c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2712c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2713c2248fc9SDouglas Gilbert 			return check_condition_result;
2714c2248fc9SDouglas Gilbert 		}
27158475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
27168475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2717c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2718c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2719c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2720c2248fc9SDouglas Gilbert 	}
2721f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2722c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2723c2248fc9SDouglas Gilbert 
2724c4837394SDouglas Gilbert 		if (sqcp) {
2725c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2726c2248fc9SDouglas Gilbert 				num /= 2;
2727c2248fc9SDouglas Gilbert 		}
2728c4837394SDouglas Gilbert 	} else
2729c4837394SDouglas Gilbert 		sqcp = NULL;
2730c2248fc9SDouglas Gilbert 
2731c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2732f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2733c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2734c2248fc9SDouglas Gilbert 		return check_condition_result;
2735c2248fc9SDouglas Gilbert 	}
2736c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2737f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2738c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2739c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2740c2248fc9SDouglas Gilbert 		return check_condition_result;
2741c2248fc9SDouglas Gilbert 	}
274219789100SFUJITA Tomonori 
2743f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2744d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2745d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
2746c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2747c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2748c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2749c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2750c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
275132f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
275232f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2753c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2754c65b1445SDouglas Gilbert 		}
2755c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
27561da177e4SLinus Torvalds 		return check_condition_result;
27571da177e4SLinus Torvalds 	}
2758c6a44287SMartin K. Petersen 
27596c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
27606c78cc06SAkinobu Mita 
2761c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2762f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2763c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2764c6a44287SMartin K. Petersen 
2765c6a44287SMartin K. Petersen 		if (prot_ret) {
27666c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2767c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2768c6a44287SMartin K. Petersen 			return illegal_condition_result;
2769c6a44287SMartin K. Petersen 		}
2770c6a44287SMartin K. Petersen 	}
2771c6a44287SMartin K. Petersen 
27720a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, false);
27731da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2774f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2775a4517511SAkinobu Mita 		return DID_ERROR << 16;
2776a4517511SAkinobu Mita 
2777c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2778a4517511SAkinobu Mita 
2779c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2780c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2781c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2782c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2783c2248fc9SDouglas Gilbert 			return check_condition_result;
2784c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2785c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2786c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2787c2248fc9SDouglas Gilbert 			return check_condition_result;
2788c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2789c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2790c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2791c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2792c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2793c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2794c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2795c2248fc9SDouglas Gilbert 		}
2796c2248fc9SDouglas Gilbert 	}
2797a4517511SAkinobu Mita 	return 0;
27981da177e4SLinus Torvalds }
27991da177e4SLinus Torvalds 
280058a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2801c6a44287SMartin K. Petersen {
2802cbf67842SDouglas Gilbert 	int i, j, n;
2803c6a44287SMartin K. Petersen 
2804cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2805c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2806cbf67842SDouglas Gilbert 		char b[128];
2807c6a44287SMartin K. Petersen 
2808cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2809c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2810c6a44287SMartin K. Petersen 
2811cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2812cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2813cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2814cbf67842SDouglas Gilbert 			else
2815cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2816cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2817cbf67842SDouglas Gilbert 		}
2818cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2819c6a44287SMartin K. Petersen 	}
2820c6a44287SMartin K. Petersen }
2821c6a44287SMartin K. Petersen 
2822c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2823395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2824c6a44287SMartin K. Petersen {
2825be4e11beSAkinobu Mita 	int ret;
28266ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2827be4e11beSAkinobu Mita 	void *daddr;
282865f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2829c6a44287SMartin K. Petersen 	int ppage_offset;
2830be4e11beSAkinobu Mita 	int dpage_offset;
2831be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2832be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2833c6a44287SMartin K. Petersen 
2834c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2835c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2836c6a44287SMartin K. Petersen 
2837be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2838be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2839be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2840be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2841be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2842c6a44287SMartin K. Petersen 
2843be4e11beSAkinobu Mita 	/* For each protection page */
2844be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2845be4e11beSAkinobu Mita 		dpage_offset = 0;
2846be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2847be4e11beSAkinobu Mita 			ret = 0x01;
2848be4e11beSAkinobu Mita 			goto out;
2849c6a44287SMartin K. Petersen 		}
2850c6a44287SMartin K. Petersen 
2851be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
28526ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2853be4e11beSAkinobu Mita 			/* If we're at the end of the current
2854be4e11beSAkinobu Mita 			 * data page advance to the next one
2855be4e11beSAkinobu Mita 			 */
2856be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2857be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2858be4e11beSAkinobu Mita 					ret = 0x01;
2859be4e11beSAkinobu Mita 					goto out;
2860be4e11beSAkinobu Mita 				}
2861be4e11beSAkinobu Mita 				dpage_offset = 0;
2862be4e11beSAkinobu Mita 			}
2863c6a44287SMartin K. Petersen 
2864be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2865be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2866be4e11beSAkinobu Mita 
2867be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2868beb40ea4SAkinobu Mita 			if (ret) {
2869773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2870395cef03SMartin K. Petersen 				goto out;
2871395cef03SMartin K. Petersen 			}
2872395cef03SMartin K. Petersen 
2873c6a44287SMartin K. Petersen 			sector++;
2874395cef03SMartin K. Petersen 			ei_lba++;
2875773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2876c6a44287SMartin K. Petersen 		}
2877be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2878be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2879c6a44287SMartin K. Petersen 	}
2880be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2881c6a44287SMartin K. Petersen 
288265f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2883c6a44287SMartin K. Petersen 	dix_writes++;
2884c6a44287SMartin K. Petersen 
2885c6a44287SMartin K. Petersen 	return 0;
2886c6a44287SMartin K. Petersen 
2887c6a44287SMartin K. Petersen out:
2888c6a44287SMartin K. Petersen 	dif_errors++;
2889be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2890be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2891c6a44287SMartin K. Petersen 	return ret;
2892c6a44287SMartin K. Petersen }
2893c6a44287SMartin K. Petersen 
2894b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2895b90ebc3dSAkinobu Mita {
2896773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2897773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2898773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2899b90ebc3dSAkinobu Mita 	return lba;
2900b90ebc3dSAkinobu Mita }
2901b90ebc3dSAkinobu Mita 
2902b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2903b90ebc3dSAkinobu Mita {
2904773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2905a027b5b9SAkinobu Mita 
2906773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2907773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2908a027b5b9SAkinobu Mita 	return lba;
2909a027b5b9SAkinobu Mita }
2910a027b5b9SAkinobu Mita 
291144d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
291244d92694SMartin K. Petersen {
2913b90ebc3dSAkinobu Mita 	sector_t end;
2914b90ebc3dSAkinobu Mita 	unsigned int mapped;
2915b90ebc3dSAkinobu Mita 	unsigned long index;
2916b90ebc3dSAkinobu Mita 	unsigned long next;
291744d92694SMartin K. Petersen 
2918b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2919b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
292044d92694SMartin K. Petersen 
292144d92694SMartin K. Petersen 	if (mapped)
2922b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
292344d92694SMartin K. Petersen 	else
2924b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
292544d92694SMartin K. Petersen 
2926b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
292744d92694SMartin K. Petersen 	*num = end - lba;
292844d92694SMartin K. Petersen 	return mapped;
292944d92694SMartin K. Petersen }
293044d92694SMartin K. Petersen 
293144d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
293244d92694SMartin K. Petersen {
293344d92694SMartin K. Petersen 	sector_t end = lba + len;
293444d92694SMartin K. Petersen 
293544d92694SMartin K. Petersen 	while (lba < end) {
2936b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
293744d92694SMartin K. Petersen 
2938b90ebc3dSAkinobu Mita 		if (index < map_size)
2939b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
294044d92694SMartin K. Petersen 
2941b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
294244d92694SMartin K. Petersen 	}
294344d92694SMartin K. Petersen }
294444d92694SMartin K. Petersen 
294544d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
294644d92694SMartin K. Petersen {
294744d92694SMartin K. Petersen 	sector_t end = lba + len;
294844d92694SMartin K. Petersen 
294944d92694SMartin K. Petersen 	while (lba < end) {
2950b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
295144d92694SMartin K. Petersen 
2952b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2953773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2954b90ebc3dSAkinobu Mita 		    index < map_size) {
2955b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2956760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2957be1dd78dSEric Sandeen 				memset(fake_storep +
2958760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2959760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2960773642d9SDouglas Gilbert 				       sdebug_sector_size *
2961773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2962be1dd78dSEric Sandeen 			}
2963e9926b43SAkinobu Mita 			if (dif_storep) {
2964e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2965e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2966773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2967e9926b43SAkinobu Mita 			}
2968b90ebc3dSAkinobu Mita 		}
2969b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
297044d92694SMartin K. Petersen 	}
297144d92694SMartin K. Petersen }
297244d92694SMartin K. Petersen 
2973fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
29741da177e4SLinus Torvalds {
2975c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2976c2248fc9SDouglas Gilbert 	u64 lba;
2977c2248fc9SDouglas Gilbert 	u32 num;
2978c2248fc9SDouglas Gilbert 	u32 ei_lba;
29791da177e4SLinus Torvalds 	unsigned long iflags;
298019789100SFUJITA Tomonori 	int ret;
2981c2248fc9SDouglas Gilbert 	bool check_prot;
29821da177e4SLinus Torvalds 
2983c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2984c2248fc9SDouglas Gilbert 	case WRITE_16:
2985c2248fc9SDouglas Gilbert 		ei_lba = 0;
2986c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2987c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2988c2248fc9SDouglas Gilbert 		check_prot = true;
2989c2248fc9SDouglas Gilbert 		break;
2990c2248fc9SDouglas Gilbert 	case WRITE_10:
2991c2248fc9SDouglas Gilbert 		ei_lba = 0;
2992c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2993c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2994c2248fc9SDouglas Gilbert 		check_prot = true;
2995c2248fc9SDouglas Gilbert 		break;
2996c2248fc9SDouglas Gilbert 	case WRITE_6:
2997c2248fc9SDouglas Gilbert 		ei_lba = 0;
2998c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2999c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
3000c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
3001c2248fc9SDouglas Gilbert 		check_prot = true;
3002c2248fc9SDouglas Gilbert 		break;
3003c2248fc9SDouglas Gilbert 	case WRITE_12:
3004c2248fc9SDouglas Gilbert 		ei_lba = 0;
3005c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3006c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3007c2248fc9SDouglas Gilbert 		check_prot = true;
3008c2248fc9SDouglas Gilbert 		break;
3009c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3010c2248fc9SDouglas Gilbert 		ei_lba = 0;
3011c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3012c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3013c2248fc9SDouglas Gilbert 		check_prot = false;
3014c2248fc9SDouglas Gilbert 		break;
3015c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3016c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3017c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3018c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3019c2248fc9SDouglas Gilbert 		check_prot = false;
3020c2248fc9SDouglas Gilbert 		break;
3021c2248fc9SDouglas Gilbert 	}
3022f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
30238475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3024c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3025c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3026c2248fc9SDouglas Gilbert 			return check_condition_result;
3027c2248fc9SDouglas Gilbert 		}
30288475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
30298475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3030c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3031c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3032c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3033c2248fc9SDouglas Gilbert 	}
3034c2248fc9SDouglas Gilbert 
3035c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
3036f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
3037c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3038c2248fc9SDouglas Gilbert 		return check_condition_result;
3039c2248fc9SDouglas Gilbert 	}
3040c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
3041f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
3042c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
3043c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3044c2248fc9SDouglas Gilbert 		return check_condition_result;
3045c2248fc9SDouglas Gilbert 	}
30461da177e4SLinus Torvalds 
30476c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
30486c78cc06SAkinobu Mita 
3049c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3050f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3051c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3052c6a44287SMartin K. Petersen 
3053c6a44287SMartin K. Petersen 		if (prot_ret) {
30546c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
3055c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3056c6a44287SMartin K. Petersen 			return illegal_condition_result;
3057c6a44287SMartin K. Petersen 		}
3058c6a44287SMartin K. Petersen 	}
3059c6a44287SMartin K. Petersen 
30600a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, true);
3061f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
306244d92694SMartin K. Petersen 		map_region(lba, num);
30631da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3064f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3065773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3066c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3067c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3068c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3069cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3070773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
307144d92694SMartin K. Petersen 
3072f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3073c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3074c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3075c2248fc9SDouglas Gilbert 
3076c4837394SDouglas Gilbert 		if (sqcp) {
3077c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3078c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3079c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3080c2248fc9SDouglas Gilbert 				return check_condition_result;
3081c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3082c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3083c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3084c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3085c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3086c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3087c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3088c2248fc9SDouglas Gilbert 			}
3089c2248fc9SDouglas Gilbert 		}
3090c4837394SDouglas Gilbert 	}
30911da177e4SLinus Torvalds 	return 0;
30921da177e4SLinus Torvalds }
30931da177e4SLinus Torvalds 
3094481b5e5cSDouglas Gilbert /*
3095481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3096481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3097481b5e5cSDouglas Gilbert  */
3098481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3099481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3100481b5e5cSDouglas Gilbert {
3101481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3102481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3103481b5e5cSDouglas Gilbert 	u8 *up;
3104481b5e5cSDouglas Gilbert 	u8 wrprotect;
3105481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3106481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3107481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3108481b5e5cSDouglas Gilbert 	u32 ei_lba;
3109481b5e5cSDouglas Gilbert 	u64 lba;
3110481b5e5cSDouglas Gilbert 	unsigned long iflags;
3111481b5e5cSDouglas Gilbert 	int ret, res;
3112481b5e5cSDouglas Gilbert 	bool is_16;
3113481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3114481b5e5cSDouglas Gilbert 
3115481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3116481b5e5cSDouglas Gilbert 		is_16 = false;
3117481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3118481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3119481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3120481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3121481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3122481b5e5cSDouglas Gilbert 		is_16 = true;
3123481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3124481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3125481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3126481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3127481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3128481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3129481b5e5cSDouglas Gilbert 			    wrprotect) {
3130481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3131481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3132481b5e5cSDouglas Gilbert 			}
3133481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3134481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3135481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3136481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3137481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3138481b5e5cSDouglas Gilbert 		}
3139481b5e5cSDouglas Gilbert 	}
3140481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3141481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3142481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3143481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3144481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3145481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3146481b5e5cSDouglas Gilbert 				my_name, __func__);
3147481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3148481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3149481b5e5cSDouglas Gilbert 	}
3150481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3151481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3152481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3153481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3154481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3155481b5e5cSDouglas Gilbert 				my_name, __func__);
3156481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3157481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3158481b5e5cSDouglas Gilbert 	}
3159481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3160481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3161481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3162481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3163481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3164481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3165481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3166481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3167481b5e5cSDouglas Gilbert 	if (res == -1) {
3168481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3169481b5e5cSDouglas Gilbert 		goto err_out;
3170481b5e5cSDouglas Gilbert 	}
3171481b5e5cSDouglas Gilbert 
3172481b5e5cSDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
3173481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3174481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3175481b5e5cSDouglas Gilbert 	cum_lb = 0;
3176481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3177481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3178481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3179481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3180481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3181481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3182481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3183481b5e5cSDouglas Gilbert 		if (num == 0)
3184481b5e5cSDouglas Gilbert 			continue;
3185481b5e5cSDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
3186481b5e5cSDouglas Gilbert 		if (ret)
3187481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3188481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3189481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3190481b5e5cSDouglas Gilbert 
3191481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3192481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3193481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3194481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3195481b5e5cSDouglas Gilbert 				    my_name, __func__);
3196481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3197481b5e5cSDouglas Gilbert 					0);
3198481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3199481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3200481b5e5cSDouglas Gilbert 		}
3201481b5e5cSDouglas Gilbert 
3202481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3203481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3204481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3205481b5e5cSDouglas Gilbert 							 ei_lba);
3206481b5e5cSDouglas Gilbert 
3207481b5e5cSDouglas Gilbert 			if (prot_ret) {
3208481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3209481b5e5cSDouglas Gilbert 						prot_ret);
3210481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3211481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3212481b5e5cSDouglas Gilbert 			}
3213481b5e5cSDouglas Gilbert 		}
3214481b5e5cSDouglas Gilbert 
3215481b5e5cSDouglas Gilbert 		ret = do_device_access(scp, sg_off, lba, num, true);
3216481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
3217481b5e5cSDouglas Gilbert 			map_region(lba, num);
3218481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3219481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3220481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3221481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3222481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3223481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3224481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3225481b5e5cSDouglas Gilbert 
3226481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3227481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3228481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3229481b5e5cSDouglas Gilbert 
3230481b5e5cSDouglas Gilbert 			if (sqcp) {
3231481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3232481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3233481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3234481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3235481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3236481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3237481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3238481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3239481b5e5cSDouglas Gilbert 							0x10, 1);
3240481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3241481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3242481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3243481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3244481b5e5cSDouglas Gilbert 							0x10, 1);
3245481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3246481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3247481b5e5cSDouglas Gilbert 				}
3248481b5e5cSDouglas Gilbert 			}
3249481b5e5cSDouglas Gilbert 		}
3250481b5e5cSDouglas Gilbert 		sg_off += num_by;
3251481b5e5cSDouglas Gilbert 		cum_lb += num;
3252481b5e5cSDouglas Gilbert 	}
3253481b5e5cSDouglas Gilbert 	ret = 0;
3254481b5e5cSDouglas Gilbert err_out_unlock:
3255481b5e5cSDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3256481b5e5cSDouglas Gilbert err_out:
3257481b5e5cSDouglas Gilbert 	kfree(lrdp);
3258481b5e5cSDouglas Gilbert 	return ret;
3259481b5e5cSDouglas Gilbert }
3260481b5e5cSDouglas Gilbert 
3261fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3262fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
326344d92694SMartin K. Petersen {
326444d92694SMartin K. Petersen 	unsigned long iflags;
326544d92694SMartin K. Petersen 	unsigned long long i;
326644d92694SMartin K. Petersen 	int ret;
3267773642d9SDouglas Gilbert 	u64 lba_off;
326844d92694SMartin K. Petersen 
3269c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
327044d92694SMartin K. Petersen 	if (ret)
327144d92694SMartin K. Petersen 		return ret;
327244d92694SMartin K. Petersen 
327344d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
327444d92694SMartin K. Petersen 
32759ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
327644d92694SMartin K. Petersen 		unmap_region(lba, num);
327744d92694SMartin K. Petersen 		goto out;
327844d92694SMartin K. Petersen 	}
327944d92694SMartin K. Petersen 
3280773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
3281c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3282c2248fc9SDouglas Gilbert 	if (ndob) {
3283773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
3284c2248fc9SDouglas Gilbert 		ret = 0;
3285c2248fc9SDouglas Gilbert 	} else
3286773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3287773642d9SDouglas Gilbert 					  sdebug_sector_size);
328844d92694SMartin K. Petersen 
328944d92694SMartin K. Petersen 	if (-1 == ret) {
329044d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3291773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3292e33d7c56SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
3293c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3294e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
3295cbf67842SDouglas Gilbert 			    my_name, "write same",
3296e33d7c56SDouglas Gilbert 			    sdebug_sector_size, ret);
329744d92694SMartin K. Petersen 
329844d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
329944d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3300773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3301773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3302773642d9SDouglas Gilbert 		       sdebug_sector_size);
330344d92694SMartin K. Petersen 
33049ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
330544d92694SMartin K. Petersen 		map_region(lba, num);
330644d92694SMartin K. Petersen out:
330744d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
330844d92694SMartin K. Petersen 
330944d92694SMartin K. Petersen 	return 0;
331044d92694SMartin K. Petersen }
331144d92694SMartin K. Petersen 
3312fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3313fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3314c2248fc9SDouglas Gilbert {
3315c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3316c2248fc9SDouglas Gilbert 	u32 lba;
3317c2248fc9SDouglas Gilbert 	u16 num;
3318c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3319c2248fc9SDouglas Gilbert 	bool unmap = false;
3320c2248fc9SDouglas Gilbert 
3321c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3322773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3323c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3324c2248fc9SDouglas Gilbert 			return check_condition_result;
3325c2248fc9SDouglas Gilbert 		} else
3326c2248fc9SDouglas Gilbert 			unmap = true;
3327c2248fc9SDouglas Gilbert 	}
3328c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3329c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3330773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3331c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3332c2248fc9SDouglas Gilbert 		return check_condition_result;
3333c2248fc9SDouglas Gilbert 	}
3334c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3335c2248fc9SDouglas Gilbert }
3336c2248fc9SDouglas Gilbert 
3337fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3338fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3339c2248fc9SDouglas Gilbert {
3340c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3341c2248fc9SDouglas Gilbert 	u64 lba;
3342c2248fc9SDouglas Gilbert 	u32 num;
3343c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3344c2248fc9SDouglas Gilbert 	bool unmap = false;
3345c2248fc9SDouglas Gilbert 	bool ndob = false;
3346c2248fc9SDouglas Gilbert 
3347c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3348773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3349c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3350c2248fc9SDouglas Gilbert 			return check_condition_result;
3351c2248fc9SDouglas Gilbert 		} else
3352c2248fc9SDouglas Gilbert 			unmap = true;
3353c2248fc9SDouglas Gilbert 	}
3354c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3355c2248fc9SDouglas Gilbert 		ndob = true;
3356c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3357c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3358773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3359c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3360c2248fc9SDouglas Gilbert 		return check_condition_result;
3361c2248fc9SDouglas Gilbert 	}
3362c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3363c2248fc9SDouglas Gilbert }
3364c2248fc9SDouglas Gilbert 
3365acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3366acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3367acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3368fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3369fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3370acafd0b9SEwan D. Milne {
3371acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3372acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3373acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3374acafd0b9SEwan D. Milne 	u8 mode;
3375acafd0b9SEwan D. Milne 
3376acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3377acafd0b9SEwan D. Milne 	switch (mode) {
3378acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3379acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3380acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3381acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3382acafd0b9SEwan D. Milne 		break;
3383acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3384acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3385acafd0b9SEwan D. Milne 		break;
3386acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3387acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3388acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3389acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3390acafd0b9SEwan D. Milne 				    dev_list)
3391acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3392acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3393acafd0b9SEwan D. Milne 				if (devip != dp)
3394acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3395acafd0b9SEwan D. Milne 						dp->uas_bm);
3396acafd0b9SEwan D. Milne 			}
3397acafd0b9SEwan D. Milne 		break;
3398acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3399acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3400acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3401acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3402acafd0b9SEwan D. Milne 				    dev_list)
3403acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3404acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3405acafd0b9SEwan D. Milne 					dp->uas_bm);
3406acafd0b9SEwan D. Milne 		break;
3407acafd0b9SEwan D. Milne 	default:
3408acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3409acafd0b9SEwan D. Milne 		break;
3410acafd0b9SEwan D. Milne 	}
3411acafd0b9SEwan D. Milne 	return 0;
3412acafd0b9SEwan D. Milne }
3413acafd0b9SEwan D. Milne 
3414fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3415fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
341638d5c833SDouglas Gilbert {
341738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
341838d5c833SDouglas Gilbert 	u8 *arr;
341938d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
342038d5c833SDouglas Gilbert 	u64 lba;
342138d5c833SDouglas Gilbert 	u32 dnum;
3422773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
342338d5c833SDouglas Gilbert 	u8 num;
342438d5c833SDouglas Gilbert 	unsigned long iflags;
342538d5c833SDouglas Gilbert 	int ret;
3426d467d31fSDouglas Gilbert 	int retval = 0;
342738d5c833SDouglas Gilbert 
3428d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
342938d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
343038d5c833SDouglas Gilbert 	if (0 == num)
343138d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
34328475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
343338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
343438d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
343538d5c833SDouglas Gilbert 		return check_condition_result;
343638d5c833SDouglas Gilbert 	}
34378475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34388475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
343938d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
344038d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
344138d5c833SDouglas Gilbert 			    "to DIF device\n");
344238d5c833SDouglas Gilbert 
344338d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
344438d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
344538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
344638d5c833SDouglas Gilbert 		return check_condition_result;
344738d5c833SDouglas Gilbert 	}
344838d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
344938d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
345038d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
345138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
345238d5c833SDouglas Gilbert 		return check_condition_result;
345338d5c833SDouglas Gilbert 	}
3454d467d31fSDouglas Gilbert 	dnum = 2 * num;
34556396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3456d467d31fSDouglas Gilbert 	if (NULL == arr) {
3457d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3458d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3459d467d31fSDouglas Gilbert 		return check_condition_result;
3460d467d31fSDouglas Gilbert 	}
346138d5c833SDouglas Gilbert 
346238d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
346338d5c833SDouglas Gilbert 
346438d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
346538d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
346638d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
346738d5c833SDouglas Gilbert 	fake_storep = arr;
34680a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, 0, dnum, true);
346938d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
347038d5c833SDouglas Gilbert 	if (ret == -1) {
3471d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3472d467d31fSDouglas Gilbert 		goto cleanup;
3473773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
347438d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
347538d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
347638d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
347738d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
347838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3479d467d31fSDouglas Gilbert 		retval = check_condition_result;
3480d467d31fSDouglas Gilbert 		goto cleanup;
348138d5c833SDouglas Gilbert 	}
348238d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
348338d5c833SDouglas Gilbert 		map_region(lba, num);
3484d467d31fSDouglas Gilbert cleanup:
348538d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3486d467d31fSDouglas Gilbert 	kfree(arr);
3487d467d31fSDouglas Gilbert 	return retval;
348838d5c833SDouglas Gilbert }
348938d5c833SDouglas Gilbert 
349044d92694SMartin K. Petersen struct unmap_block_desc {
349144d92694SMartin K. Petersen 	__be64	lba;
349244d92694SMartin K. Petersen 	__be32	blocks;
349344d92694SMartin K. Petersen 	__be32	__reserved;
349444d92694SMartin K. Petersen };
349544d92694SMartin K. Petersen 
3496fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
349744d92694SMartin K. Petersen {
349844d92694SMartin K. Petersen 	unsigned char *buf;
349944d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
350044d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
350144d92694SMartin K. Petersen 	int ret;
35026c78cc06SAkinobu Mita 	unsigned long iflags;
350344d92694SMartin K. Petersen 
350444d92694SMartin K. Petersen 
3505c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3506c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3507c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3508c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
350944d92694SMartin K. Petersen 
351044d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3511773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3512c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
351344d92694SMartin K. Petersen 		return check_condition_result;
3514c2248fc9SDouglas Gilbert 	}
351544d92694SMartin K. Petersen 
3516b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3517c2248fc9SDouglas Gilbert 	if (!buf) {
3518c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3519c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3520c2248fc9SDouglas Gilbert 		return check_condition_result;
3521c2248fc9SDouglas Gilbert 	}
3522c2248fc9SDouglas Gilbert 
3523c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
352444d92694SMartin K. Petersen 
352544d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
352644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
352744d92694SMartin K. Petersen 
352844d92694SMartin K. Petersen 	desc = (void *)&buf[8];
352944d92694SMartin K. Petersen 
35306c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
35316c78cc06SAkinobu Mita 
353244d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
353344d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
353444d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
353544d92694SMartin K. Petersen 
3536c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
353744d92694SMartin K. Petersen 		if (ret)
353844d92694SMartin K. Petersen 			goto out;
353944d92694SMartin K. Petersen 
354044d92694SMartin K. Petersen 		unmap_region(lba, num);
354144d92694SMartin K. Petersen 	}
354244d92694SMartin K. Petersen 
354344d92694SMartin K. Petersen 	ret = 0;
354444d92694SMartin K. Petersen 
354544d92694SMartin K. Petersen out:
35466c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
354744d92694SMartin K. Petersen 	kfree(buf);
354844d92694SMartin K. Petersen 
354944d92694SMartin K. Petersen 	return ret;
355044d92694SMartin K. Petersen }
355144d92694SMartin K. Petersen 
355244d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
355344d92694SMartin K. Petersen 
3554fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3555fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
355644d92694SMartin K. Petersen {
3557c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3558c2248fc9SDouglas Gilbert 	u64 lba;
3559c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3560c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
356144d92694SMartin K. Petersen 	int ret;
356244d92694SMartin K. Petersen 
3563c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3564c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
356544d92694SMartin K. Petersen 
356644d92694SMartin K. Petersen 	if (alloc_len < 24)
356744d92694SMartin K. Petersen 		return 0;
356844d92694SMartin K. Petersen 
3569c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
357044d92694SMartin K. Petersen 	if (ret)
357144d92694SMartin K. Petersen 		return ret;
357244d92694SMartin K. Petersen 
3573c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
357444d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3575c2248fc9SDouglas Gilbert 	else {
3576c2248fc9SDouglas Gilbert 		mapped = 1;
3577c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3578c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3579c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3580c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3581c2248fc9SDouglas Gilbert 		else
3582c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3583c2248fc9SDouglas Gilbert 	}
358444d92694SMartin K. Petersen 
358544d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3586c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3587c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3588c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3589c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
359044d92694SMartin K. Petersen 
3591c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
359244d92694SMartin K. Petersen }
359344d92694SMartin K. Petersen 
359480c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
359580c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
359680c49563SDouglas Gilbert {
35974f2c8bf6SDouglas Gilbert 	int res = 0;
359880c49563SDouglas Gilbert 	u64 lba;
359980c49563SDouglas Gilbert 	u32 num_blocks;
360080c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
360180c49563SDouglas Gilbert 
360280c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
360380c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
360480c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
360580c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
360680c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
360780c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
360880c49563SDouglas Gilbert 	}
360980c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
361080c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
361180c49563SDouglas Gilbert 		return check_condition_result;
361280c49563SDouglas Gilbert 	}
36134f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
36144f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
36154f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
36164f2c8bf6SDouglas Gilbert 		write_since_sync = false;
36174f2c8bf6SDouglas Gilbert 	return res;
361880c49563SDouglas Gilbert }
361980c49563SDouglas Gilbert 
3620fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3621fb0cc8d1SDouglas Gilbert 
36228d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
36238d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
36248d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
36258d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
36268d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
36278d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
36288d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
36298d039e22SDouglas Gilbert  */
36301da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
36311da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
36321da177e4SLinus Torvalds {
363301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
36348d039e22SDouglas Gilbert 	unsigned int alloc_len;
36358d039e22SDouglas Gilbert 	unsigned char select_report;
36368d039e22SDouglas Gilbert 	u64 lun;
36378d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3638fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
36398d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
36408d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
36418d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
36428d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3643fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3644fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3645fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
36461da177e4SLinus Torvalds 
364719c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
36488d039e22SDouglas Gilbert 
36498d039e22SDouglas Gilbert 	select_report = cmd[2];
36508d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
36518d039e22SDouglas Gilbert 
36528d039e22SDouglas Gilbert 	if (alloc_len < 4) {
36538d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
36548d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
36551da177e4SLinus Torvalds 		return check_condition_result;
36561da177e4SLinus Torvalds 	}
36578d039e22SDouglas Gilbert 
36588d039e22SDouglas Gilbert 	switch (select_report) {
36598d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3660773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36618d039e22SDouglas Gilbert 		wlun_cnt = 0;
36628d039e22SDouglas Gilbert 		break;
36638d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3664c65b1445SDouglas Gilbert 		lun_cnt = 0;
36658d039e22SDouglas Gilbert 		wlun_cnt = 1;
36668d039e22SDouglas Gilbert 		break;
36678d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
36688d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36698d039e22SDouglas Gilbert 		wlun_cnt = 1;
36708d039e22SDouglas Gilbert 		break;
36718d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
36728d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
36738d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
36748d039e22SDouglas Gilbert 	default:
36758d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
36768d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
36778d039e22SDouglas Gilbert 		return check_condition_result;
36788d039e22SDouglas Gilbert 	}
36798d039e22SDouglas Gilbert 
36808d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3681c65b1445SDouglas Gilbert 		--lun_cnt;
36828d039e22SDouglas Gilbert 
36838d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3684fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3685fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
36868d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
36878d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
36888d039e22SDouglas Gilbert 
3689fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
36908d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3691fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3692fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3693fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3694fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3695fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3696fb0cc8d1SDouglas Gilbert 			++lun_p;
3697fb0cc8d1SDouglas Gilbert 			j = 1;
3698fb0cc8d1SDouglas Gilbert 		}
3699fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3700fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3701fb0cc8d1SDouglas Gilbert 				break;
3702fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3703fb0cc8d1SDouglas Gilbert 		}
3704fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3705fb0cc8d1SDouglas Gilbert 			break;
3706fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3707fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3708fb0cc8d1SDouglas Gilbert 		if (res)
3709fb0cc8d1SDouglas Gilbert 			return res;
3710fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3711fb0cc8d1SDouglas Gilbert 	}
3712fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3713fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3714fb0cc8d1SDouglas Gilbert 		++j;
3715fb0cc8d1SDouglas Gilbert 	}
3716fb0cc8d1SDouglas Gilbert 	if (j > 0)
3717fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
37188d039e22SDouglas Gilbert 	return res;
37191da177e4SLinus Torvalds }
37201da177e4SLinus Torvalds 
3721c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3722c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3723c639d14eSFUJITA Tomonori {
3724be4e11beSAkinobu Mita 	int j;
3725c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3726c639d14eSFUJITA Tomonori 	unsigned int offset;
3727c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3728be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3729c639d14eSFUJITA Tomonori 
3730c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3731b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3732c5af0db9SAkinobu Mita 	if (!buf) {
373322017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
373422017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3735c5af0db9SAkinobu Mita 		return check_condition_result;
3736c5af0db9SAkinobu Mita 	}
3737c639d14eSFUJITA Tomonori 
373821a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3739c639d14eSFUJITA Tomonori 
3740c639d14eSFUJITA Tomonori 	offset = 0;
3741be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3742be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3743c639d14eSFUJITA Tomonori 
3744be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3745be4e11beSAkinobu Mita 		kaddr = miter.addr;
3746be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3747be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3748c639d14eSFUJITA Tomonori 
3749be4e11beSAkinobu Mita 		offset += miter.length;
3750c639d14eSFUJITA Tomonori 	}
3751be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3752c639d14eSFUJITA Tomonori 	kfree(buf);
3753c639d14eSFUJITA Tomonori 
3754be4e11beSAkinobu Mita 	return 0;
3755c639d14eSFUJITA Tomonori }
3756c639d14eSFUJITA Tomonori 
3757fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3758fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3759c2248fc9SDouglas Gilbert {
3760c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3761c2248fc9SDouglas Gilbert 	u64 lba;
3762c2248fc9SDouglas Gilbert 	u32 num;
3763c2248fc9SDouglas Gilbert 	int errsts;
3764c2248fc9SDouglas Gilbert 
3765c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3766c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3767c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3768c2248fc9SDouglas Gilbert 		return check_condition_result;
3769c2248fc9SDouglas Gilbert 	}
3770c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3771c2248fc9SDouglas Gilbert 	if (errsts)
3772c2248fc9SDouglas Gilbert 		return errsts;
3773c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3774c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3775c2248fc9SDouglas Gilbert 		if (errsts)
3776c2248fc9SDouglas Gilbert 			return errsts;
3777c2248fc9SDouglas Gilbert 	}
3778c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3779c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3780c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3781c2248fc9SDouglas Gilbert }
3782c2248fc9SDouglas Gilbert 
3783c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3784c4837394SDouglas Gilbert {
3785c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
3786c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3787c4837394SDouglas Gilbert 
3788458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3789458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
3790458df78bSBart Van Assche 		hwq = 0;
3791458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
3792c4837394SDouglas Gilbert }
3793c4837394SDouglas Gilbert 
3794c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3795fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
37961da177e4SLinus Torvalds {
37977382f9d8SDouglas Gilbert 	bool aborted = sd_dp->aborted;
3798c4837394SDouglas Gilbert 	int qc_idx;
3799cbf67842SDouglas Gilbert 	int retiring = 0;
38001da177e4SLinus Torvalds 	unsigned long iflags;
3801c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3802cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3803cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3804cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38051da177e4SLinus Torvalds 
380610bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
38077382f9d8SDouglas Gilbert 	if (unlikely(aborted))
38087382f9d8SDouglas Gilbert 		sd_dp->aborted = false;
3809c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3810c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3811c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3812cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3813c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3814c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3815c4837394SDouglas Gilbert 	}
3816c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3817c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
38181da177e4SLinus Torvalds 		return;
38191da177e4SLinus Torvalds 	}
3820c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3821c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3822cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3823b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3824c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3825c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3826c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
38271da177e4SLinus Torvalds 		return;
38281da177e4SLinus Torvalds 	}
3829cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3830f46eb0e9SDouglas Gilbert 	if (likely(devip))
3831cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3832cbf67842SDouglas Gilbert 	else
3833c1287970STomas Winkler 		pr_err("devip=NULL\n");
3834f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3835cbf67842SDouglas Gilbert 		retiring = 1;
3836cbf67842SDouglas Gilbert 
3837cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3838c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3839c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3840c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3841cbf67842SDouglas Gilbert 		return;
38421da177e4SLinus Torvalds 	}
38431da177e4SLinus Torvalds 
3844cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3845cbf67842SDouglas Gilbert 		int k, retval;
3846cbf67842SDouglas Gilbert 
3847cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3848c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3849c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3850c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3851cbf67842SDouglas Gilbert 			return;
3852cbf67842SDouglas Gilbert 		}
3853c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3854773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3855cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3856cbf67842SDouglas Gilbert 		else
3857cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3858cbf67842SDouglas Gilbert 	}
3859c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
38607382f9d8SDouglas Gilbert 	if (unlikely(aborted)) {
38617382f9d8SDouglas Gilbert 		if (sdebug_verbose)
38627382f9d8SDouglas Gilbert 			pr_info("bypassing scsi_done() due to aborted cmd\n");
38637382f9d8SDouglas Gilbert 		return;
38647382f9d8SDouglas Gilbert 	}
3865cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3866cbf67842SDouglas Gilbert }
3867cbf67842SDouglas Gilbert 
3868cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3869fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3870cbf67842SDouglas Gilbert {
3871a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3872a10bc12aSDouglas Gilbert 						  hrt);
3873a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3874cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3875cbf67842SDouglas Gilbert }
38761da177e4SLinus Torvalds 
3877a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3878fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3879a10bc12aSDouglas Gilbert {
3880a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3881a10bc12aSDouglas Gilbert 						  ew.work);
3882a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3883a10bc12aSDouglas Gilbert }
3884a10bc12aSDouglas Gilbert 
388509ba24c1SDouglas Gilbert static bool got_shared_uuid;
3886bf476433SChristoph Hellwig static uuid_t shared_uuid;
388709ba24c1SDouglas Gilbert 
3888fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3889fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
38905cb2fc06SFUJITA Tomonori {
38915cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
38925cb2fc06SFUJITA Tomonori 
38935cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
38945cb2fc06SFUJITA Tomonori 	if (devip) {
389509ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3896bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
389709ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
389809ba24c1SDouglas Gilbert 			if (got_shared_uuid)
389909ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
390009ba24c1SDouglas Gilbert 			else {
3901bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
390209ba24c1SDouglas Gilbert 				got_shared_uuid = true;
390309ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
390409ba24c1SDouglas Gilbert 			}
390509ba24c1SDouglas Gilbert 		}
39065cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
39075cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
39085cb2fc06SFUJITA Tomonori 	}
39095cb2fc06SFUJITA Tomonori 	return devip;
39105cb2fc06SFUJITA Tomonori }
39115cb2fc06SFUJITA Tomonori 
3912f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
39131da177e4SLinus Torvalds {
39141da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
39151da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3916f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
39171da177e4SLinus Torvalds 
3918d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
39191da177e4SLinus Torvalds 	if (!sdbg_host) {
3920c1287970STomas Winkler 		pr_err("Host info NULL\n");
39211da177e4SLinus Torvalds 		return NULL;
39221da177e4SLinus Torvalds 	}
39231da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
39241da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
39251da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
39261da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
39271da177e4SLinus Torvalds 			return devip;
39281da177e4SLinus Torvalds 		else {
39291da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
39301da177e4SLinus Torvalds 				open_devip = devip;
39311da177e4SLinus Torvalds 		}
39321da177e4SLinus Torvalds 	}
39335cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
39345cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
39355cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3936c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
39371da177e4SLinus Torvalds 			return NULL;
39381da177e4SLinus Torvalds 		}
39391da177e4SLinus Torvalds 	}
3940a75869d1SFUJITA Tomonori 
39411da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
39421da177e4SLinus Torvalds 	open_devip->target = sdev->id;
39431da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
39441da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3945cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3946cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3947c2248fc9SDouglas Gilbert 	open_devip->used = true;
39481da177e4SLinus Torvalds 	return open_devip;
39491da177e4SLinus Torvalds }
39501da177e4SLinus Torvalds 
39518dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
39521da177e4SLinus Torvalds {
3953773642d9SDouglas Gilbert 	if (sdebug_verbose)
3954c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
39558dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39568b904b5bSBart Van Assche 	blk_queue_flag_set(QUEUE_FLAG_BIDI, sdp->request_queue);
39578dea0d02SFUJITA Tomonori 	return 0;
39588dea0d02SFUJITA Tomonori }
39591da177e4SLinus Torvalds 
39608dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
39618dea0d02SFUJITA Tomonori {
3962f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3963f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3964a34c4e98SFUJITA Tomonori 
3965773642d9SDouglas Gilbert 	if (sdebug_verbose)
3966c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
39678dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3968b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3969b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3970b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3971f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3972b01f6f83SDouglas Gilbert 		if (devip == NULL)
39738dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3974f46eb0e9SDouglas Gilbert 	}
3975c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
3976773642d9SDouglas Gilbert 	if (sdebug_no_uld)
397778d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
39789b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
39798dea0d02SFUJITA Tomonori 	return 0;
39808dea0d02SFUJITA Tomonori }
39818dea0d02SFUJITA Tomonori 
39828dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
39838dea0d02SFUJITA Tomonori {
39848dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
39858dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
39868dea0d02SFUJITA Tomonori 
3987773642d9SDouglas Gilbert 	if (sdebug_verbose)
3988c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
39898dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39908dea0d02SFUJITA Tomonori 	if (devip) {
399125985edcSLucas De Marchi 		/* make this slot available for re-use */
3992c2248fc9SDouglas Gilbert 		devip->used = false;
39938dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
39948dea0d02SFUJITA Tomonori 	}
39958dea0d02SFUJITA Tomonori }
39968dea0d02SFUJITA Tomonori 
399710bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
399810bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
3999c4837394SDouglas Gilbert {
4000c4837394SDouglas Gilbert 	if (!sd_dp)
4001c4837394SDouglas Gilbert 		return;
400210bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
4003c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
400410bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
4005c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
4006c4837394SDouglas Gilbert }
4007c4837394SDouglas Gilbert 
4008a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
4009a10bc12aSDouglas Gilbert    returns false */
4010a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
40118dea0d02SFUJITA Tomonori {
40128dea0d02SFUJITA Tomonori 	unsigned long iflags;
4013c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
401410bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4015c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
40168dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4017cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4018a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40198dea0d02SFUJITA Tomonori 
4020c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4021c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4022773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
4023cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
4024cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
4025cbf67842SDouglas Gilbert 			qmax = r_qmax;
4026cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
4027c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4028c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4029a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
4030a10bc12aSDouglas Gilbert 					continue;
4031c4837394SDouglas Gilbert 				/* found */
4032db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4033db525fceSDouglas Gilbert 						cmnd->device->hostdata;
4034db525fceSDouglas Gilbert 				if (devip)
4035db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4036db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4037a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
403810bde980SDouglas Gilbert 				if (sd_dp) {
403910bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
404010bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
404110bde980SDouglas Gilbert 				} else
404210bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4043c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
404410bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4045c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4046a10bc12aSDouglas Gilbert 				return true;
40478dea0d02SFUJITA Tomonori 			}
4048cbf67842SDouglas Gilbert 		}
4049c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4050c4837394SDouglas Gilbert 	}
4051a10bc12aSDouglas Gilbert 	return false;
40528dea0d02SFUJITA Tomonori }
40538dea0d02SFUJITA Tomonori 
4054a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
40558dea0d02SFUJITA Tomonori static void stop_all_queued(void)
40568dea0d02SFUJITA Tomonori {
40578dea0d02SFUJITA Tomonori 	unsigned long iflags;
4058c4837394SDouglas Gilbert 	int j, k;
405910bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4060c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
40618dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4062cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4063a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40648dea0d02SFUJITA Tomonori 
4065c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4066c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4067c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4068c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4069c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4070c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
4071a10bc12aSDouglas Gilbert 					continue;
4072db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4073db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
4074db525fceSDouglas Gilbert 				if (devip)
4075db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4076db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4077a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
407810bde980SDouglas Gilbert 				if (sd_dp) {
407910bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
408010bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
408110bde980SDouglas Gilbert 				} else
408210bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4083c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
408410bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4085c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4086c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
40878dea0d02SFUJITA Tomonori 			}
40888dea0d02SFUJITA Tomonori 		}
4089c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4090c4837394SDouglas Gilbert 	}
4091cbf67842SDouglas Gilbert }
4092cbf67842SDouglas Gilbert 
4093cbf67842SDouglas Gilbert /* Free queued command memory on heap */
4094cbf67842SDouglas Gilbert static void free_all_queued(void)
4095cbf67842SDouglas Gilbert {
4096c4837394SDouglas Gilbert 	int j, k;
4097c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4098cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4099cbf67842SDouglas Gilbert 
4100c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4101c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4102c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
4103a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
4104a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
4105cbf67842SDouglas Gilbert 		}
41061da177e4SLinus Torvalds 	}
4107c4837394SDouglas Gilbert }
41081da177e4SLinus Torvalds 
41091da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
41101da177e4SLinus Torvalds {
4111a10bc12aSDouglas Gilbert 	bool ok;
4112a10bc12aSDouglas Gilbert 
41131da177e4SLinus Torvalds 	++num_aborts;
4114cbf67842SDouglas Gilbert 	if (SCpnt) {
4115a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
4116a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4117a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4118a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
4119a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
4120cbf67842SDouglas Gilbert 	}
41211da177e4SLinus Torvalds 	return SUCCESS;
41221da177e4SLinus Torvalds }
41231da177e4SLinus Torvalds 
41241da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
41251da177e4SLinus Torvalds {
41261da177e4SLinus Torvalds 	++num_dev_resets;
4127cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
4128cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
4129f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
4130f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
4131cbf67842SDouglas Gilbert 
4132773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4133cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
41341da177e4SLinus Torvalds 		if (devip)
4135cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
41361da177e4SLinus Torvalds 	}
41371da177e4SLinus Torvalds 	return SUCCESS;
41381da177e4SLinus Torvalds }
41391da177e4SLinus Torvalds 
4140cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4141cbf67842SDouglas Gilbert {
4142cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
4143cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4144cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
4145cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
4146cbf67842SDouglas Gilbert 	int k = 0;
4147cbf67842SDouglas Gilbert 
4148cbf67842SDouglas Gilbert 	++num_target_resets;
4149cbf67842SDouglas Gilbert 	if (!SCpnt)
4150cbf67842SDouglas Gilbert 		goto lie;
4151cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4152cbf67842SDouglas Gilbert 	if (!sdp)
4153cbf67842SDouglas Gilbert 		goto lie;
4154773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4155cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4156cbf67842SDouglas Gilbert 	hp = sdp->host;
4157cbf67842SDouglas Gilbert 	if (!hp)
4158cbf67842SDouglas Gilbert 		goto lie;
4159cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4160cbf67842SDouglas Gilbert 	if (sdbg_host) {
4161cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
4162cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
4163cbf67842SDouglas Gilbert 				    dev_list)
4164cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
4165cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4166cbf67842SDouglas Gilbert 				++k;
4167cbf67842SDouglas Gilbert 			}
4168cbf67842SDouglas Gilbert 	}
4169773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4170cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4171cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
4172cbf67842SDouglas Gilbert lie:
4173cbf67842SDouglas Gilbert 	return SUCCESS;
4174cbf67842SDouglas Gilbert }
4175cbf67842SDouglas Gilbert 
41761da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
41771da177e4SLinus Torvalds {
41781da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4179cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
41801da177e4SLinus Torvalds 	struct scsi_device *sdp;
41811da177e4SLinus Torvalds 	struct Scsi_Host *hp;
4182cbf67842SDouglas Gilbert 	int k = 0;
41831da177e4SLinus Torvalds 
41841da177e4SLinus Torvalds 	++num_bus_resets;
4185cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
4186cbf67842SDouglas Gilbert 		goto lie;
4187cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4188773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4189cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4190cbf67842SDouglas Gilbert 	hp = sdp->host;
4191cbf67842SDouglas Gilbert 	if (hp) {
4192d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
41931da177e4SLinus Torvalds 		if (sdbg_host) {
4194cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
41951da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
4196cbf67842SDouglas Gilbert 					    dev_list) {
4197cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4198cbf67842SDouglas Gilbert 				++k;
41991da177e4SLinus Torvalds 			}
42001da177e4SLinus Torvalds 		}
4201cbf67842SDouglas Gilbert 	}
4202773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4203cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4204cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
4205cbf67842SDouglas Gilbert lie:
42061da177e4SLinus Torvalds 	return SUCCESS;
42071da177e4SLinus Torvalds }
42081da177e4SLinus Torvalds 
42091da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
42101da177e4SLinus Torvalds {
42111da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4212cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4213cbf67842SDouglas Gilbert 	int k = 0;
42141da177e4SLinus Torvalds 
42151da177e4SLinus Torvalds 	++num_host_resets;
4216773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4217cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
42181da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
42191da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
4220cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
4221cbf67842SDouglas Gilbert 				    dev_list) {
4222cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4223cbf67842SDouglas Gilbert 			++k;
4224cbf67842SDouglas Gilbert 		}
42251da177e4SLinus Torvalds 	}
42261da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
42271da177e4SLinus Torvalds 	stop_all_queued();
4228773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4229cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
4230cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
42311da177e4SLinus Torvalds 	return SUCCESS;
42321da177e4SLinus Torvalds }
42331da177e4SLinus Torvalds 
4234f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
42355f2578e5SFUJITA Tomonori 				      unsigned long store_size)
42361da177e4SLinus Torvalds {
42371da177e4SLinus Torvalds 	struct partition *pp;
42381da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
42391da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
42401da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
42411da177e4SLinus Torvalds 
42421da177e4SLinus Torvalds 	/* assume partition table already zeroed */
4243773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
42441da177e4SLinus Torvalds 		return;
4245773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4246773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
4247c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
42481da177e4SLinus Torvalds 	}
4249c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
42501da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4251773642d9SDouglas Gilbert 			   / sdebug_num_parts;
42521da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
42531da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4254773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
42551da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
42561da177e4SLinus Torvalds 			    * heads_by_sects;
4257773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4258773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
42591da177e4SLinus Torvalds 
42601da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
42611da177e4SLinus Torvalds 	ramp[511] = 0xAA;
42621da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
42631da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
42641da177e4SLinus Torvalds 		start_sec = starts[k];
42651da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
42661da177e4SLinus Torvalds 		pp->boot_ind = 0;
42671da177e4SLinus Torvalds 
42681da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
42691da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
42701da177e4SLinus Torvalds 			   / sdebug_sectors_per;
42711da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
42721da177e4SLinus Torvalds 
42731da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
42741da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
42751da177e4SLinus Torvalds 			       / sdebug_sectors_per;
42761da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
42771da177e4SLinus Torvalds 
4278150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4279150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
42801da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
42811da177e4SLinus Torvalds 	}
42821da177e4SLinus Torvalds }
42831da177e4SLinus Torvalds 
4284c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4285c4837394SDouglas Gilbert {
4286c4837394SDouglas Gilbert 	int j;
4287c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4288c4837394SDouglas Gilbert 
4289c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4290c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4291c4837394SDouglas Gilbert }
4292c4837394SDouglas Gilbert 
4293c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4294c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4295c4837394SDouglas Gilbert  */
4296c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4297c4837394SDouglas Gilbert {
4298c4837394SDouglas Gilbert 	int count, modulo;
4299c4837394SDouglas Gilbert 
4300c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4301c4837394SDouglas Gilbert 	if (modulo < 2)
4302c4837394SDouglas Gilbert 		return;
4303c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4304c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4305c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4306c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4307c4837394SDouglas Gilbert }
4308c4837394SDouglas Gilbert 
4309c4837394SDouglas Gilbert static void clear_queue_stats(void)
4310c4837394SDouglas Gilbert {
4311c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4312c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4313c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4314c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4315c4837394SDouglas Gilbert }
4316c4837394SDouglas Gilbert 
4317c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4318c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4319c4837394SDouglas Gilbert {
4320f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4321f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
4322f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
4323f9ba7af8SMartin Wilck 				= sqcp->inj_dif
43247382f9d8SDouglas Gilbert 				= sqcp->inj_dix = sqcp->inj_short
43257382f9d8SDouglas Gilbert 				= sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
4326c4837394SDouglas Gilbert 		return;
4327f9ba7af8SMartin Wilck 	}
4328c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4329c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4330c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4331c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4332c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
43337ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
43347382f9d8SDouglas Gilbert 	sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
4335c4837394SDouglas Gilbert }
4336c4837394SDouglas Gilbert 
4337c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4338c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4339c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4340c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4341c4837394SDouglas Gilbert  */
4342fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4343f66b8517SMartin Wilck 			 int scsi_result,
4344f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
4345f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
4346f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
43471da177e4SLinus Torvalds {
4348cbf67842SDouglas Gilbert 	unsigned long iflags;
4349cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4350c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4351c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4352299b6c07STomas Winkler 	struct scsi_device *sdp;
4353a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
43541da177e4SLinus Torvalds 
4355b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4356b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4357f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4358f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
43591da177e4SLinus Torvalds 	}
4360299b6c07STomas Winkler 	sdp = cmnd->device;
4361299b6c07STomas Winkler 
4362cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4363cd62b7daSDouglas Gilbert 		goto respond_in_thread;
43641da177e4SLinus Torvalds 
4365cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4366c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4367c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4368c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4369c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4370c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4371c4837394SDouglas Gilbert 	}
4372cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4373cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4374cbf67842SDouglas Gilbert 	inject = 0;
4375f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4376cd62b7daSDouglas Gilbert 		if (scsi_result) {
4377c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4378cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4379cd62b7daSDouglas Gilbert 		} else
4380cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4381c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4382773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4383f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4384cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4385cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4386773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4387cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4388cbf67842SDouglas Gilbert 			inject = 1;
4389cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
43901da177e4SLinus Torvalds 		}
4391cbf67842SDouglas Gilbert 	}
4392cbf67842SDouglas Gilbert 
4393c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4394f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4395c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4396cd62b7daSDouglas Gilbert 		if (scsi_result)
4397cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4398773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4399cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4400773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4401cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4402cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4403773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4404cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4405cbf67842SDouglas Gilbert 						    "report: host busy"));
4406cd62b7daSDouglas Gilbert 		if (scsi_result)
4407cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4408cd62b7daSDouglas Gilbert 		else
4409cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
44101da177e4SLinus Torvalds 	}
4411c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4412cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4413c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
44141da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4415c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4416a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4417c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4418c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4419c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
442010bde980SDouglas Gilbert 	if (sd_dp == NULL) {
442110bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
442210bde980SDouglas Gilbert 		if (sd_dp == NULL)
442310bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
442410bde980SDouglas Gilbert 	}
4425f66b8517SMartin Wilck 
4426f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4427f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
4428f66b8517SMartin Wilck 		/*
4429f66b8517SMartin Wilck 		 * This is the F_DELAY_OVERR case. No delay.
4430f66b8517SMartin Wilck 		 */
4431f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
4432f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
4433f66b8517SMartin Wilck 	}
4434f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4435f66b8517SMartin Wilck 		cmnd->result = scsi_result;
4436f66b8517SMartin Wilck 
4437f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
4438f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4439f66b8517SMartin Wilck 			    __func__, cmnd->result);
4440f66b8517SMartin Wilck 
444110bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
4442b333a819SDouglas Gilbert 		ktime_t kt;
4443cbf67842SDouglas Gilbert 
4444b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
444513f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4446b333a819SDouglas Gilbert 		} else
444710bde980SDouglas Gilbert 			kt = ndelay;
444810bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
444910bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
4450a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4451a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4452c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4453a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4454c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4455c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4456cbf67842SDouglas Gilbert 		}
4457c4837394SDouglas Gilbert 		if (sdebug_statistics)
4458c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
445910bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
4460c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4461c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
446210bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
446310bde980SDouglas Gilbert 			sd_dp->init_wq = true;
4464a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4465c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4466c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4467a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4468cbf67842SDouglas Gilbert 		}
4469c4837394SDouglas Gilbert 		if (sdebug_statistics)
4470c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
447110bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
44727382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort))
44737382f9d8SDouglas Gilbert 			sd_dp->aborted = true;
4474a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
44757382f9d8SDouglas Gilbert 		if (unlikely(sqcp->inj_cmd_abort)) {
44767382f9d8SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
44777382f9d8SDouglas Gilbert 				    cmnd->request->tag);
44787382f9d8SDouglas Gilbert 			blk_abort_request(cmnd->request);
44797382f9d8SDouglas Gilbert 		}
4480cbf67842SDouglas Gilbert 	}
4481f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4482f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4483cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4484cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4485cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4486cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
44871da177e4SLinus Torvalds 	return 0;
4488cd62b7daSDouglas Gilbert 
4489cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4490f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4491f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
4492f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4493cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
4494cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4495cd62b7daSDouglas Gilbert 	return 0;
44961da177e4SLinus Torvalds }
4497cbf67842SDouglas Gilbert 
449823183910SDouglas Gilbert /* Note: The following macros create attribute files in the
449923183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
450023183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
450123183910SDouglas Gilbert    as it can when the corresponding attribute in the
450223183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
450323183910SDouglas Gilbert  */
4504773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4505773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
45069b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4507773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4508c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4509773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4510773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4511773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4512773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4513773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4514773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4515773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4516773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4517e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4518e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4519e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4520e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4521e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4522e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4523773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4524773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4525773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4526773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4527773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4528773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4529773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4530d9da891aSLaurence Oberman module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4531d9da891aSLaurence Oberman module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
4532773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4533773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4534773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4535773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4536773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4537773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4538773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4539773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
454086e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4541773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4542773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4543773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4544773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4545c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4546773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4547c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4548773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4549773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4550773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4551773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4552773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
455309ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4554773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
455523183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4556773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
45575b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
45581da177e4SLinus Torvalds 
45591da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
45601da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
45611da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4562b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
45631da177e4SLinus Torvalds 
45641da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
45655b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
45669b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
45670759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4568cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4569c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
45705b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
45715b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4572c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4573beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
457423183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
45755b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4576185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4577e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4578e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
45799b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
45809b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
45815b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
45825b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
45835b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4584760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4585760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
45865b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4587c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4588cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4589d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4590d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
4591cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4592c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
459378d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
45941da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4595c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
459632c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
45976f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
45985b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
459986e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
46001da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4601d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4602760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4603ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4604c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4605c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4606c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
46075b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
46085b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
46096014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
46106014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
461109ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
461209ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4613c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
46145b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
46155b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
46161da177e4SLinus Torvalds 
4617760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4618760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
46191da177e4SLinus Torvalds 
46201da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
46211da177e4SLinus Torvalds {
4622c4837394SDouglas Gilbert 	int k;
4623c4837394SDouglas Gilbert 
4624760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4625760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4626760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4627c4837394SDouglas Gilbert 		return sdebug_info;
4628760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4629760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4630760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4631760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
46321da177e4SLinus Torvalds 	return sdebug_info;
46331da177e4SLinus Torvalds }
46341da177e4SLinus Torvalds 
4635cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4636fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4637fd32119bSDouglas Gilbert 				 int length)
46381da177e4SLinus Torvalds {
46391da177e4SLinus Torvalds 	char arr[16];
4640c8ed555aSAl Viro 	int opts;
46411da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
46421da177e4SLinus Torvalds 
46431da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
46441da177e4SLinus Torvalds 		return -EACCES;
46451da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
46461da177e4SLinus Torvalds 	arr[minLen] = '\0';
4647c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
46481da177e4SLinus Torvalds 		return -EINVAL;
4649773642d9SDouglas Gilbert 	sdebug_opts = opts;
4650773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4651773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4652773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4653c4837394SDouglas Gilbert 		tweak_cmnd_count();
46541da177e4SLinus Torvalds 	return length;
46551da177e4SLinus Torvalds }
4656c8ed555aSAl Viro 
4657cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4658cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4659cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4660c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4661c8ed555aSAl Viro {
4662c4837394SDouglas Gilbert 	int f, j, l;
4663c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4664cbf67842SDouglas Gilbert 
4665c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4666c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4667c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4668c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4669c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4670c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4671c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4672c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4673c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4674c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4675c4837394SDouglas Gilbert 		   num_aborts);
4676c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4677c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4678c4837394SDouglas Gilbert 		   num_host_resets);
4679c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4680c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4681458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4682458df78bSBart Van Assche 		   sdebug_statistics);
4683c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4684c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4685c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4686c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4687c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4688cbf67842SDouglas Gilbert 
4689c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4690c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4691c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4692c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4693773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4694c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4695c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4696c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4697c4837394SDouglas Gilbert 		}
4698cbf67842SDouglas Gilbert 	}
4699c8ed555aSAl Viro 	return 0;
47001da177e4SLinus Torvalds }
47011da177e4SLinus Torvalds 
470282069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
47031da177e4SLinus Torvalds {
4704c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
47051da177e4SLinus Torvalds }
4706c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4707c4837394SDouglas Gilbert  * of delay is jiffies.
4708c4837394SDouglas Gilbert  */
470982069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
471082069379SAkinobu Mita 			   size_t count)
47111da177e4SLinus Torvalds {
4712c2206098SDouglas Gilbert 	int jdelay, res;
47131da177e4SLinus Torvalds 
4714b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4715cbf67842SDouglas Gilbert 		res = count;
4716c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4717c4837394SDouglas Gilbert 			int j, k;
4718c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4719cbf67842SDouglas Gilbert 
4720c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4721c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4722c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4723c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4724c4837394SDouglas Gilbert 						   sdebug_max_queue);
4725c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4726c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4727c4837394SDouglas Gilbert 					break;
4728c4837394SDouglas Gilbert 				}
4729c4837394SDouglas Gilbert 			}
4730c4837394SDouglas Gilbert 			if (res > 0) {
4731c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4732773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
47331da177e4SLinus Torvalds 			}
4734c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4735cbf67842SDouglas Gilbert 		}
4736cbf67842SDouglas Gilbert 		return res;
47371da177e4SLinus Torvalds 	}
47381da177e4SLinus Torvalds 	return -EINVAL;
47391da177e4SLinus Torvalds }
474082069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
47411da177e4SLinus Torvalds 
4742cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4743cbf67842SDouglas Gilbert {
4744773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4745cbf67842SDouglas Gilbert }
4746cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4747c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4748cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4749cbf67842SDouglas Gilbert 			    size_t count)
4750cbf67842SDouglas Gilbert {
4751c4837394SDouglas Gilbert 	int ndelay, res;
4752cbf67842SDouglas Gilbert 
4753cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4754c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4755cbf67842SDouglas Gilbert 		res = count;
4756773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4757c4837394SDouglas Gilbert 			int j, k;
4758c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4759c4837394SDouglas Gilbert 
4760c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4761c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4762c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4763c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4764c4837394SDouglas Gilbert 						   sdebug_max_queue);
4765c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4766c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4767c4837394SDouglas Gilbert 					break;
4768c4837394SDouglas Gilbert 				}
4769c4837394SDouglas Gilbert 			}
4770c4837394SDouglas Gilbert 			if (res > 0) {
4771773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4772c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4773c2206098SDouglas Gilbert 							: DEF_JDELAY;
4774cbf67842SDouglas Gilbert 			}
4775c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4776cbf67842SDouglas Gilbert 		}
4777cbf67842SDouglas Gilbert 		return res;
4778cbf67842SDouglas Gilbert 	}
4779cbf67842SDouglas Gilbert 	return -EINVAL;
4780cbf67842SDouglas Gilbert }
4781cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4782cbf67842SDouglas Gilbert 
478382069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
47841da177e4SLinus Torvalds {
4785773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
47861da177e4SLinus Torvalds }
47871da177e4SLinus Torvalds 
478882069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
478982069379SAkinobu Mita 			  size_t count)
47901da177e4SLinus Torvalds {
47911da177e4SLinus Torvalds 	int opts;
47921da177e4SLinus Torvalds 	char work[20];
47931da177e4SLinus Torvalds 
47949a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
47959a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
47969a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
47971da177e4SLinus Torvalds 				goto opts_done;
47981da177e4SLinus Torvalds 		} else {
47999a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
48001da177e4SLinus Torvalds 				goto opts_done;
48011da177e4SLinus Torvalds 		}
48021da177e4SLinus Torvalds 	}
48031da177e4SLinus Torvalds 	return -EINVAL;
48041da177e4SLinus Torvalds opts_done:
4805773642d9SDouglas Gilbert 	sdebug_opts = opts;
4806773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4807773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4808c4837394SDouglas Gilbert 	tweak_cmnd_count();
48091da177e4SLinus Torvalds 	return count;
48101da177e4SLinus Torvalds }
481182069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
48121da177e4SLinus Torvalds 
481382069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
48141da177e4SLinus Torvalds {
4815773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
48161da177e4SLinus Torvalds }
481782069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
481882069379SAkinobu Mita 			   size_t count)
48191da177e4SLinus Torvalds {
48201da177e4SLinus Torvalds 	int n;
48211da177e4SLinus Torvalds 
48221da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4823773642d9SDouglas Gilbert 		sdebug_ptype = n;
48241da177e4SLinus Torvalds 		return count;
48251da177e4SLinus Torvalds 	}
48261da177e4SLinus Torvalds 	return -EINVAL;
48271da177e4SLinus Torvalds }
482882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
48291da177e4SLinus Torvalds 
483082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
48311da177e4SLinus Torvalds {
4832773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
48331da177e4SLinus Torvalds }
483482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
483582069379SAkinobu Mita 			    size_t count)
48361da177e4SLinus Torvalds {
48371da177e4SLinus Torvalds 	int n;
48381da177e4SLinus Torvalds 
48391da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4840773642d9SDouglas Gilbert 		sdebug_dsense = n;
48411da177e4SLinus Torvalds 		return count;
48421da177e4SLinus Torvalds 	}
48431da177e4SLinus Torvalds 	return -EINVAL;
48441da177e4SLinus Torvalds }
484582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
48461da177e4SLinus Torvalds 
484782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
484823183910SDouglas Gilbert {
4849773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
485023183910SDouglas Gilbert }
485182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
485282069379SAkinobu Mita 			     size_t count)
485323183910SDouglas Gilbert {
485423183910SDouglas Gilbert 	int n;
485523183910SDouglas Gilbert 
485623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4857cbf67842SDouglas Gilbert 		n = (n > 0);
4858773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4859773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4860cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4861cbf67842SDouglas Gilbert 				unsigned long sz =
4862773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4863cbf67842SDouglas Gilbert 					1048576;
4864cbf67842SDouglas Gilbert 
48657382f9d8SDouglas Gilbert 				fake_storep = vzalloc(sz);
4866cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4867c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4868cbf67842SDouglas Gilbert 					return -ENOMEM;
4869cbf67842SDouglas Gilbert 				}
4870cbf67842SDouglas Gilbert 			}
4871773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4872cbf67842SDouglas Gilbert 		}
487323183910SDouglas Gilbert 		return count;
487423183910SDouglas Gilbert 	}
487523183910SDouglas Gilbert 	return -EINVAL;
487623183910SDouglas Gilbert }
487782069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
487823183910SDouglas Gilbert 
487982069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4880c65b1445SDouglas Gilbert {
4881773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4882c65b1445SDouglas Gilbert }
488382069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
488482069379SAkinobu Mita 			      size_t count)
4885c65b1445SDouglas Gilbert {
4886c65b1445SDouglas Gilbert 	int n;
4887c65b1445SDouglas Gilbert 
4888c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4889773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4890c65b1445SDouglas Gilbert 		return count;
4891c65b1445SDouglas Gilbert 	}
4892c65b1445SDouglas Gilbert 	return -EINVAL;
4893c65b1445SDouglas Gilbert }
489482069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4895c65b1445SDouglas Gilbert 
489682069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
48971da177e4SLinus Torvalds {
4898773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
48991da177e4SLinus Torvalds }
490082069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
490182069379SAkinobu Mita 			      size_t count)
49021da177e4SLinus Torvalds {
49031da177e4SLinus Torvalds 	int n;
49041da177e4SLinus Torvalds 
49051da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4906773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
49071da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
49081da177e4SLinus Torvalds 		return count;
49091da177e4SLinus Torvalds 	}
49101da177e4SLinus Torvalds 	return -EINVAL;
49111da177e4SLinus Torvalds }
491282069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
49131da177e4SLinus Torvalds 
491482069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
49151da177e4SLinus Torvalds {
4916773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
49171da177e4SLinus Torvalds }
491882069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
49191da177e4SLinus Torvalds 
492082069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
49211da177e4SLinus Torvalds {
4922773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
49231da177e4SLinus Torvalds }
492482069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
49251da177e4SLinus Torvalds 
492682069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
49271da177e4SLinus Torvalds {
4928773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
49291da177e4SLinus Torvalds }
493082069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
493182069379SAkinobu Mita 			       size_t count)
49321da177e4SLinus Torvalds {
49331da177e4SLinus Torvalds 	int nth;
49341da177e4SLinus Torvalds 
49351da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4936773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4937c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4938c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4939c4837394SDouglas Gilbert 			sdebug_statistics = true;
4940c4837394SDouglas Gilbert 		}
4941c4837394SDouglas Gilbert 		tweak_cmnd_count();
49421da177e4SLinus Torvalds 		return count;
49431da177e4SLinus Torvalds 	}
49441da177e4SLinus Torvalds 	return -EINVAL;
49451da177e4SLinus Torvalds }
494682069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
49471da177e4SLinus Torvalds 
494882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
49491da177e4SLinus Torvalds {
4950773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
49511da177e4SLinus Torvalds }
495282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
495382069379SAkinobu Mita 			      size_t count)
49541da177e4SLinus Torvalds {
49551da177e4SLinus Torvalds 	int n;
495619c8ead7SEwan D. Milne 	bool changed;
49571da177e4SLinus Torvalds 
49581da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
49598d039e22SDouglas Gilbert 		if (n > 256) {
49608d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
49618d039e22SDouglas Gilbert 			return -EINVAL;
49628d039e22SDouglas Gilbert 		}
4963773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4964773642d9SDouglas Gilbert 		sdebug_max_luns = n;
49651da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4966773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
496719c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
496819c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
496919c8ead7SEwan D. Milne 
497019c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
497119c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
497219c8ead7SEwan D. Milne 					    host_list) {
497319c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
497419c8ead7SEwan D. Milne 						    dev_list) {
497519c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
497619c8ead7SEwan D. Milne 						dp->uas_bm);
497719c8ead7SEwan D. Milne 				}
497819c8ead7SEwan D. Milne 			}
497919c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
498019c8ead7SEwan D. Milne 		}
49811da177e4SLinus Torvalds 		return count;
49821da177e4SLinus Torvalds 	}
49831da177e4SLinus Torvalds 	return -EINVAL;
49841da177e4SLinus Torvalds }
498582069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
49861da177e4SLinus Torvalds 
498782069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
498878d4e5a0SDouglas Gilbert {
4989773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
499078d4e5a0SDouglas Gilbert }
4991cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4992cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
499382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
499482069379SAkinobu Mita 			       size_t count)
499578d4e5a0SDouglas Gilbert {
4996c4837394SDouglas Gilbert 	int j, n, k, a;
4997c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
499878d4e5a0SDouglas Gilbert 
499978d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
5000c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
5001c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
5002c4837394SDouglas Gilbert 		k = 0;
5003c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5004c4837394SDouglas Gilbert 		     ++j, ++sqp) {
5005c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
5006c4837394SDouglas Gilbert 			if (a > k)
5007c4837394SDouglas Gilbert 				k = a;
5008c4837394SDouglas Gilbert 		}
5009773642d9SDouglas Gilbert 		sdebug_max_queue = n;
5010c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
5011cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
5012cbf67842SDouglas Gilbert 		else if (k >= n)
5013cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
5014cbf67842SDouglas Gilbert 		else
5015cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
5016c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
501778d4e5a0SDouglas Gilbert 		return count;
501878d4e5a0SDouglas Gilbert 	}
501978d4e5a0SDouglas Gilbert 	return -EINVAL;
502078d4e5a0SDouglas Gilbert }
502182069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
502278d4e5a0SDouglas Gilbert 
502382069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
502478d4e5a0SDouglas Gilbert {
5025773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
502678d4e5a0SDouglas Gilbert }
502782069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
502878d4e5a0SDouglas Gilbert 
502982069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
50301da177e4SLinus Torvalds {
5031773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
50321da177e4SLinus Torvalds }
503382069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
50341da177e4SLinus Torvalds 
503582069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
5036c65b1445SDouglas Gilbert {
5037773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
5038c65b1445SDouglas Gilbert }
503982069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
504082069379SAkinobu Mita 				size_t count)
5041c65b1445SDouglas Gilbert {
5042c65b1445SDouglas Gilbert 	int n;
50430d01c5dfSDouglas Gilbert 	bool changed;
5044c65b1445SDouglas Gilbert 
5045c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5046773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
5047773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
504828898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
50490d01c5dfSDouglas Gilbert 		if (changed) {
50500d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
50510d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
505228898873SFUJITA Tomonori 
50534bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
50540d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
50550d01c5dfSDouglas Gilbert 					    host_list) {
50560d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
50570d01c5dfSDouglas Gilbert 						    dev_list) {
50580d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
50590d01c5dfSDouglas Gilbert 						dp->uas_bm);
50600d01c5dfSDouglas Gilbert 				}
50610d01c5dfSDouglas Gilbert 			}
50624bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
50630d01c5dfSDouglas Gilbert 		}
5064c65b1445SDouglas Gilbert 		return count;
5065c65b1445SDouglas Gilbert 	}
5066c65b1445SDouglas Gilbert 	return -EINVAL;
5067c65b1445SDouglas Gilbert }
506882069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
5069c65b1445SDouglas Gilbert 
507082069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
50711da177e4SLinus Torvalds {
5072773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
50731da177e4SLinus Torvalds }
50741da177e4SLinus Torvalds 
5075fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
5076fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
5077fd32119bSDouglas Gilbert 
507882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
507982069379SAkinobu Mita 			      size_t count)
50801da177e4SLinus Torvalds {
50811da177e4SLinus Torvalds 	int delta_hosts;
50821da177e4SLinus Torvalds 
5083f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
50841da177e4SLinus Torvalds 		return -EINVAL;
50851da177e4SLinus Torvalds 	if (delta_hosts > 0) {
50861da177e4SLinus Torvalds 		do {
50871da177e4SLinus Torvalds 			sdebug_add_adapter();
50881da177e4SLinus Torvalds 		} while (--delta_hosts);
50891da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
50901da177e4SLinus Torvalds 		do {
50911da177e4SLinus Torvalds 			sdebug_remove_adapter();
50921da177e4SLinus Torvalds 		} while (++delta_hosts);
50931da177e4SLinus Torvalds 	}
50941da177e4SLinus Torvalds 	return count;
50951da177e4SLinus Torvalds }
509682069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
50971da177e4SLinus Torvalds 
509882069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
509923183910SDouglas Gilbert {
5100773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
510123183910SDouglas Gilbert }
510282069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
510382069379SAkinobu Mita 				    size_t count)
510423183910SDouglas Gilbert {
510523183910SDouglas Gilbert 	int n;
510623183910SDouglas Gilbert 
510723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5108773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
510923183910SDouglas Gilbert 		return count;
511023183910SDouglas Gilbert 	}
511123183910SDouglas Gilbert 	return -EINVAL;
511223183910SDouglas Gilbert }
511382069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
511423183910SDouglas Gilbert 
5115c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5116c4837394SDouglas Gilbert {
5117c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5118c4837394SDouglas Gilbert }
5119c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5120c4837394SDouglas Gilbert 				size_t count)
5121c4837394SDouglas Gilbert {
5122c4837394SDouglas Gilbert 	int n;
5123c4837394SDouglas Gilbert 
5124c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5125c4837394SDouglas Gilbert 		if (n > 0)
5126c4837394SDouglas Gilbert 			sdebug_statistics = true;
5127c4837394SDouglas Gilbert 		else {
5128c4837394SDouglas Gilbert 			clear_queue_stats();
5129c4837394SDouglas Gilbert 			sdebug_statistics = false;
5130c4837394SDouglas Gilbert 		}
5131c4837394SDouglas Gilbert 		return count;
5132c4837394SDouglas Gilbert 	}
5133c4837394SDouglas Gilbert 	return -EINVAL;
5134c4837394SDouglas Gilbert }
5135c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
5136c4837394SDouglas Gilbert 
513782069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
5138597136abSMartin K. Petersen {
5139773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
5140597136abSMartin K. Petersen }
514182069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
5142597136abSMartin K. Petersen 
5143c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5144c4837394SDouglas Gilbert {
5145c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5146c4837394SDouglas Gilbert }
5147c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
5148c4837394SDouglas Gilbert 
514982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
5150c6a44287SMartin K. Petersen {
5151773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
5152c6a44287SMartin K. Petersen }
515382069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
5154c6a44287SMartin K. Petersen 
515582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
5156c6a44287SMartin K. Petersen {
5157773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
5158c6a44287SMartin K. Petersen }
515982069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
5160c6a44287SMartin K. Petersen 
516182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
5162c6a44287SMartin K. Petersen {
5163773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
5164c6a44287SMartin K. Petersen }
516582069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
5166c6a44287SMartin K. Petersen 
516782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
5168c6a44287SMartin K. Petersen {
5169773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
5170c6a44287SMartin K. Petersen }
517182069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
5172c6a44287SMartin K. Petersen 
517382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
517444d92694SMartin K. Petersen {
517544d92694SMartin K. Petersen 	ssize_t count;
517644d92694SMartin K. Petersen 
51775b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
517844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
517944d92694SMartin K. Petersen 				 sdebug_store_sectors);
518044d92694SMartin K. Petersen 
5181c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5182c7badc90STejun Heo 			  (int)map_size, map_storep);
518344d92694SMartin K. Petersen 	buf[count++] = '\n';
5184c7badc90STejun Heo 	buf[count] = '\0';
518544d92694SMartin K. Petersen 
518644d92694SMartin K. Petersen 	return count;
518744d92694SMartin K. Petersen }
518882069379SAkinobu Mita static DRIVER_ATTR_RO(map);
518944d92694SMartin K. Petersen 
519082069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
5191d986788bSMartin Pitt {
5192773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
5193d986788bSMartin Pitt }
519482069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
519582069379SAkinobu Mita 			       size_t count)
5196d986788bSMartin Pitt {
5197d986788bSMartin Pitt 	int n;
5198d986788bSMartin Pitt 
5199d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5200773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
5201d986788bSMartin Pitt 		return count;
5202d986788bSMartin Pitt 	}
5203d986788bSMartin Pitt 	return -EINVAL;
5204d986788bSMartin Pitt }
520582069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
5206d986788bSMartin Pitt 
5207cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5208cbf67842SDouglas Gilbert {
5209773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
5210cbf67842SDouglas Gilbert }
5211185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
5212cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5213cbf67842SDouglas Gilbert 			       size_t count)
5214cbf67842SDouglas Gilbert {
5215185dd232SDouglas Gilbert 	int n;
5216cbf67842SDouglas Gilbert 
5217cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5218185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
5219185dd232SDouglas Gilbert 		return count;
5220cbf67842SDouglas Gilbert 	}
5221cbf67842SDouglas Gilbert 	return -EINVAL;
5222cbf67842SDouglas Gilbert }
5223cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
5224cbf67842SDouglas Gilbert 
5225c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
5226c2248fc9SDouglas Gilbert {
5227773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
5228c2248fc9SDouglas Gilbert }
5229c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5230c2248fc9SDouglas Gilbert 			    size_t count)
5231c2248fc9SDouglas Gilbert {
5232c2248fc9SDouglas Gilbert 	int n;
5233c2248fc9SDouglas Gilbert 
5234c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5235773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
5236c2248fc9SDouglas Gilbert 		return count;
5237c2248fc9SDouglas Gilbert 	}
5238c2248fc9SDouglas Gilbert 	return -EINVAL;
5239c2248fc9SDouglas Gilbert }
5240c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
5241c2248fc9SDouglas Gilbert 
524209ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
524309ba24c1SDouglas Gilbert {
524409ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
524509ba24c1SDouglas Gilbert }
524609ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
524709ba24c1SDouglas Gilbert 
52489b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
52499b760fd8SDouglas Gilbert {
52509b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
52519b760fd8SDouglas Gilbert }
52529b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
52539b760fd8SDouglas Gilbert 			     size_t count)
52549b760fd8SDouglas Gilbert {
52559b760fd8SDouglas Gilbert 	int ret, n;
52569b760fd8SDouglas Gilbert 
52579b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
52589b760fd8SDouglas Gilbert 	if (ret)
52599b760fd8SDouglas Gilbert 		return ret;
52609b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
52619b760fd8SDouglas Gilbert 	all_config_cdb_len();
52629b760fd8SDouglas Gilbert 	return count;
52639b760fd8SDouglas Gilbert }
52649b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
52659b760fd8SDouglas Gilbert 
5266cbf67842SDouglas Gilbert 
526782069379SAkinobu Mita /* Note: The following array creates attribute files in the
526823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
526923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
527023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
527123183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
527223183910SDouglas Gilbert  */
52736ecaff7fSRandy Dunlap 
527482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
527582069379SAkinobu Mita 	&driver_attr_delay.attr,
527682069379SAkinobu Mita 	&driver_attr_opts.attr,
527782069379SAkinobu Mita 	&driver_attr_ptype.attr,
527882069379SAkinobu Mita 	&driver_attr_dsense.attr,
527982069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
528082069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
528182069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
528282069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
528382069379SAkinobu Mita 	&driver_attr_num_parts.attr,
528482069379SAkinobu Mita 	&driver_attr_every_nth.attr,
528582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
528682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
528782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
528882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
528982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
529082069379SAkinobu Mita 	&driver_attr_add_host.attr,
529182069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
529282069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5293c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5294c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
529582069379SAkinobu Mita 	&driver_attr_dix.attr,
529682069379SAkinobu Mita 	&driver_attr_dif.attr,
529782069379SAkinobu Mita 	&driver_attr_guard.attr,
529882069379SAkinobu Mita 	&driver_attr_ato.attr,
529982069379SAkinobu Mita 	&driver_attr_map.attr,
530082069379SAkinobu Mita 	&driver_attr_removable.attr,
5301cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5302cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5303c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
530409ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
53059b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
530682069379SAkinobu Mita 	NULL,
530782069379SAkinobu Mita };
530882069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
53091da177e4SLinus Torvalds 
531011ddcecaSAkinobu Mita static struct device *pseudo_primary;
53118dea0d02SFUJITA Tomonori 
53121da177e4SLinus Torvalds static int __init scsi_debug_init(void)
53131da177e4SLinus Torvalds {
53145f2578e5SFUJITA Tomonori 	unsigned long sz;
53151da177e4SLinus Torvalds 	int host_to_add;
53161da177e4SLinus Torvalds 	int k;
53176ecaff7fSRandy Dunlap 	int ret;
53181da177e4SLinus Torvalds 
5319cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5320cbf67842SDouglas Gilbert 
5321773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5322c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5323773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5324773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5325c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5326cbf67842SDouglas Gilbert 
5327773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5328597136abSMartin K. Petersen 	case  512:
5329597136abSMartin K. Petersen 	case 1024:
5330597136abSMartin K. Petersen 	case 2048:
5331597136abSMartin K. Petersen 	case 4096:
5332597136abSMartin K. Petersen 		break;
5333597136abSMartin K. Petersen 	default:
5334773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5335597136abSMartin K. Petersen 		return -EINVAL;
5336597136abSMartin K. Petersen 	}
5337597136abSMartin K. Petersen 
5338773642d9SDouglas Gilbert 	switch (sdebug_dif) {
53398475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5340f46eb0e9SDouglas Gilbert 		break;
53418475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
53428475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
53438475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5344f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5345c6a44287SMartin K. Petersen 		break;
5346c6a44287SMartin K. Petersen 
5347c6a44287SMartin K. Petersen 	default:
5348c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5349c6a44287SMartin K. Petersen 		return -EINVAL;
5350c6a44287SMartin K. Petersen 	}
5351c6a44287SMartin K. Petersen 
5352773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5353c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5354c6a44287SMartin K. Petersen 		return -EINVAL;
5355c6a44287SMartin K. Petersen 	}
5356c6a44287SMartin K. Petersen 
5357773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5358c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5359c6a44287SMartin K. Petersen 		return -EINVAL;
5360c6a44287SMartin K. Petersen 	}
5361c6a44287SMartin K. Petersen 
5362773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5363773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5364ea61fca5SMartin K. Petersen 		return -EINVAL;
5365ea61fca5SMartin K. Petersen 	}
53668d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
53678d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
53688d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
53698d039e22SDouglas Gilbert 	}
5370ea61fca5SMartin K. Petersen 
5371773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5372773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5373ea61fca5SMartin K. Petersen 		return -EINVAL;
5374ea61fca5SMartin K. Petersen 	}
5375ea61fca5SMartin K. Petersen 
5376c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5377c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5378c4837394SDouglas Gilbert 		return -EINVAL;
5379c4837394SDouglas Gilbert 	}
5380c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5381c4837394SDouglas Gilbert 			       GFP_KERNEL);
5382c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5383c4837394SDouglas Gilbert 		return -ENOMEM;
5384c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5385c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5386c4837394SDouglas Gilbert 
5387773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5388773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5389773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5390773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
539128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
53921da177e4SLinus Torvalds 
53931da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
53941da177e4SLinus Torvalds 	sdebug_heads = 8;
53951da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5396773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
53971da177e4SLinus Torvalds 		sdebug_heads = 64;
5398773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5399fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
54001da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
54011da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
54021da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
54031da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
54041da177e4SLinus Torvalds 		sdebug_heads = 255;
54051da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
54061da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
54071da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
54081da177e4SLinus Torvalds 	}
54091da177e4SLinus Torvalds 
5410b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
54117382f9d8SDouglas Gilbert 		fake_storep = vzalloc(sz);
54121da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5413c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5414c4837394SDouglas Gilbert 			ret = -ENOMEM;
5415c4837394SDouglas Gilbert 			goto free_q_arr;
54161da177e4SLinus Torvalds 		}
5417773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5418f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5419cbf67842SDouglas Gilbert 	}
54201da177e4SLinus Torvalds 
5421773642d9SDouglas Gilbert 	if (sdebug_dix) {
5422c6a44287SMartin K. Petersen 		int dif_size;
5423c6a44287SMartin K. Petersen 
54246ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5425c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5426c6a44287SMartin K. Petersen 
5427c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5428c6a44287SMartin K. Petersen 
5429c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5430c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5431c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5432c6a44287SMartin K. Petersen 			goto free_vm;
5433c6a44287SMartin K. Petersen 		}
5434c6a44287SMartin K. Petersen 
5435c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5436c6a44287SMartin K. Petersen 	}
5437c6a44287SMartin K. Petersen 
54385b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
54395b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5440773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5441773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
54426014759cSMartin K. Petersen 
5443773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5444773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
54456014759cSMartin K. Petersen 
5446773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5447773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
54486014759cSMartin K. Petersen 
5449773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5450773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5451773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5452c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5453c4837394SDouglas Gilbert 			ret = -EINVAL;
5454c4837394SDouglas Gilbert 			goto free_vm;
545544d92694SMartin K. Petersen 		}
545644d92694SMartin K. Petersen 
5457b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
545842bc47b3SKees Cook 		map_storep = vmalloc(array_size(sizeof(long),
545942bc47b3SKees Cook 						BITS_TO_LONGS(map_size)));
546044d92694SMartin K. Petersen 
5461c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
546244d92694SMartin K. Petersen 
546344d92694SMartin K. Petersen 		if (map_storep == NULL) {
5464c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
546544d92694SMartin K. Petersen 			ret = -ENOMEM;
546644d92694SMartin K. Petersen 			goto free_vm;
546744d92694SMartin K. Petersen 		}
546844d92694SMartin K. Petersen 
5469b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
547044d92694SMartin K. Petersen 
547144d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5472773642d9SDouglas Gilbert 		if (sdebug_num_parts)
547344d92694SMartin K. Petersen 			map_region(0, 2);
547444d92694SMartin K. Petersen 	}
547544d92694SMartin K. Petersen 
54769b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
54779b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5478c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
54799b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
54806ecaff7fSRandy Dunlap 		goto free_vm;
54816ecaff7fSRandy Dunlap 	}
54826ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
54836ecaff7fSRandy Dunlap 	if (ret < 0) {
5484c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
54856ecaff7fSRandy Dunlap 		goto dev_unreg;
54866ecaff7fSRandy Dunlap 	}
54876ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
54886ecaff7fSRandy Dunlap 	if (ret < 0) {
5489c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
54906ecaff7fSRandy Dunlap 		goto bus_unreg;
54916ecaff7fSRandy Dunlap 	}
54921da177e4SLinus Torvalds 
5493773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5494773642d9SDouglas Gilbert 	sdebug_add_host = 0;
54951da177e4SLinus Torvalds 
54961da177e4SLinus Torvalds 	for (k = 0; k < host_to_add; k++) {
54971da177e4SLinus Torvalds 		if (sdebug_add_adapter()) {
5498c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
54991da177e4SLinus Torvalds 			break;
55001da177e4SLinus Torvalds 		}
55011da177e4SLinus Torvalds 	}
55021da177e4SLinus Torvalds 
5503773642d9SDouglas Gilbert 	if (sdebug_verbose)
5504773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5505c1287970STomas Winkler 
55061da177e4SLinus Torvalds 	return 0;
55076ecaff7fSRandy Dunlap 
55086ecaff7fSRandy Dunlap bus_unreg:
55096ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
55106ecaff7fSRandy Dunlap dev_unreg:
55119b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
55126ecaff7fSRandy Dunlap free_vm:
551344d92694SMartin K. Petersen 	vfree(map_storep);
5514c6a44287SMartin K. Petersen 	vfree(dif_storep);
55156ecaff7fSRandy Dunlap 	vfree(fake_storep);
5516c4837394SDouglas Gilbert free_q_arr:
5517c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
55186ecaff7fSRandy Dunlap 	return ret;
55191da177e4SLinus Torvalds }
55201da177e4SLinus Torvalds 
55211da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
55221da177e4SLinus Torvalds {
5523773642d9SDouglas Gilbert 	int k = sdebug_add_host;
55241da177e4SLinus Torvalds 
55251da177e4SLinus Torvalds 	stop_all_queued();
55261da177e4SLinus Torvalds 	for (; k; k--)
55271da177e4SLinus Torvalds 		sdebug_remove_adapter();
552852ab9768SLuis Henriques 	free_all_queued();
55291da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
55301da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
55319b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
55321da177e4SLinus Torvalds 
55334d2b496fSEwan D. Milne 	vfree(map_storep);
5534c6a44287SMartin K. Petersen 	vfree(dif_storep);
55351da177e4SLinus Torvalds 	vfree(fake_storep);
5536c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
55371da177e4SLinus Torvalds }
55381da177e4SLinus Torvalds 
55391da177e4SLinus Torvalds device_initcall(scsi_debug_init);
55401da177e4SLinus Torvalds module_exit(scsi_debug_exit);
55411da177e4SLinus Torvalds 
55421da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
55431da177e4SLinus Torvalds {
55441da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55451da177e4SLinus Torvalds 
55461da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55471da177e4SLinus Torvalds 	kfree(sdbg_host);
55481da177e4SLinus Torvalds }
55491da177e4SLinus Torvalds 
55501da177e4SLinus Torvalds static int sdebug_add_adapter(void)
55511da177e4SLinus Torvalds {
55521da177e4SLinus Torvalds 	int k, devs_per_host;
55531da177e4SLinus Torvalds 	int error = 0;
55541da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55558b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55561da177e4SLinus Torvalds 
555724669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
55589a051019SDouglas Gilbert 	if (sdbg_host == NULL) {
5559c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
55601da177e4SLinus Torvalds 		return -ENOMEM;
55611da177e4SLinus Torvalds 	}
55621da177e4SLinus Torvalds 
55631da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
55641da177e4SLinus Torvalds 
5565773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
55661da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
55675cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
55685cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5569c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
55701da177e4SLinus Torvalds 			error = -ENOMEM;
55711da177e4SLinus Torvalds 			goto clean;
55721da177e4SLinus Torvalds 		}
55731da177e4SLinus Torvalds 	}
55741da177e4SLinus Torvalds 
55751da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55761da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
55771da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55781da177e4SLinus Torvalds 
55791da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
55809b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
55811da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
5582773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
55831da177e4SLinus Torvalds 
55841da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
55851da177e4SLinus Torvalds 
55861da177e4SLinus Torvalds 	if (error)
55871da177e4SLinus Torvalds 		goto clean;
55881da177e4SLinus Torvalds 
5589773642d9SDouglas Gilbert 	++sdebug_add_host;
55901da177e4SLinus Torvalds 	return error;
55911da177e4SLinus Torvalds 
55921da177e4SLinus Torvalds clean:
55938b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55948b40228fSFUJITA Tomonori 				 dev_list) {
55951da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
55961da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
55971da177e4SLinus Torvalds 	}
55981da177e4SLinus Torvalds 
55991da177e4SLinus Torvalds 	kfree(sdbg_host);
56001da177e4SLinus Torvalds 	return error;
56011da177e4SLinus Torvalds }
56021da177e4SLinus Torvalds 
56031da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
56041da177e4SLinus Torvalds {
56051da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
56061da177e4SLinus Torvalds 
56071da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
56081da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
56091da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
56101da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
56111da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
56121da177e4SLinus Torvalds 	}
56131da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
56141da177e4SLinus Torvalds 
56151da177e4SLinus Torvalds 	if (!sdbg_host)
56161da177e4SLinus Torvalds 		return;
56171da177e4SLinus Torvalds 
56181da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5619773642d9SDouglas Gilbert 	--sdebug_add_host;
56201da177e4SLinus Torvalds }
56211da177e4SLinus Torvalds 
5622fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5623cbf67842SDouglas Gilbert {
5624cbf67842SDouglas Gilbert 	int num_in_q = 0;
5625cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5626cbf67842SDouglas Gilbert 
5627c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5628cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5629cbf67842SDouglas Gilbert 	if (NULL == devip) {
5630c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5631cbf67842SDouglas Gilbert 		return	-ENODEV;
5632cbf67842SDouglas Gilbert 	}
5633cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5634c40ecc12SChristoph Hellwig 
5635cbf67842SDouglas Gilbert 	if (qdepth < 1)
5636cbf67842SDouglas Gilbert 		qdepth = 1;
5637c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5638c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5639c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5640db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5641cbf67842SDouglas Gilbert 
5642773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5643c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5644c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5645cbf67842SDouglas Gilbert 	}
5646c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5647cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5648cbf67842SDouglas Gilbert }
5649cbf67842SDouglas Gilbert 
5650c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5651817fd66bSDouglas Gilbert {
5652c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5653773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5654773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5655773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5656c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5657773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5658817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5659c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5660817fd66bSDouglas Gilbert 	}
5661c4837394SDouglas Gilbert 	return false;
5662817fd66bSDouglas Gilbert }
5663817fd66bSDouglas Gilbert 
56647ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
56657ee6d1b4SBart Van Assche {
56667ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
56677ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
56687ee6d1b4SBart Van Assche }
56697ee6d1b4SBart Van Assche 
5670fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5671fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5672c2248fc9SDouglas Gilbert {
5673c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5674c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5675c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5676c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5677c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5678c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5679c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5680f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
5681c2248fc9SDouglas Gilbert 	int k, na;
5682c2248fc9SDouglas Gilbert 	int errsts = 0;
5683c2248fc9SDouglas Gilbert 	u32 flags;
5684c2248fc9SDouglas Gilbert 	u16 sa;
5685c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5686c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5687c2248fc9SDouglas Gilbert 
5688c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5689c4837394SDouglas Gilbert 	if (sdebug_statistics)
5690c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5691f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5692f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5693c2248fc9SDouglas Gilbert 		char b[120];
5694c2248fc9SDouglas Gilbert 		int n, len, sb;
5695c2248fc9SDouglas Gilbert 
5696c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5697c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5698c2248fc9SDouglas Gilbert 		if (len > 32)
5699c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5700c2248fc9SDouglas Gilbert 		else {
5701c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5702c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5703c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5704c2248fc9SDouglas Gilbert 		}
5705458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5706458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
5707c2248fc9SDouglas Gilbert 	}
57087ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
57097ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
571034d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5711f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5712f46eb0e9SDouglas Gilbert 		goto err_out;
5713c2248fc9SDouglas Gilbert 
5714c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5715c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5716c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5717f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5718f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5719c2248fc9SDouglas Gilbert 		if (NULL == devip)
5720f46eb0e9SDouglas Gilbert 			goto err_out;
5721c2248fc9SDouglas Gilbert 	}
5722c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5723c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5724c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5725c2248fc9SDouglas Gilbert 		r_oip = oip;
5726c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5727c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5728c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5729c2248fc9SDouglas Gilbert 			else
5730c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5731c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5732c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5733c2248fc9SDouglas Gilbert 					break;
5734c2248fc9SDouglas Gilbert 			}
5735c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5736c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5737c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5738c2248fc9SDouglas Gilbert 					break;
5739c2248fc9SDouglas Gilbert 			}
5740c2248fc9SDouglas Gilbert 		}
5741c2248fc9SDouglas Gilbert 		if (k > na) {
5742c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5743c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5744c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5745c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5746c2248fc9SDouglas Gilbert 			else
5747c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5748c2248fc9SDouglas Gilbert 			goto check_cond;
5749c2248fc9SDouglas Gilbert 		}
5750c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5751c2248fc9SDouglas Gilbert 	flags = oip->flags;
5752f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5753c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5754c2248fc9SDouglas Gilbert 		goto check_cond;
5755c2248fc9SDouglas Gilbert 	}
5756f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5757773642d9SDouglas Gilbert 		if (sdebug_verbose)
5758773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5759773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5760c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5761c2248fc9SDouglas Gilbert 		goto check_cond;
5762c2248fc9SDouglas Gilbert 	}
5763f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5764c2248fc9SDouglas Gilbert 		u8 rem;
5765c2248fc9SDouglas Gilbert 		int j;
5766c2248fc9SDouglas Gilbert 
5767c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5768c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5769c2248fc9SDouglas Gilbert 			if (rem) {
5770c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5771c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5772c2248fc9SDouglas Gilbert 						break;
5773c2248fc9SDouglas Gilbert 				}
5774c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5775c2248fc9SDouglas Gilbert 				goto check_cond;
5776c2248fc9SDouglas Gilbert 			}
5777c2248fc9SDouglas Gilbert 		}
5778c2248fc9SDouglas Gilbert 	}
5779f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5780b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5781b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5782f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5783c2248fc9SDouglas Gilbert 		if (errsts)
5784c2248fc9SDouglas Gilbert 			goto check_cond;
5785c2248fc9SDouglas Gilbert 	}
5786c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5787c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5788773642d9SDouglas Gilbert 		if (sdebug_verbose)
5789c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5790c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5791c2248fc9SDouglas Gilbert 				    "required");
5792c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5793c2248fc9SDouglas Gilbert 		goto fini;
5794c2248fc9SDouglas Gilbert 	}
5795773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5796c2248fc9SDouglas Gilbert 		goto fini;
5797f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5798c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5799c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5800c2248fc9SDouglas Gilbert 	}
5801f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5802f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
5803f66b8517SMartin Wilck 	else
5804f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
5805c2248fc9SDouglas Gilbert 
5806c2248fc9SDouglas Gilbert fini:
580710bde980SDouglas Gilbert 	if (F_DELAY_OVERR & flags)
5808f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
580975aa3209SDouglas Gilbert 	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
581075aa3209SDouglas Gilbert 					    sdebug_ndelay > 10000)) {
581180c49563SDouglas Gilbert 		/*
581275aa3209SDouglas Gilbert 		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
581375aa3209SDouglas Gilbert 		 * for Start Stop Unit (SSU) want at least 1 second delay and
581475aa3209SDouglas Gilbert 		 * if sdebug_jdelay>1 want a long delay of that many seconds.
581575aa3209SDouglas Gilbert 		 * For Synchronize Cache want 1/20 of SSU's delay.
581680c49563SDouglas Gilbert 		 */
581780c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
58184f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
581980c49563SDouglas Gilbert 
58204f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
5821f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
582280c49563SDouglas Gilbert 	} else
5823f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
582410bde980SDouglas Gilbert 				     sdebug_ndelay);
5825c2248fc9SDouglas Gilbert check_cond:
5826f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
5827f46eb0e9SDouglas Gilbert err_out:
5828f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
5829c2248fc9SDouglas Gilbert }
5830c2248fc9SDouglas Gilbert 
58319e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5832c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5833c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
58349e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
58359e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
58369e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
58379e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
58389e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
58399e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
58409e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5841185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5842cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
58439e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
58449e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5845cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5846cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
58479e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5848c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
58499e603ca0SFUJITA Tomonori 	.this_id =		7,
585065e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5851cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
58526bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
585350c2e910SChristoph Hellwig 	.max_segment_size =	-1U,
58549e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5855c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
58569e603ca0SFUJITA Tomonori };
58579e603ca0SFUJITA Tomonori 
58581da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
58591da177e4SLinus Torvalds {
58601da177e4SLinus Torvalds 	int error = 0;
58611da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
58621da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5863f46eb0e9SDouglas Gilbert 	int hprot;
58641da177e4SLinus Torvalds 
58651da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
58661da177e4SLinus Torvalds 
5867773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
58682a3d4eb8SChristoph Hellwig 	if (!sdebug_clustering)
58692a3d4eb8SChristoph Hellwig 		sdebug_driver_template.use_clustering = DISABLE_CLUSTERING;
58701da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
58711da177e4SLinus Torvalds 	if (NULL == hpnt) {
5872c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
58731da177e4SLinus Torvalds 		error = -ENODEV;
58741da177e4SLinus Torvalds 		return error;
58751da177e4SLinus Torvalds 	}
5876c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
58779b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5878c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5879c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5880c4837394SDouglas Gilbert 	}
5881c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5882c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5883458df78bSBart Van Assche 	if (shost_use_blk_mq(hpnt))
5884c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
58851da177e4SLinus Torvalds 
58861da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
58871da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5888773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5889773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
58901da177e4SLinus Torvalds 	else
5891773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5892773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5893f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
58941da177e4SLinus Torvalds 
5895f46eb0e9SDouglas Gilbert 	hprot = 0;
5896c6a44287SMartin K. Petersen 
5897773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5898c6a44287SMartin K. Petersen 
58998475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5900f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5901773642d9SDouglas Gilbert 		if (sdebug_dix)
5902f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5903c6a44287SMartin K. Petersen 		break;
5904c6a44287SMartin K. Petersen 
59058475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5906f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5907773642d9SDouglas Gilbert 		if (sdebug_dix)
5908f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5909c6a44287SMartin K. Petersen 		break;
5910c6a44287SMartin K. Petersen 
59118475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5912f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5913773642d9SDouglas Gilbert 		if (sdebug_dix)
5914f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5915c6a44287SMartin K. Petersen 		break;
5916c6a44287SMartin K. Petersen 
5917c6a44287SMartin K. Petersen 	default:
5918773642d9SDouglas Gilbert 		if (sdebug_dix)
5919f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5920c6a44287SMartin K. Petersen 		break;
5921c6a44287SMartin K. Petersen 	}
5922c6a44287SMartin K. Petersen 
5923f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5924c6a44287SMartin K. Petersen 
5925f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5926c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5927f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5928f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5929f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5930f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5931f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5932f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5933f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5934c6a44287SMartin K. Petersen 
5935773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5936c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5937c6a44287SMartin K. Petersen 	else
5938c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5939c6a44287SMartin K. Petersen 
5940773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5941773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5942c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5943c4837394SDouglas Gilbert 		sdebug_statistics = true;
59441da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
59451da177e4SLinus Torvalds 	if (error) {
5946c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
59471da177e4SLinus Torvalds 		error = -ENODEV;
59481da177e4SLinus Torvalds 		scsi_host_put(hpnt);
59491da177e4SLinus Torvalds 	} else
59501da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
59511da177e4SLinus Torvalds 
59521da177e4SLinus Torvalds 	return error;
59531da177e4SLinus Torvalds }
59541da177e4SLinus Torvalds 
59551da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
59561da177e4SLinus Torvalds {
59571da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
59588b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
59591da177e4SLinus Torvalds 
59601da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
59611da177e4SLinus Torvalds 
59621da177e4SLinus Torvalds 	if (!sdbg_host) {
5963c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
59641da177e4SLinus Torvalds 		return -ENODEV;
59651da177e4SLinus Torvalds 	}
59661da177e4SLinus Torvalds 
59671da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
59681da177e4SLinus Torvalds 
59698b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
59708b40228fSFUJITA Tomonori 				 dev_list) {
59711da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
59721da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
59731da177e4SLinus Torvalds 	}
59741da177e4SLinus Torvalds 
59751da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
59761da177e4SLinus Torvalds 	return 0;
59771da177e4SLinus Torvalds }
59781da177e4SLinus Torvalds 
59798dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
59808dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
59811da177e4SLinus Torvalds {
59828dea0d02SFUJITA Tomonori 	return 1;
59838dea0d02SFUJITA Tomonori }
59841da177e4SLinus Torvalds 
59858dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
59868dea0d02SFUJITA Tomonori 	.name = "pseudo",
59878dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
59888dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
59898dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
599082069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
59918dea0d02SFUJITA Tomonori };
5992