xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 09ba24c1)
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  *
9773642d9SDouglas Gilbert  * Copyright (C) 2001 - 2016 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>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
581da177e4SLinus Torvalds 
59c6a44287SMartin K. Petersen #include "sd.h"
601da177e4SLinus Torvalds #include "scsi_logging.h"
611da177e4SLinus Torvalds 
62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
63b01f6f83SDouglas Gilbert #define SDEBUG_VERSION "1.86"
64b01f6f83SDouglas Gilbert static const char *sdebug_version_date = "20160430";
65cbf67842SDouglas Gilbert 
66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
671da177e4SLinus Torvalds 
686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
85cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
86cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8722017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
881da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
896f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
90c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
91c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9222017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
93acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
951da177e4SLinus Torvalds 
966f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
976f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
986f3cbf55SDouglas Gilbert 
991da177e4SLinus Torvalds /* Default values for driver parameters */
1001da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1011da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1021da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1031da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1041da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1051da177e4SLinus Torvalds  */
1065b94e232SMartin K. Petersen #define DEF_ATO 1
107c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1081da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1095b94e232SMartin K. Petersen #define DEF_DIF 0
1105b94e232SMartin K. Petersen #define DEF_DIX 0
1115b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1121da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1135b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1145b94e232SMartin K. Petersen #define DEF_GUARD 0
115cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1165b94e232SMartin K. Petersen #define DEF_LBPU 0
1175b94e232SMartin K. Petersen #define DEF_LBPWS 0
1185b94e232SMartin K. Petersen #define DEF_LBPWS10 0
119be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1205b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
121cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1225b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1231da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1241da177e4SLinus Torvalds #define DEF_OPTS   0
12532c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1265b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
127b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
128d986788bSMartin Pitt #define DEF_REMOVABLE false
129760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1305b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1315b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1325b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1355b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1365b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1375b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
138c2248fc9SDouglas Gilbert #define DEF_STRICT 0
139c4837394SDouglas Gilbert #define DEF_STATISTICS false
140c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14109ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
142c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1431da177e4SLinus Torvalds 
144b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
145b01f6f83SDouglas Gilbert 
146773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
147773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
148773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
149773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
150773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
151773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
152773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
153773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
154773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
155773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
156773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
157773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
158773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
159773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
160773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
161773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
162773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
163773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
164773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
165773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
166773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
167773642d9SDouglas Gilbert 				  SDEBUG_OPT_SHORT_TRANSFER)
1681da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
169fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1701da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
171773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1726f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
173773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1741da177e4SLinus Torvalds  *
1751da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
176fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1771da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
178773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1796f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
180773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
181773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
182773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
183773642d9SDouglas Gilbert  * every_nth via sysfs).
1841da177e4SLinus Torvalds  */
1851da177e4SLinus Torvalds 
186cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
187cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
188cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
189cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
190cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
191cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
192cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1930d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
19419c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
195acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
196acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
197acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
198cbf67842SDouglas Gilbert 
199773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2001da177e4SLinus Torvalds  * sector on read commands: */
2011da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2051da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2061da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2071da177e4SLinus Torvalds 
208c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
209c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
210c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
211c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
212c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
213c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
214c4837394SDouglas Gilbert  */
215c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
216c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
217cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
218cbf67842SDouglas Gilbert 
219fd32119bSDouglas Gilbert #define F_D_IN			1
220fd32119bSDouglas Gilbert #define F_D_OUT			2
221fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
222fd32119bSDouglas Gilbert #define F_D_UNKN		8
223fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
224fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
225fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
226fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
227fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
228fd32119bSDouglas Gilbert #define F_INV_OP		0x200
229fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
230fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
231fd32119bSDouglas Gilbert 
232fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
233fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
234fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
235fd32119bSDouglas Gilbert 
236fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
237fd32119bSDouglas Gilbert 
238b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
239fd32119bSDouglas Gilbert 
240fd32119bSDouglas Gilbert 
241fd32119bSDouglas Gilbert struct sdebug_dev_info {
242fd32119bSDouglas Gilbert 	struct list_head dev_list;
243fd32119bSDouglas Gilbert 	unsigned int channel;
244fd32119bSDouglas Gilbert 	unsigned int target;
245fd32119bSDouglas Gilbert 	u64 lun;
24609ba24c1SDouglas Gilbert 	uuid_be lu_name;
247fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
248fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
249fd32119bSDouglas Gilbert 	atomic_t num_in_q;
250c4837394SDouglas Gilbert 	atomic_t stopped;
251fd32119bSDouglas Gilbert 	bool used;
252fd32119bSDouglas Gilbert };
253fd32119bSDouglas Gilbert 
254fd32119bSDouglas Gilbert struct sdebug_host_info {
255fd32119bSDouglas Gilbert 	struct list_head host_list;
256fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
257fd32119bSDouglas Gilbert 	struct device dev;
258fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
259fd32119bSDouglas Gilbert };
260fd32119bSDouglas Gilbert 
261fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
262fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
263fd32119bSDouglas Gilbert 
264fd32119bSDouglas Gilbert struct sdebug_defer {
265fd32119bSDouglas Gilbert 	struct hrtimer hrt;
266fd32119bSDouglas Gilbert 	struct execute_work ew;
267c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
268c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
269c4837394SDouglas Gilbert 	int issuing_cpu;
270fd32119bSDouglas Gilbert };
271fd32119bSDouglas Gilbert 
272fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
273c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
274c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
275c4837394SDouglas Gilbert 	 */
276fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
277fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
278c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
279c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
280c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
281c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
282c4837394SDouglas Gilbert 	unsigned int inj_short:1;
283fd32119bSDouglas Gilbert };
284fd32119bSDouglas Gilbert 
285c4837394SDouglas Gilbert struct sdebug_queue {
286c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
287c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
288c4837394SDouglas Gilbert 	spinlock_t qc_lock;
289c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
290fd32119bSDouglas Gilbert };
291fd32119bSDouglas Gilbert 
292c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
293c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
294c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
295c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
296c4837394SDouglas Gilbert 
297fd32119bSDouglas Gilbert struct opcode_info_t {
298b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
299b01f6f83SDouglas Gilbert 				/* for terminating element */
300fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
301fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
302fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
303fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
304fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
305fd32119bSDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
306fd32119bSDouglas Gilbert 				/* ignore cdb bytes after position 15 */
307fd32119bSDouglas Gilbert };
308fd32119bSDouglas Gilbert 
309fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
310c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
311c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
312c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
313c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
314c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
315c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
316c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
317c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
318c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
319c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
320c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
321c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
322c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
323c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
324c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
325c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
326c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
327c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
328c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
329c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
330c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
331c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
332c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
333c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
334c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
335c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
336c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
337c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
338c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
339c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
340c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
341c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
342c2248fc9SDouglas Gilbert };
343c2248fc9SDouglas Gilbert 
344c4837394SDouglas Gilbert 
345c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
346c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
347c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
348c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
349c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
350c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
351c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
352c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
353c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
354c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
355c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
356c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
357c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
358c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
359c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
360c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
361c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
362c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
363c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
364c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
365fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
366c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
369c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
370c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
371c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
372c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
373c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
374c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
375c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
376c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
377c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
378c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
379c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
380c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
381c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
382c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 0, 0,
386c2248fc9SDouglas Gilbert };
387c2248fc9SDouglas Gilbert 
388c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
389c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
390c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
391c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
392c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
393c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
394c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
395c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
396c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
397c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
398c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
399c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
400c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
401c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
40238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
40338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
404c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
405c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
406c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
40738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
408acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
409c2248fc9SDouglas Gilbert 
410c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
411c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
412c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
413c2248fc9SDouglas Gilbert };
414c2248fc9SDouglas Gilbert 
415c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
416c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
417c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
418c2248fc9SDouglas Gilbert };
419c2248fc9SDouglas Gilbert 
420c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
421c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
422c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
423c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
424c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
425c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
426c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
427c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
428c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
429c2248fc9SDouglas Gilbert };
430c2248fc9SDouglas Gilbert 
431c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
432c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
433c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
434c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
435c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
436c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
437c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
438c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
439c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
440c2248fc9SDouglas Gilbert };
441c2248fc9SDouglas Gilbert 
442c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
443c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
444c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
445c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
446c2248fc9SDouglas Gilbert };
447c2248fc9SDouglas Gilbert 
448c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
449c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
450c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
451c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
452c2248fc9SDouglas Gilbert };
453c2248fc9SDouglas Gilbert 
454c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
45538d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
456c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
457c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
45838d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
459c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
460c2248fc9SDouglas Gilbert 	     0, 0} },
461c2248fc9SDouglas Gilbert };
462c2248fc9SDouglas Gilbert 
463c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
464c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
465c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
466c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
467c2248fc9SDouglas Gilbert };
468c2248fc9SDouglas Gilbert 
469c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
470c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
471c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
472c2248fc9SDouglas Gilbert };
473c2248fc9SDouglas Gilbert 
474c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
475c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
476c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
477c2248fc9SDouglas Gilbert };
478c2248fc9SDouglas Gilbert 
479c2248fc9SDouglas Gilbert 
480c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
481c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
482c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
483c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
484c2248fc9SDouglas Gilbert /* 0 */
485c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
486c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
487c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
488c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
489c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
490c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
491c2248fc9SDouglas Gilbert 	     0, 0} },
492c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
493c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
494c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
495c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
496c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
497c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
498c2248fc9SDouglas Gilbert 	     0} },
499c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
500c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
501c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
502c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
503c2248fc9SDouglas Gilbert 	     0, 0, 0} },
504c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
505c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
506c2248fc9SDouglas Gilbert 	     0, 0} },
507c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
508c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
509c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
510c2248fc9SDouglas Gilbert /* 10 */
511c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
512c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
513c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
514c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
515c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
516c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
517c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
518c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
519c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
520c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
521c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
522c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
523c2248fc9SDouglas Gilbert 	     0} },
524c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
525c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
526f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
527f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
528f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
529c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
530c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
531c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
532c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
533c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
534c2248fc9SDouglas Gilbert 	     0} },
535c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
536c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
537c2248fc9SDouglas Gilbert 	     0} },
538c2248fc9SDouglas Gilbert /* 20 */
539f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
540f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
541c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
542c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
543c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
544c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
545c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
546c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
547c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
548c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
549c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
550c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
551c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
552acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
553acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
554acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
555c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
556c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
557c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
558c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
559c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
560c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
56138d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
562c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
563c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
564c2248fc9SDouglas Gilbert 
565c2248fc9SDouglas Gilbert /* 30 */
566c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
567c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
568c2248fc9SDouglas Gilbert };
569c2248fc9SDouglas Gilbert 
570773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
571773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
572c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
573773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
574773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
575773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
576773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
577773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
578773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
579773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
580773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
581773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
582c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
583cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
584c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
585773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
586773642d9SDouglas Gilbert static int sdebug_no_uld;
587773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
588773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
589773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
590773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
591773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
592b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
593773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
594773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
595773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
596773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
597773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
598773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
599773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
600773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
601773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
602773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
603773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
604773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
605773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
60609ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
607773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
608773642d9SDouglas Gilbert static bool sdebug_clustering;
609773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
610773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
611817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
612773642d9SDouglas Gilbert static bool sdebug_verbose;
613f46eb0e9SDouglas Gilbert static bool have_dif_prot;
614c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
615c4837394SDouglas Gilbert static bool sdebug_mq_active;
6161da177e4SLinus Torvalds 
617c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6181da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6211da177e4SLinus Torvalds    may still need them */
6221da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6231da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6241da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6271da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
630e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
63144d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6321da177e4SLinus Torvalds 
63344d92694SMartin K. Petersen static unsigned long map_size;
634cbf67842SDouglas Gilbert static int num_aborts;
635cbf67842SDouglas Gilbert static int num_dev_resets;
636cbf67842SDouglas Gilbert static int num_target_resets;
637cbf67842SDouglas Gilbert static int num_bus_resets;
638cbf67842SDouglas Gilbert static int num_host_resets;
639c6a44287SMartin K. Petersen static int dix_writes;
640c6a44287SMartin K. Petersen static int dix_reads;
641c6a44287SMartin K. Petersen static int dif_errors;
6421da177e4SLinus Torvalds 
643c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
644c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
645fd32119bSDouglas Gilbert 
6461da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6471da177e4SLinus Torvalds 
648cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
649cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6541da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6551da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6561da177e4SLinus Torvalds };
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds static const int check_condition_result =
6591da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6601da177e4SLinus Torvalds 
661c6a44287SMartin K. Petersen static const int illegal_condition_result =
662c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
663c6a44287SMartin K. Petersen 
664cbf67842SDouglas Gilbert static const int device_qfull_result =
665cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
666cbf67842SDouglas Gilbert 
667fd32119bSDouglas Gilbert 
668760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
669760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
670760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
671760f3b03SDouglas Gilbert  */
672760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
673fd32119bSDouglas Gilbert {
674fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
675fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
676fd32119bSDouglas Gilbert }
677c65b1445SDouglas Gilbert 
67814faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
67914faa944SAkinobu Mita {
68014faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
68114faa944SAkinobu Mita 
682773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
68314faa944SAkinobu Mita }
68414faa944SAkinobu Mita 
68514faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
68614faa944SAkinobu Mita {
68749413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
68814faa944SAkinobu Mita 
68914faa944SAkinobu Mita 	return dif_storep + sector;
69014faa944SAkinobu Mita }
69114faa944SAkinobu Mita 
6928dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6938dea0d02SFUJITA Tomonori {
6948dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6958dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6968dea0d02SFUJITA Tomonori 
6978dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
6988dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
6998dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7008dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
701773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
702773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7038dea0d02SFUJITA Tomonori 		else
704773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
705773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
706f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7078dea0d02SFUJITA Tomonori 	}
7088dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7098dea0d02SFUJITA Tomonori }
7108dea0d02SFUJITA Tomonori 
71122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
71222017ed2SDouglas Gilbert 
71322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
714fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
715fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
71622017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
71722017ed2SDouglas Gilbert {
71822017ed2SDouglas Gilbert 	unsigned char *sbuff;
71922017ed2SDouglas Gilbert 	u8 sks[4];
72022017ed2SDouglas Gilbert 	int sl, asc;
72122017ed2SDouglas Gilbert 
72222017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
72322017ed2SDouglas Gilbert 	if (!sbuff) {
72422017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
72522017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
72622017ed2SDouglas Gilbert 		return;
72722017ed2SDouglas Gilbert 	}
72822017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
72922017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
730773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
73122017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
73222017ed2SDouglas Gilbert 	sks[0] = 0x80;
73322017ed2SDouglas Gilbert 	if (c_d)
73422017ed2SDouglas Gilbert 		sks[0] |= 0x40;
73522017ed2SDouglas Gilbert 	if (in_bit >= 0) {
73622017ed2SDouglas Gilbert 		sks[0] |= 0x8;
73722017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
73822017ed2SDouglas Gilbert 	}
73922017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
740773642d9SDouglas Gilbert 	if (sdebug_dsense) {
74122017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
74222017ed2SDouglas Gilbert 		sbuff[7] = sl;
74322017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
74422017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
74522017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
74622017ed2SDouglas Gilbert 	} else
74722017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
748773642d9SDouglas Gilbert 	if (sdebug_verbose)
74922017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
75022017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
75122017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
75222017ed2SDouglas Gilbert }
75322017ed2SDouglas Gilbert 
754cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7558dea0d02SFUJITA Tomonori {
7568dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7578dea0d02SFUJITA Tomonori 
758cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
759cbf67842SDouglas Gilbert 	if (!sbuff) {
760cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
761cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
762cbf67842SDouglas Gilbert 		return;
763cbf67842SDouglas Gilbert 	}
764cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7658dea0d02SFUJITA Tomonori 
766773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7678dea0d02SFUJITA Tomonori 
768773642d9SDouglas Gilbert 	if (sdebug_verbose)
769cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
770cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
771cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7728dea0d02SFUJITA Tomonori }
7731da177e4SLinus Torvalds 
774fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
77522017ed2SDouglas Gilbert {
77622017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
77722017ed2SDouglas Gilbert }
77822017ed2SDouglas Gilbert 
7791da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7801da177e4SLinus Torvalds {
781773642d9SDouglas Gilbert 	if (sdebug_verbose) {
782cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
783cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
784cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
785cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
786cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
787cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
788cbf67842SDouglas Gilbert 				    __func__);
789cbf67842SDouglas Gilbert 		else
790cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
791cbf67842SDouglas Gilbert 				    __func__, cmd);
7921da177e4SLinus Torvalds 	}
7931da177e4SLinus Torvalds 	return -EINVAL;
7941da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7951da177e4SLinus Torvalds }
7961da177e4SLinus Torvalds 
79719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
79819c8ead7SEwan D. Milne {
79919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
80019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
80119c8ead7SEwan D. Milne 
80219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
80319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
80419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
80519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
80619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
80719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
80819c8ead7SEwan D. Milne 		}
80919c8ead7SEwan D. Milne 	}
81019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
81119c8ead7SEwan D. Milne }
81219c8ead7SEwan D. Milne 
813f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
8141da177e4SLinus Torvalds {
815cbf67842SDouglas Gilbert 	int k;
816cbf67842SDouglas Gilbert 
817cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
818cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
819cbf67842SDouglas Gilbert 		const char *cp = NULL;
820cbf67842SDouglas Gilbert 
821cbf67842SDouglas Gilbert 		switch (k) {
822cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
823f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
824f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
825773642d9SDouglas Gilbert 			if (sdebug_verbose)
826cbf67842SDouglas Gilbert 				cp = "power on reset";
827cbf67842SDouglas Gilbert 			break;
828cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
829f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
830f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
831773642d9SDouglas Gilbert 			if (sdebug_verbose)
832cbf67842SDouglas Gilbert 				cp = "bus reset";
833cbf67842SDouglas Gilbert 			break;
834cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
835f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
836f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
837773642d9SDouglas Gilbert 			if (sdebug_verbose)
838cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
839cbf67842SDouglas Gilbert 			break;
8400d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
841f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
842f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
843773642d9SDouglas Gilbert 			if (sdebug_verbose)
8440d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
845f49accf1SEwan D. Milne 			break;
846acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
847f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
848b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
849b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
850773642d9SDouglas Gilbert 			if (sdebug_verbose)
851acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
852acafd0b9SEwan D. Milne 			break;
853acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
854f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
855acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
856acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
857773642d9SDouglas Gilbert 			if (sdebug_verbose)
858acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
859acafd0b9SEwan D. Milne 			break;
86019c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
86119c8ead7SEwan D. Milne 			/*
86219c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
86319c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
86419c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
86519c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
866773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
86719c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
86819c8ead7SEwan D. Milne 			 */
869773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
87019c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
871f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
87219c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
87319c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
874773642d9SDouglas Gilbert 			if (sdebug_verbose)
87519c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
87619c8ead7SEwan D. Milne 			break;
877cbf67842SDouglas Gilbert 		default:
878773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
879773642d9SDouglas Gilbert 			if (sdebug_verbose)
880cbf67842SDouglas Gilbert 				cp = "unknown";
881cbf67842SDouglas Gilbert 			break;
882cbf67842SDouglas Gilbert 		}
883cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
884773642d9SDouglas Gilbert 		if (sdebug_verbose)
885f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
886cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
887cbf67842SDouglas Gilbert 				   my_name, cp);
8881da177e4SLinus Torvalds 		return check_condition_result;
8891da177e4SLinus Torvalds 	}
8901da177e4SLinus Torvalds 	return 0;
8911da177e4SLinus Torvalds }
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
8941da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
8951da177e4SLinus Torvalds 				int arr_len)
8961da177e4SLinus Torvalds {
89721a61829SFUJITA Tomonori 	int act_len;
898072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
8991da177e4SLinus Torvalds 
900072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9011da177e4SLinus Torvalds 		return 0;
902072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
903773642d9SDouglas Gilbert 		return DID_ERROR << 16;
90421a61829SFUJITA Tomonori 
90521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
90621a61829SFUJITA Tomonori 				      arr, arr_len);
90721a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
90821a61829SFUJITA Tomonori 
9091da177e4SLinus Torvalds 	return 0;
9101da177e4SLinus Torvalds }
9111da177e4SLinus Torvalds 
9121da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
9131da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
91421a61829SFUJITA Tomonori 			       int arr_len)
9151da177e4SLinus Torvalds {
91621a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
9171da177e4SLinus Torvalds 		return 0;
918072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
9191da177e4SLinus Torvalds 		return -1;
92021a61829SFUJITA Tomonori 
92121a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
9221da177e4SLinus Torvalds }
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
9261da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
927773642d9SDouglas Gilbert static const char *inq_product_rev = "0186";	/* version less '.' */
928773642d9SDouglas Gilbert static const u64 naa5_comp_a = 0x5222222000000000ULL;
929773642d9SDouglas Gilbert static const u64 naa5_comp_b = 0x5333333000000000ULL;
930773642d9SDouglas Gilbert static const u64 naa5_comp_c = 0x5111111000000000ULL;
9311da177e4SLinus Torvalds 
932cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
933760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
9345a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
93509ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
93609ba24c1SDouglas Gilbert 			  const uuid_be *lu_name)
9371da177e4SLinus Torvalds {
938c65b1445SDouglas Gilbert 	int num, port_a;
939c65b1445SDouglas Gilbert 	char b[32];
9401da177e4SLinus Torvalds 
941c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9421da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9431da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9441da177e4SLinus Torvalds 	arr[1] = 0x1;
9451da177e4SLinus Torvalds 	arr[2] = 0x0;
9461da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
9471da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
9481da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9491da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9501da177e4SLinus Torvalds 	arr[3] = num;
9511da177e4SLinus Torvalds 	num += 4;
952c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
95309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
95409ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
95509ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
95609ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
95709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
95809ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
95909ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
96009ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
96109ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
96209ba24c1SDouglas Gilbert 			num += 16;
96309ba24c1SDouglas Gilbert 		} else {
964c65b1445SDouglas Gilbert 			/* NAA-5, Logical unit identifier (binary) */
965c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
966c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
967c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
968c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
969773642d9SDouglas Gilbert 			put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
970773642d9SDouglas Gilbert 			num += 8;
97109ba24c1SDouglas Gilbert 		}
972c65b1445SDouglas Gilbert 		/* Target relative port number */
973c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
974c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
975c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
976c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
977c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
978c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
979c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
980c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
981c65b1445SDouglas Gilbert 	}
982c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
983c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
984c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
985c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
986c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
987773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
988773642d9SDouglas Gilbert 	num += 8;
9895a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
9905a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
9915a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
9925a09e398SHannes Reinecke 	arr[num++] = 0x0;
9935a09e398SHannes Reinecke 	arr[num++] = 0x4;
9945a09e398SHannes Reinecke 	arr[num++] = 0;
9955a09e398SHannes Reinecke 	arr[num++] = 0;
996773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
997773642d9SDouglas Gilbert 	num += 2;
998c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
999c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1000c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1001c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1002c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
1003773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
1004773642d9SDouglas Gilbert 	num += 8;
1005c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1006c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1007c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1008c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1009c65b1445SDouglas Gilbert 	arr[num++] = 24;
1010c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
1011c65b1445SDouglas Gilbert 	num += 12;
1012c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1013c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1014c65b1445SDouglas Gilbert 	num += 8;
1015c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1016c65b1445SDouglas Gilbert 	num += 4;
1017c65b1445SDouglas Gilbert 	return num;
1018c65b1445SDouglas Gilbert }
1019c65b1445SDouglas Gilbert 
1020c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1021c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1022c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1023c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1024c65b1445SDouglas Gilbert };
1025c65b1445SDouglas Gilbert 
1026cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1027760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1028c65b1445SDouglas Gilbert {
1029c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1030c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1031c65b1445SDouglas Gilbert }
1032c65b1445SDouglas Gilbert 
1033cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1034760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1035c65b1445SDouglas Gilbert {
1036c65b1445SDouglas Gilbert 	int num = 0;
1037c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1038c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1039c65b1445SDouglas Gilbert 	int plen, olen;
1040c65b1445SDouglas Gilbert 
1041c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1042c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1043c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1044c65b1445SDouglas Gilbert 	olen = strlen(na1);
1045c65b1445SDouglas Gilbert 	plen = olen + 1;
1046c65b1445SDouglas Gilbert 	if (plen % 4)
1047c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1048c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1049c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1050c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1051c65b1445SDouglas Gilbert 	num += plen;
1052c65b1445SDouglas Gilbert 
1053c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1054c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1055c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1056c65b1445SDouglas Gilbert 	olen = strlen(na2);
1057c65b1445SDouglas Gilbert 	plen = olen + 1;
1058c65b1445SDouglas Gilbert 	if (plen % 4)
1059c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1060c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1061c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1062c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1063c65b1445SDouglas Gilbert 	num += plen;
1064c65b1445SDouglas Gilbert 
1065c65b1445SDouglas Gilbert 	return num;
1066c65b1445SDouglas Gilbert }
1067c65b1445SDouglas Gilbert 
1068c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1069760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1070c65b1445SDouglas Gilbert {
1071c65b1445SDouglas Gilbert 	int num = 0;
1072c65b1445SDouglas Gilbert 	int port_a, port_b;
1073c65b1445SDouglas Gilbert 
1074c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1075c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1076c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1077c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1078c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1079c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1080c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1081c65b1445SDouglas Gilbert 	num += 6;
1082c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1083c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1084c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1085c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1086c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1087c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1088c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1089773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1090773642d9SDouglas Gilbert 	num += 8;
1091c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1092c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1093c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1094c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1095c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1096c65b1445SDouglas Gilbert 	num += 6;
1097c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1098c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1099c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1100c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1101c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1102c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1103c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1104773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1105773642d9SDouglas Gilbert 	num += 8;
1106c65b1445SDouglas Gilbert 
1107c65b1445SDouglas Gilbert 	return num;
1108c65b1445SDouglas Gilbert }
1109c65b1445SDouglas Gilbert 
1110c65b1445SDouglas Gilbert 
1111c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1112c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1113c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1114c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1115c65b1445SDouglas Gilbert '1','2','3','4',
1116c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1117c65b1445SDouglas Gilbert 0xec,0,0,0,
1118c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1119c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1120c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1121c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1122c65b1445SDouglas Gilbert 0x53,0x41,
1123c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1124c65b1445SDouglas Gilbert 0x20,0x20,
1125c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1126c65b1445SDouglas Gilbert 0x10,0x80,
1127c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1128c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1129c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1130c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1131c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1132c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1133c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1134c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1135c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1136c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1137c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1138c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1139c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1140c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1141c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1142c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1143c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1144c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1145c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1146c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1147c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1148c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1149c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1150c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1151c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1152c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1153c65b1445SDouglas Gilbert };
1154c65b1445SDouglas Gilbert 
1155cbf67842SDouglas Gilbert /* ATA Information VPD page */
1156760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1157c65b1445SDouglas Gilbert {
1158c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1159c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1160c65b1445SDouglas Gilbert }
1161c65b1445SDouglas Gilbert 
1162c65b1445SDouglas Gilbert 
1163c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11641e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11651e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11661e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11671e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1168c65b1445SDouglas Gilbert };
1169c65b1445SDouglas Gilbert 
1170cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1171760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1172c65b1445SDouglas Gilbert {
1173ea61fca5SMartin K. Petersen 	unsigned int gran;
1174ea61fca5SMartin K. Petersen 
1175c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1176e308b3d1SMartin K. Petersen 
1177e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1178773642d9SDouglas Gilbert 	gran = 1 << sdebug_physblk_exp;
1179773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1180e308b3d1SMartin K. Petersen 
1181e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1182773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1183773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
118444d92694SMartin K. Petersen 
1185e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1186773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1187e308b3d1SMartin K. Petersen 
1188773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1189e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1190773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1191e308b3d1SMartin K. Petersen 
1192e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1193773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
119444d92694SMartin K. Petersen 	}
119544d92694SMartin K. Petersen 
1196e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1197773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1198773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
119944d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
120044d92694SMartin K. Petersen 	}
120144d92694SMartin K. Petersen 
1202e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1203773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
12046014759cSMartin K. Petersen 
12055b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1206773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
12075b94e232SMartin K. Petersen 
12085b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
120944d92694SMartin K. Petersen 
1210c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
12111da177e4SLinus Torvalds }
12121da177e4SLinus Torvalds 
12131e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1214760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1215eac6e8e4SMatthew Wilcox {
1216eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1217eac6e8e4SMatthew Wilcox 	arr[0] = 0;
12181e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
12191e49f785SDouglas Gilbert 	arr[2] = 0;
12201e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1221eac6e8e4SMatthew Wilcox 
1222eac6e8e4SMatthew Wilcox 	return 0x3c;
1223eac6e8e4SMatthew Wilcox }
12241da177e4SLinus Torvalds 
1225760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1226760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
12276014759cSMartin K. Petersen {
12283f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12296014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1230773642d9SDouglas Gilbert 	if (sdebug_lbpu)
12316014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1232773642d9SDouglas Gilbert 	if (sdebug_lbpws)
12336014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1234773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
12355b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1236760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1237760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1238760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1239760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1240760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
12413f0bc3b3SMartin K. Petersen 	return 0x4;
12426014759cSMartin K. Petersen }
12436014759cSMartin K. Petersen 
12441da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1245c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12461da177e4SLinus Torvalds 
1247c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12481da177e4SLinus Torvalds {
12491da177e4SLinus Torvalds 	unsigned char pq_pdt;
12505a09e398SHannes Reinecke 	unsigned char * arr;
125101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12525a09e398SHannes Reinecke 	int alloc_len, n, ret;
1253760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
12541da177e4SLinus Torvalds 
1255773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
12566f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12576f3cbf55SDouglas Gilbert 	if (! arr)
12586f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1259760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1260b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1261c2248fc9SDouglas Gilbert 	if (have_wlun)
1262b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1263b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1264b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1265c65b1445SDouglas Gilbert 	else
1266773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
12671da177e4SLinus Torvalds 	arr[0] = pq_pdt;
12681da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
126922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
12705a09e398SHannes Reinecke 		kfree(arr);
12711da177e4SLinus Torvalds 		return check_condition_result;
12721da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
12735a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1274c65b1445SDouglas Gilbert 		char lu_id_str[6];
1275c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
12761da177e4SLinus Torvalds 
12775a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
12785a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1279b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
128023183910SDouglas Gilbert 			host_no = 0;
1281c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1282c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1283c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1284c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1285c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
12861da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1287c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1288c65b1445SDouglas Gilbert 			n = 4;
1289c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1290c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1291c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1292c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1293c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1294c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1295c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1296c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1297760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1298c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1299760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1300760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1301760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1302760f3b03SDouglas Gilbert 			}
1303c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
13041da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1305c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13061da177e4SLinus Torvalds 			arr[3] = len;
1307c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
13081da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1309c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1310760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
13115a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
131209ba24c1SDouglas Gilbert 						lu_id_str, len,
131309ba24c1SDouglas Gilbert 						&devip->lu_name);
1314c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1315c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1316760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1317c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1318c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1319760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1320c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1321c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1322c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1323773642d9SDouglas Gilbert 			if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
1324c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1325760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1326c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1327c6a44287SMartin K. Petersen 			else
1328c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1329c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1330c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1331c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1332c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1333c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1334c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1335c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1336c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1337c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1338c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1339760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1340760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1341c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1342760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1343773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1344760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1345c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1346760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1347760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1348eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1349760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1350760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
13516014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1352760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
13531da177e4SLinus Torvalds 		} else {
135422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13555a09e398SHannes Reinecke 			kfree(arr);
13561da177e4SLinus Torvalds 			return check_condition_result;
13571da177e4SLinus Torvalds 		}
1358773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
13595a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1360c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13615a09e398SHannes Reinecke 		kfree(arr);
13625a09e398SHannes Reinecke 		return ret;
13631da177e4SLinus Torvalds 	}
13641da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1365773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1366773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
13671da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
13681da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1369f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1370b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
13715a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1372c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
13731da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1374c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
13751da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
13761da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
13771da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
13781da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1379760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1380760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1381c65b1445SDouglas Gilbert 	n = 62;
1382760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1383760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1384760f3b03SDouglas Gilbert 		n += 2;
1385760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1386760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1387760f3b03SDouglas Gilbert 		n += 2;
13881da177e4SLinus Torvalds 	}
1389760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
13905a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
13911da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
13925a09e398SHannes Reinecke 	kfree(arr);
13935a09e398SHannes Reinecke 	return ret;
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds 
1396fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1397fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1398fd32119bSDouglas Gilbert 
13991da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
14001da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
14011da177e4SLinus Torvalds {
14021da177e4SLinus Torvalds 	unsigned char * sbuff;
140301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1404cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
14052492fc09STomas Winkler 	bool dsense;
14061da177e4SLinus Torvalds 	int len = 18;
14071da177e4SLinus Torvalds 
1408c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1409c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1410cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1411c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1412c2248fc9SDouglas Gilbert 		if (dsense) {
1413c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1414c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1415c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1416c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1417c2248fc9SDouglas Gilbert 			len = 8;
1418c65b1445SDouglas Gilbert 		} else {
1419c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1420c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1421c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1422c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1423c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1424c65b1445SDouglas Gilbert 		}
1425c65b1445SDouglas Gilbert 	} else {
1426cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1427773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1428c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1429c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1430c2248fc9SDouglas Gilbert 			if (dsense) {
1431c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1432c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1433c2248fc9SDouglas Gilbert 				len = 8;
1434c2248fc9SDouglas Gilbert 			} else {
1435c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1436c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1437c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1438c2248fc9SDouglas Gilbert 			}
1439c2248fc9SDouglas Gilbert 		} else if (dsense) {
1440c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14411da177e4SLinus Torvalds 			arr[0] = 0x72;
14421da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14431da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14441da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14451da177e4SLinus Torvalds 			len = 8;
1446c2248fc9SDouglas Gilbert 		} else {
1447c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1448c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1449c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1450c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1451c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1452c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1453c65b1445SDouglas Gilbert 		}
1454c2248fc9SDouglas Gilbert 
1455c65b1445SDouglas Gilbert 	}
1456cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14571da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14581da177e4SLinus Torvalds }
14591da177e4SLinus Torvalds 
1460c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1461c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1462c65b1445SDouglas Gilbert {
146301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1464c4837394SDouglas Gilbert 	int power_cond, stop;
1465c65b1445SDouglas Gilbert 
1466c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1467c65b1445SDouglas Gilbert 	if (power_cond) {
146822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1469c65b1445SDouglas Gilbert 		return check_condition_result;
1470c65b1445SDouglas Gilbert 	}
1471c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1472c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
1473c65b1445SDouglas Gilbert 	return 0;
1474c65b1445SDouglas Gilbert }
1475c65b1445SDouglas Gilbert 
147628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
147728898873SFUJITA Tomonori {
1478773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1479773642d9SDouglas Gilbert 
1480773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1481773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1482773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
148328898873SFUJITA Tomonori 	else
148428898873SFUJITA Tomonori 		return sdebug_store_sectors;
148528898873SFUJITA Tomonori }
148628898873SFUJITA Tomonori 
14871da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
14881da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
14891da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
14901da177e4SLinus Torvalds {
14911da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1492c65b1445SDouglas Gilbert 	unsigned int capac;
14931da177e4SLinus Torvalds 
1494c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
149528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
14961da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1497c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1498c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1499773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1500773642d9SDouglas Gilbert 	} else
1501773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1502773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
15031da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
15041da177e4SLinus Torvalds }
15051da177e4SLinus Torvalds 
1506c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1507c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1508c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1509c65b1445SDouglas Gilbert {
151001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1511c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1512773642d9SDouglas Gilbert 	int alloc_len;
1513c65b1445SDouglas Gilbert 
1514773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1515c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
151628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1517c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1518773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1519773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1520773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1521773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
152244d92694SMartin K. Petersen 
1523be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15245b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1525760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1526760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1527760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1528760f3b03SDouglas Gilbert 		 */
1529760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1530760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1531be1dd78dSEric Sandeen 	}
153244d92694SMartin K. Petersen 
1533773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1534c6a44287SMartin K. Petersen 
1535760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1536773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1537c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1538c6a44287SMartin K. Petersen 	}
1539c6a44287SMartin K. Petersen 
1540c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1541c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1542c65b1445SDouglas Gilbert }
1543c65b1445SDouglas Gilbert 
15445a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15455a09e398SHannes Reinecke 
15465a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15475a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15485a09e398SHannes Reinecke {
154901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15505a09e398SHannes Reinecke 	unsigned char * arr;
15515a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15525a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15535a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15545a09e398SHannes Reinecke 
1555773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
15566f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15576f3cbf55SDouglas Gilbert 	if (! arr)
15586f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15595a09e398SHannes Reinecke 	/*
15605a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15615a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15625a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15635a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
15645a09e398SHannes Reinecke 	 */
15655a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
15665a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
15675a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
15685a09e398SHannes Reinecke 			(devip->channel & 0x7f);
15695a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
15705a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
15715a09e398SHannes Reinecke 
15725a09e398SHannes Reinecke 	/*
15735a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
15745a09e398SHannes Reinecke 	 */
15755a09e398SHannes Reinecke 	n = 4;
1576b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
15775a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
15785a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
15795a09e398SHannes Reinecke 	} else {
15805a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1581773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
15825a09e398SHannes Reinecke 	}
1583773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1584773642d9SDouglas Gilbert 	n += 2;
15855a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15865a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15875a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15885a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15895a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15905a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1591773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1592773642d9SDouglas Gilbert 	n += 2;
15935a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
15945a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1595773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1596773642d9SDouglas Gilbert 	n += 2;
15975a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15985a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15995a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16005a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16015a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16025a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1603773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1604773642d9SDouglas Gilbert 	n += 2;
16055a09e398SHannes Reinecke 
16065a09e398SHannes Reinecke 	rlen = n - 4;
1607773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
16085a09e398SHannes Reinecke 
16095a09e398SHannes Reinecke 	/*
16105a09e398SHannes Reinecke 	 * Return the smallest value of either
16115a09e398SHannes Reinecke 	 * - The allocated length
16125a09e398SHannes Reinecke 	 * - The constructed command length
16135a09e398SHannes Reinecke 	 * - The maximum array size
16145a09e398SHannes Reinecke 	 */
16155a09e398SHannes Reinecke 	rlen = min(alen,n);
16165a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16175a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16185a09e398SHannes Reinecke 	kfree(arr);
16195a09e398SHannes Reinecke 	return ret;
16205a09e398SHannes Reinecke }
16215a09e398SHannes Reinecke 
1622fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1623fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
162438d5c833SDouglas Gilbert {
162538d5c833SDouglas Gilbert 	bool rctd;
162638d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
162738d5c833SDouglas Gilbert 	u16 req_sa, u;
162838d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
162938d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
163038d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
163138d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
163238d5c833SDouglas Gilbert 	u8 *arr;
163338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
163438d5c833SDouglas Gilbert 
163538d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
163638d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
163738d5c833SDouglas Gilbert 	req_opcode = cmd[3];
163838d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
163938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16406d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
164138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
164238d5c833SDouglas Gilbert 		return check_condition_result;
164338d5c833SDouglas Gilbert 	}
164438d5c833SDouglas Gilbert 	if (alloc_len > 8192)
164538d5c833SDouglas Gilbert 		a_len = 8192;
164638d5c833SDouglas Gilbert 	else
164738d5c833SDouglas Gilbert 		a_len = alloc_len;
164899531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
164938d5c833SDouglas Gilbert 	if (NULL == arr) {
165038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
165138d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
165238d5c833SDouglas Gilbert 		return check_condition_result;
165338d5c833SDouglas Gilbert 	}
165438d5c833SDouglas Gilbert 	switch (reporting_opts) {
165538d5c833SDouglas Gilbert 	case 0:	/* all commands */
165638d5c833SDouglas Gilbert 		/* count number of commands */
165738d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
165838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
165938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
166038d5c833SDouglas Gilbert 				continue;
166138d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
166238d5c833SDouglas Gilbert 		}
166338d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
166438d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
166538d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
166638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
166738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
166838d5c833SDouglas Gilbert 				continue;
166938d5c833SDouglas Gilbert 			na = oip->num_attached;
167038d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
167138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
167238d5c833SDouglas Gilbert 			if (rctd)
167338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
167438d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
167538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
167638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
167738d5c833SDouglas Gilbert 			if (rctd)
167838d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
167938d5c833SDouglas Gilbert 			r_oip = oip;
168038d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
168138d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
168238d5c833SDouglas Gilbert 					continue;
168338d5c833SDouglas Gilbert 				offset += bump;
168438d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
168538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
168638d5c833SDouglas Gilbert 				if (rctd)
168738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
168838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
168938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
169038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
169138d5c833SDouglas Gilbert 						   arr + offset + 6);
169238d5c833SDouglas Gilbert 				if (rctd)
169338d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
169438d5c833SDouglas Gilbert 							   arr + offset + 8);
169538d5c833SDouglas Gilbert 			}
169638d5c833SDouglas Gilbert 			oip = r_oip;
169738d5c833SDouglas Gilbert 			offset += bump;
169838d5c833SDouglas Gilbert 		}
169938d5c833SDouglas Gilbert 		break;
170038d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
170138d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
170238d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
170338d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
170438d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
170538d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
170638d5c833SDouglas Gilbert 			supp = 1;
170738d5c833SDouglas Gilbert 			offset = 4;
170838d5c833SDouglas Gilbert 		} else {
170938d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
171038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
171138d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
171238d5c833SDouglas Gilbert 							     2, 2);
171338d5c833SDouglas Gilbert 					kfree(arr);
171438d5c833SDouglas Gilbert 					return check_condition_result;
171538d5c833SDouglas Gilbert 				}
171638d5c833SDouglas Gilbert 				req_sa = 0;
171738d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
171838d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
171938d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
172038d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
172138d5c833SDouglas Gilbert 				return check_condition_result;
172238d5c833SDouglas Gilbert 			}
172338d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
172438d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
172538d5c833SDouglas Gilbert 				supp = 3;
172638d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
172738d5c833SDouglas Gilbert 				na = oip->num_attached;
172838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
172938d5c833SDouglas Gilbert 				     ++k, ++oip) {
173038d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
173138d5c833SDouglas Gilbert 						break;
173238d5c833SDouglas Gilbert 				}
173338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
173438d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
173538d5c833SDouglas Gilbert 				na = oip->num_attached;
173638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
173738d5c833SDouglas Gilbert 				     ++k, ++oip) {
173838d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
173938d5c833SDouglas Gilbert 						break;
174038d5c833SDouglas Gilbert 				}
174138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
174238d5c833SDouglas Gilbert 			} else
174338d5c833SDouglas Gilbert 				supp = 3;
174438d5c833SDouglas Gilbert 			if (3 == supp) {
174538d5c833SDouglas Gilbert 				u = oip->len_mask[0];
174638d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
174738d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
174838d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
174938d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
175038d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
175138d5c833SDouglas Gilbert 				offset = 4 + u;
175238d5c833SDouglas Gilbert 			} else
175338d5c833SDouglas Gilbert 				offset = 4;
175438d5c833SDouglas Gilbert 		}
175538d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
175638d5c833SDouglas Gilbert 		if (rctd) {
175738d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
175838d5c833SDouglas Gilbert 			offset += 12;
175938d5c833SDouglas Gilbert 		}
176038d5c833SDouglas Gilbert 		break;
176138d5c833SDouglas Gilbert 	default:
176238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
176338d5c833SDouglas Gilbert 		kfree(arr);
176438d5c833SDouglas Gilbert 		return check_condition_result;
176538d5c833SDouglas Gilbert 	}
176638d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
176738d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
176838d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
176938d5c833SDouglas Gilbert 	kfree(arr);
177038d5c833SDouglas Gilbert 	return errsts;
177138d5c833SDouglas Gilbert }
177238d5c833SDouglas Gilbert 
1773fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1774fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
177538d5c833SDouglas Gilbert {
177638d5c833SDouglas Gilbert 	bool repd;
177738d5c833SDouglas Gilbert 	u32 alloc_len, len;
177838d5c833SDouglas Gilbert 	u8 arr[16];
177938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
178038d5c833SDouglas Gilbert 
178138d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
178238d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
178338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
178438d5c833SDouglas Gilbert 	if (alloc_len < 4) {
178538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
178638d5c833SDouglas Gilbert 		return check_condition_result;
178738d5c833SDouglas Gilbert 	}
178838d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
178938d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
179038d5c833SDouglas Gilbert 	if (repd) {
179138d5c833SDouglas Gilbert 		arr[3] = 0xc;
179238d5c833SDouglas Gilbert 		len = 16;
179338d5c833SDouglas Gilbert 	} else
179438d5c833SDouglas Gilbert 		len = 4;
179538d5c833SDouglas Gilbert 
179638d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
179738d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
179838d5c833SDouglas Gilbert }
179938d5c833SDouglas Gilbert 
18001da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
18011da177e4SLinus Torvalds 
18021da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
18031da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
18041da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
18051da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
18061da177e4SLinus Torvalds 
18071da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
18081da177e4SLinus Torvalds 	if (1 == pcontrol)
18091da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
18101da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
18111da177e4SLinus Torvalds }
18121da177e4SLinus Torvalds 
18131da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
18141da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18151da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18161da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18191da177e4SLinus Torvalds 	if (1 == pcontrol)
18201da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18211da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18221da177e4SLinus Torvalds }
18231da177e4SLinus Torvalds 
18241da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18251da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18261da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18271da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18281da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18291da177e4SLinus Torvalds 
18301da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1831773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1832773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1833773642d9SDouglas Gilbert 	if (sdebug_removable)
18341da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18351da177e4SLinus Torvalds 	if (1 == pcontrol)
18361da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18371da177e4SLinus Torvalds 	return sizeof(format_pg);
18381da177e4SLinus Torvalds }
18391da177e4SLinus Torvalds 
1840fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1841fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1842fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1843fd32119bSDouglas Gilbert 
18441da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18451da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1846cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1847cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1848cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18491da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18501da177e4SLinus Torvalds 
1851773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1852cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18531da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18541da177e4SLinus Torvalds 	if (1 == pcontrol)
1855cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1856cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1857cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18581da177e4SLinus Torvalds 	return sizeof(caching_pg);
18591da177e4SLinus Torvalds }
18601da177e4SLinus Torvalds 
1861fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1862fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1863fd32119bSDouglas Gilbert 
18641da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
18651da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1866c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1867c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1868c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
18691da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
18701da177e4SLinus Torvalds 
1871773642d9SDouglas Gilbert 	if (sdebug_dsense)
18721da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1873c65b1445SDouglas Gilbert 	else
1874c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1875c6a44287SMartin K. Petersen 
1876773642d9SDouglas Gilbert 	if (sdebug_ato)
1877c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1878c6a44287SMartin K. Petersen 
18791da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
18801da177e4SLinus Torvalds 	if (1 == pcontrol)
1881c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1882c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1883c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
18841da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
18851da177e4SLinus Torvalds }
18861da177e4SLinus Torvalds 
1887c65b1445SDouglas Gilbert 
18881da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
18891da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1890c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
18911da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1892c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1893c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1894c65b1445SDouglas Gilbert 
18951da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
18961da177e4SLinus Torvalds 	if (1 == pcontrol)
1897c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1898c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1899c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
19001da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
19011da177e4SLinus Torvalds }
19021da177e4SLinus Torvalds 
1903c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1904c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1905c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1906c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1907c65b1445SDouglas Gilbert 
1908c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1909c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1910c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1911c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1912c65b1445SDouglas Gilbert }
1913c65b1445SDouglas Gilbert 
1914c65b1445SDouglas Gilbert 
1915c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1916c65b1445SDouglas Gilbert 			      int target_dev_id)
1917c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1918c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1919c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1920773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1921773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1922c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1923c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1924c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1925c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1926773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1927773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1928c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1929c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1930c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1931c65b1445SDouglas Gilbert 		};
1932c65b1445SDouglas Gilbert 	int port_a, port_b;
1933c65b1445SDouglas Gilbert 
1934773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1935773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1936773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1937773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
1938c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1939c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1940c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1941773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
1942773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
1943c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1944c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1945c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1946c65b1445SDouglas Gilbert }
1947c65b1445SDouglas Gilbert 
1948c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1949c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1950c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1951c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1952c65b1445SDouglas Gilbert 		};
1953c65b1445SDouglas Gilbert 
1954c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1955c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1956c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1957c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1958c65b1445SDouglas Gilbert }
1959c65b1445SDouglas Gilbert 
19601da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19611da177e4SLinus Torvalds 
1962fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
1963fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
19641da177e4SLinus Torvalds {
196523183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
19661da177e4SLinus Torvalds 	unsigned char dev_spec;
1967760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
1968c2248fc9SDouglas Gilbert 	int target = scp->device->id;
19691da177e4SLinus Torvalds 	unsigned char * ap;
19701da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
197101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1972760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
19731da177e4SLinus Torvalds 
1974760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
19751da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
19761da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
19771da177e4SLinus Torvalds 	subpcode = cmd[3];
19781da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
1979760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
1980760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1981760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
198223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
198323183910SDouglas Gilbert 	else
198423183910SDouglas Gilbert 		bd_len = 0;
1985773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
19861da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
19871da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
1988cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
19891da177e4SLinus Torvalds 		return check_condition_result;
19901da177e4SLinus Torvalds 	}
1991c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1992c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
1993b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
1994760f3b03SDouglas Gilbert 	if (is_disk)
1995b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
199623183910SDouglas Gilbert 	else
199723183910SDouglas Gilbert 		dev_spec = 0x0;
19981da177e4SLinus Torvalds 	if (msense_6) {
19991da177e4SLinus Torvalds 		arr[2] = dev_spec;
200023183910SDouglas Gilbert 		arr[3] = bd_len;
20011da177e4SLinus Torvalds 		offset = 4;
20021da177e4SLinus Torvalds 	} else {
20031da177e4SLinus Torvalds 		arr[3] = dev_spec;
200423183910SDouglas Gilbert 		if (16 == bd_len)
200523183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
200623183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
20071da177e4SLinus Torvalds 		offset = 8;
20081da177e4SLinus Torvalds 	}
20091da177e4SLinus Torvalds 	ap = arr + offset;
201028898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
201128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
201228898873SFUJITA Tomonori 
201323183910SDouglas Gilbert 	if (8 == bd_len) {
2014773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2015773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2016773642d9SDouglas Gilbert 		else
2017773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2018773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
201923183910SDouglas Gilbert 		offset += bd_len;
202023183910SDouglas Gilbert 		ap = arr + offset;
202123183910SDouglas Gilbert 	} else if (16 == bd_len) {
2022773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2023773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
202423183910SDouglas Gilbert 		offset += bd_len;
202523183910SDouglas Gilbert 		ap = arr + offset;
202623183910SDouglas Gilbert 	}
20271da177e4SLinus Torvalds 
2028c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2029c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
203022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20311da177e4SLinus Torvalds 		return check_condition_result;
20321da177e4SLinus Torvalds 	}
2033760f3b03SDouglas Gilbert 	bad_pcode = false;
2034760f3b03SDouglas Gilbert 
20351da177e4SLinus Torvalds 	switch (pcode) {
20361da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20371da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20381da177e4SLinus Torvalds 		offset += len;
20391da177e4SLinus Torvalds 		break;
20401da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20411da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20421da177e4SLinus Torvalds 		offset += len;
20431da177e4SLinus Torvalds 		break;
20441da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
2045760f3b03SDouglas Gilbert 		if (is_disk) {
20461da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
20471da177e4SLinus Torvalds 			offset += len;
2048760f3b03SDouglas Gilbert 		} else
2049760f3b03SDouglas Gilbert 			bad_pcode = true;
20501da177e4SLinus Torvalds                 break;
20511da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2052760f3b03SDouglas Gilbert 		if (is_disk) {
20531da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
20541da177e4SLinus Torvalds 			offset += len;
2055760f3b03SDouglas Gilbert 		} else
2056760f3b03SDouglas Gilbert 			bad_pcode = true;
20571da177e4SLinus Torvalds 		break;
20581da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20591da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20601da177e4SLinus Torvalds 		offset += len;
20611da177e4SLinus Torvalds 		break;
2062c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2063c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
206422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2065c65b1445SDouglas Gilbert 			return check_condition_result;
2066c65b1445SDouglas Gilbert 	        }
2067c65b1445SDouglas Gilbert 		len = 0;
2068c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2069c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2070c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2071c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2072c65b1445SDouglas Gilbert 						  target_dev_id);
2073c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2074c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2075c65b1445SDouglas Gilbert 		offset += len;
2076c65b1445SDouglas Gilbert 		break;
20771da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
20781da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
20791da177e4SLinus Torvalds 		offset += len;
20801da177e4SLinus Torvalds 		break;
20811da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2082c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
20831da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
20841da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2085760f3b03SDouglas Gilbert 			if (is_disk) {
2086760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2087760f3b03SDouglas Gilbert 						      target);
2088760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2089760f3b03SDouglas Gilbert 						       target);
2090760f3b03SDouglas Gilbert 			}
20911da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2092c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2093c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2094c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2095c65b1445SDouglas Gilbert 						  target, target_dev_id);
2096c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2097c65b1445SDouglas Gilbert 			}
20981da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2099760f3b03SDouglas Gilbert 			offset += len;
2100c65b1445SDouglas Gilbert 		} else {
210122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2102c65b1445SDouglas Gilbert 			return check_condition_result;
2103c65b1445SDouglas Gilbert                 }
21041da177e4SLinus Torvalds 		break;
21051da177e4SLinus Torvalds 	default:
2106760f3b03SDouglas Gilbert 		bad_pcode = true;
2107760f3b03SDouglas Gilbert 		break;
2108760f3b03SDouglas Gilbert 	}
2109760f3b03SDouglas Gilbert 	if (bad_pcode) {
211022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
21111da177e4SLinus Torvalds 		return check_condition_result;
21121da177e4SLinus Torvalds 	}
21131da177e4SLinus Torvalds 	if (msense_6)
21141da177e4SLinus Torvalds 		arr[0] = offset - 1;
2115773642d9SDouglas Gilbert 	else
2116773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
21171da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
21181da177e4SLinus Torvalds }
21191da177e4SLinus Torvalds 
2120c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2121c65b1445SDouglas Gilbert 
2122fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2123fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2124c65b1445SDouglas Gilbert {
2125c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2126c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2127c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
212801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2129c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2130c65b1445SDouglas Gilbert 
2131c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2132c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2133c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2134773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2135c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
213622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2137c65b1445SDouglas Gilbert 		return check_condition_result;
2138c65b1445SDouglas Gilbert 	}
2139c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2140c65b1445SDouglas Gilbert         if (-1 == res)
2141773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2142773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2143cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2144cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2145cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2146773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2147773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
214823183910SDouglas Gilbert 	if (md_len > 2) {
214922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2150c65b1445SDouglas Gilbert 		return check_condition_result;
2151c65b1445SDouglas Gilbert 	}
2152c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2153c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2154c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2155c65b1445SDouglas Gilbert 	if (ps) {
215622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2157c65b1445SDouglas Gilbert 		return check_condition_result;
2158c65b1445SDouglas Gilbert 	}
2159c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2160773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2161c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2162c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2163cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2164c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2165c65b1445SDouglas Gilbert 		return check_condition_result;
2166c65b1445SDouglas Gilbert 	}
2167c65b1445SDouglas Gilbert 	switch (mpage) {
2168cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2169cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2170cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2171cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2172cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2173cbf67842SDouglas Gilbert 		}
2174cbf67842SDouglas Gilbert 		break;
2175c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2176c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2177c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2178c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2179773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2180cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2181c65b1445SDouglas Gilbert 		}
2182c65b1445SDouglas Gilbert 		break;
2183c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2184c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2185c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2186c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2187cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2188c65b1445SDouglas Gilbert 		}
2189c65b1445SDouglas Gilbert 		break;
2190c65b1445SDouglas Gilbert 	default:
2191c65b1445SDouglas Gilbert 		break;
2192c65b1445SDouglas Gilbert 	}
219322017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2194c65b1445SDouglas Gilbert 	return check_condition_result;
2195cbf67842SDouglas Gilbert set_mode_changed_ua:
2196cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2197cbf67842SDouglas Gilbert 	return 0;
2198c65b1445SDouglas Gilbert }
2199c65b1445SDouglas Gilbert 
2200c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2201c65b1445SDouglas Gilbert {
2202c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2203c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2204c65b1445SDouglas Gilbert 		};
2205c65b1445SDouglas Gilbert 
2206c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2207c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2208c65b1445SDouglas Gilbert }
2209c65b1445SDouglas Gilbert 
2210c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2211c65b1445SDouglas Gilbert {
2212c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2213c65b1445SDouglas Gilbert 		};
2214c65b1445SDouglas Gilbert 
2215c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2216c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2217c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2218c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2219c65b1445SDouglas Gilbert 	}
2220c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2221c65b1445SDouglas Gilbert }
2222c65b1445SDouglas Gilbert 
2223c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2224c65b1445SDouglas Gilbert 
2225c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2226c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2227c65b1445SDouglas Gilbert {
2228c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2229c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
223001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2231c65b1445SDouglas Gilbert 
2232c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2233c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2234c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2235c65b1445SDouglas Gilbert 	if (ppc || sp) {
223622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2237c65b1445SDouglas Gilbert 		return check_condition_result;
2238c65b1445SDouglas Gilbert 	}
2239c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2240c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
224123183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2242773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2243c65b1445SDouglas Gilbert 	arr[0] = pcode;
224423183910SDouglas Gilbert 	if (0 == subpcode) {
2245c65b1445SDouglas Gilbert 		switch (pcode) {
2246c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2247c65b1445SDouglas Gilbert 			n = 4;
2248c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2249c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2250c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2251c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2252c65b1445SDouglas Gilbert 			break;
2253c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2254c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2255c65b1445SDouglas Gilbert 			break;
2256c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2257c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2258c65b1445SDouglas Gilbert 			break;
2259c65b1445SDouglas Gilbert 		default:
226022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2261c65b1445SDouglas Gilbert 			return check_condition_result;
2262c65b1445SDouglas Gilbert 		}
226323183910SDouglas Gilbert 	} else if (0xff == subpcode) {
226423183910SDouglas Gilbert 		arr[0] |= 0x40;
226523183910SDouglas Gilbert 		arr[1] = subpcode;
226623183910SDouglas Gilbert 		switch (pcode) {
226723183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
226823183910SDouglas Gilbert 			n = 4;
226923183910SDouglas Gilbert 			arr[n++] = 0x0;
227023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
227123183910SDouglas Gilbert 			arr[n++] = 0x0;
227223183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
227323183910SDouglas Gilbert 			arr[n++] = 0xd;
227423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
227523183910SDouglas Gilbert 			arr[n++] = 0x2f;
227623183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
227723183910SDouglas Gilbert 			arr[3] = n - 4;
227823183910SDouglas Gilbert 			break;
227923183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
228023183910SDouglas Gilbert 			n = 4;
228123183910SDouglas Gilbert 			arr[n++] = 0xd;
228223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
228323183910SDouglas Gilbert 			arr[3] = n - 4;
228423183910SDouglas Gilbert 			break;
228523183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
228623183910SDouglas Gilbert 			n = 4;
228723183910SDouglas Gilbert 			arr[n++] = 0x2f;
228823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
228923183910SDouglas Gilbert 			arr[3] = n - 4;
229023183910SDouglas Gilbert 			break;
229123183910SDouglas Gilbert 		default:
229222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
229323183910SDouglas Gilbert 			return check_condition_result;
229423183910SDouglas Gilbert 		}
229523183910SDouglas Gilbert 	} else {
229622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
229723183910SDouglas Gilbert 		return check_condition_result;
229823183910SDouglas Gilbert 	}
2299773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2300c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2301c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2302c65b1445SDouglas Gilbert }
2303c65b1445SDouglas Gilbert 
2304cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
230519789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
23061da177e4SLinus Torvalds {
2307c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
230822017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
23091da177e4SLinus Torvalds 		return check_condition_result;
23101da177e4SLinus Torvalds 	}
2311c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2312c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
231322017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2314cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2315c65b1445SDouglas Gilbert 		return check_condition_result;
2316c65b1445SDouglas Gilbert 	}
231719789100SFUJITA Tomonori 	return 0;
231819789100SFUJITA Tomonori }
231919789100SFUJITA Tomonori 
2320a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2321fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2322fd32119bSDouglas Gilbert 			    bool do_write)
232319789100SFUJITA Tomonori {
232419789100SFUJITA Tomonori 	int ret;
2325c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2326a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2327a4517511SAkinobu Mita 	enum dma_data_direction dir;
232819789100SFUJITA Tomonori 
2329c2248fc9SDouglas Gilbert 	if (do_write) {
2330a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2331a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2332a4517511SAkinobu Mita 	} else {
2333a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2334a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2335a4517511SAkinobu Mita 	}
2336a4517511SAkinobu Mita 
2337a4517511SAkinobu Mita 	if (!sdb->length)
2338a4517511SAkinobu Mita 		return 0;
2339a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2340a4517511SAkinobu Mita 		return -1;
234119789100SFUJITA Tomonori 
234219789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
234319789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
234419789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
234519789100SFUJITA Tomonori 
2346386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2347773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2348773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2349773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2350a4517511SAkinobu Mita 		return ret;
2351a4517511SAkinobu Mita 
2352a4517511SAkinobu Mita 	if (rest) {
2353386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2354773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2355773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2356a4517511SAkinobu Mita 	}
235719789100SFUJITA Tomonori 
235819789100SFUJITA Tomonori 	return ret;
235919789100SFUJITA Tomonori }
236019789100SFUJITA Tomonori 
236138d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
236238d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
236338d5c833SDouglas Gilbert  * return false. */
2364fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
236538d5c833SDouglas Gilbert {
236638d5c833SDouglas Gilbert 	bool res;
236738d5c833SDouglas Gilbert 	u64 block, rest = 0;
236838d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2369773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
237038d5c833SDouglas Gilbert 
237138d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
237238d5c833SDouglas Gilbert 	if (block + num > store_blks)
237338d5c833SDouglas Gilbert 		rest = block + num - store_blks;
237438d5c833SDouglas Gilbert 
237538d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
237638d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
237738d5c833SDouglas Gilbert 	if (!res)
237838d5c833SDouglas Gilbert 		return res;
237938d5c833SDouglas Gilbert 	if (rest)
238038d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
238138d5c833SDouglas Gilbert 			     rest * lb_size);
238238d5c833SDouglas Gilbert 	if (!res)
238338d5c833SDouglas Gilbert 		return res;
238438d5c833SDouglas Gilbert 	arr += num * lb_size;
238538d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
238638d5c833SDouglas Gilbert 	if (rest)
238738d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
238838d5c833SDouglas Gilbert 		       rest * lb_size);
238938d5c833SDouglas Gilbert 	return res;
239038d5c833SDouglas Gilbert }
239138d5c833SDouglas Gilbert 
239251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2393beb40ea4SAkinobu Mita {
239451d648afSAkinobu Mita 	__be16 csum;
2395beb40ea4SAkinobu Mita 
2396773642d9SDouglas Gilbert 	if (sdebug_guard)
239751d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
239851d648afSAkinobu Mita 	else
2399beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
240051d648afSAkinobu Mita 
2401beb40ea4SAkinobu Mita 	return csum;
2402beb40ea4SAkinobu Mita }
2403beb40ea4SAkinobu Mita 
2404beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2405beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2406beb40ea4SAkinobu Mita {
2407773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2408beb40ea4SAkinobu Mita 
2409beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2410c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2411beb40ea4SAkinobu Mita 			(unsigned long)sector,
2412beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2413beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2414beb40ea4SAkinobu Mita 		return 0x01;
2415beb40ea4SAkinobu Mita 	}
2416773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
2417beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2418c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2419c1287970STomas Winkler 			(unsigned long)sector);
2420beb40ea4SAkinobu Mita 		return 0x03;
2421beb40ea4SAkinobu Mita 	}
2422773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2423beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2424c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2425c1287970STomas Winkler 			(unsigned long)sector);
2426beb40ea4SAkinobu Mita 		return 0x03;
2427beb40ea4SAkinobu Mita 	}
2428beb40ea4SAkinobu Mita 	return 0;
2429beb40ea4SAkinobu Mita }
2430beb40ea4SAkinobu Mita 
2431bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
243265f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2433c6a44287SMartin K. Petersen {
2434be4e11beSAkinobu Mita 	size_t resid;
2435c6a44287SMartin K. Petersen 	void *paddr;
243614faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2437be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2438c6a44287SMartin K. Petersen 
2439e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2440e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2441c6a44287SMartin K. Petersen 
2442be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2443be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2444be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2445be4e11beSAkinobu Mita 
2446be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2447be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
244814faa944SAkinobu Mita 		void *start = dif_store(sector);
2449be4e11beSAkinobu Mita 		size_t rest = 0;
245014faa944SAkinobu Mita 
245114faa944SAkinobu Mita 		if (dif_store_end < start + len)
245214faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2453c6a44287SMartin K. Petersen 
2454be4e11beSAkinobu Mita 		paddr = miter.addr;
245514faa944SAkinobu Mita 
245665f72f2aSAkinobu Mita 		if (read)
245765f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
245865f72f2aSAkinobu Mita 		else
245965f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
246065f72f2aSAkinobu Mita 
246165f72f2aSAkinobu Mita 		if (rest) {
246265f72f2aSAkinobu Mita 			if (read)
246314faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
246465f72f2aSAkinobu Mita 			else
246565f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
246665f72f2aSAkinobu Mita 		}
2467c6a44287SMartin K. Petersen 
2468e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2469c6a44287SMartin K. Petersen 		resid -= len;
2470c6a44287SMartin K. Petersen 	}
2471be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2472bb8c063cSAkinobu Mita }
2473c6a44287SMartin K. Petersen 
2474bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2475bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2476bb8c063cSAkinobu Mita {
2477bb8c063cSAkinobu Mita 	unsigned int i;
2478bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
2479bb8c063cSAkinobu Mita 	sector_t sector;
2480bb8c063cSAkinobu Mita 
2481c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2482bb8c063cSAkinobu Mita 		int ret;
2483bb8c063cSAkinobu Mita 
2484bb8c063cSAkinobu Mita 		sector = start_sec + i;
2485bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2486bb8c063cSAkinobu Mita 
248751d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2488bb8c063cSAkinobu Mita 			continue;
2489bb8c063cSAkinobu Mita 
2490bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2491bb8c063cSAkinobu Mita 		if (ret) {
2492bb8c063cSAkinobu Mita 			dif_errors++;
2493bb8c063cSAkinobu Mita 			return ret;
2494bb8c063cSAkinobu Mita 		}
2495bb8c063cSAkinobu Mita 	}
2496bb8c063cSAkinobu Mita 
249765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2498c6a44287SMartin K. Petersen 	dix_reads++;
2499c6a44287SMartin K. Petersen 
2500c6a44287SMartin K. Petersen 	return 0;
2501c6a44287SMartin K. Petersen }
2502c6a44287SMartin K. Petersen 
2503fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
250419789100SFUJITA Tomonori {
2505c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2506c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2507c2248fc9SDouglas Gilbert 	u64 lba;
2508c2248fc9SDouglas Gilbert 	u32 num;
2509c2248fc9SDouglas Gilbert 	u32 ei_lba;
251019789100SFUJITA Tomonori 	unsigned long iflags;
251119789100SFUJITA Tomonori 	int ret;
2512c2248fc9SDouglas Gilbert 	bool check_prot;
251319789100SFUJITA Tomonori 
2514c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2515c2248fc9SDouglas Gilbert 	case READ_16:
2516c2248fc9SDouglas Gilbert 		ei_lba = 0;
2517c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2518c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2519c2248fc9SDouglas Gilbert 		check_prot = true;
2520c2248fc9SDouglas Gilbert 		break;
2521c2248fc9SDouglas Gilbert 	case READ_10:
2522c2248fc9SDouglas Gilbert 		ei_lba = 0;
2523c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2524c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2525c2248fc9SDouglas Gilbert 		check_prot = true;
2526c2248fc9SDouglas Gilbert 		break;
2527c2248fc9SDouglas Gilbert 	case READ_6:
2528c2248fc9SDouglas Gilbert 		ei_lba = 0;
2529c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2530c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2531c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2532c2248fc9SDouglas Gilbert 		check_prot = true;
2533c2248fc9SDouglas Gilbert 		break;
2534c2248fc9SDouglas Gilbert 	case READ_12:
2535c2248fc9SDouglas Gilbert 		ei_lba = 0;
2536c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2537c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2538c2248fc9SDouglas Gilbert 		check_prot = true;
2539c2248fc9SDouglas Gilbert 		break;
2540c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2541c2248fc9SDouglas Gilbert 		ei_lba = 0;
2542c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2543c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2544c2248fc9SDouglas Gilbert 		check_prot = false;
2545c2248fc9SDouglas Gilbert 		break;
2546c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2547c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2548c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2549c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2550c2248fc9SDouglas Gilbert 		check_prot = false;
2551c2248fc9SDouglas Gilbert 		break;
2552c2248fc9SDouglas Gilbert 	}
2553f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
2554773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2555c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2556c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2557c2248fc9SDouglas Gilbert 			return check_condition_result;
2558c2248fc9SDouglas Gilbert 		}
2559773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2560773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2561c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2562c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2563c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2564c2248fc9SDouglas Gilbert 	}
2565f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2566c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2567c2248fc9SDouglas Gilbert 
2568c4837394SDouglas Gilbert 		if (sqcp) {
2569c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2570c2248fc9SDouglas Gilbert 				num /= 2;
2571c2248fc9SDouglas Gilbert 		}
2572c4837394SDouglas Gilbert 	} else
2573c4837394SDouglas Gilbert 		sqcp = NULL;
2574c2248fc9SDouglas Gilbert 
2575c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2576f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2577c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2578c2248fc9SDouglas Gilbert 		return check_condition_result;
2579c2248fc9SDouglas Gilbert 	}
2580c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2581f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2582c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2583c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2584c2248fc9SDouglas Gilbert 		return check_condition_result;
2585c2248fc9SDouglas Gilbert 	}
258619789100SFUJITA Tomonori 
2587f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
258832f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2589f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2590c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2591c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2592c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2593c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2594c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
259532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
259632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2597c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2598c65b1445SDouglas Gilbert 		}
2599c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
26001da177e4SLinus Torvalds 		return check_condition_result;
26011da177e4SLinus Torvalds 	}
2602c6a44287SMartin K. Petersen 
26036c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
26046c78cc06SAkinobu Mita 
2605c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2606f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2607c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2608c6a44287SMartin K. Petersen 
2609c6a44287SMartin K. Petersen 		if (prot_ret) {
26106c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2611c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2612c6a44287SMartin K. Petersen 			return illegal_condition_result;
2613c6a44287SMartin K. Petersen 		}
2614c6a44287SMartin K. Petersen 	}
2615c6a44287SMartin K. Petersen 
2616c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
26171da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2618f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2619a4517511SAkinobu Mita 		return DID_ERROR << 16;
2620a4517511SAkinobu Mita 
2621c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2622a4517511SAkinobu Mita 
2623c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2624c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2625c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2626c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2627c2248fc9SDouglas Gilbert 			return check_condition_result;
2628c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2629c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2630c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2631c2248fc9SDouglas Gilbert 			return check_condition_result;
2632c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2633c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2634c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2635c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2636c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2637c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2638c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2639c2248fc9SDouglas Gilbert 		}
2640c2248fc9SDouglas Gilbert 	}
2641a4517511SAkinobu Mita 	return 0;
26421da177e4SLinus Torvalds }
26431da177e4SLinus Torvalds 
264458a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2645c6a44287SMartin K. Petersen {
2646cbf67842SDouglas Gilbert 	int i, j, n;
2647c6a44287SMartin K. Petersen 
2648cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2649c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2650cbf67842SDouglas Gilbert 		char b[128];
2651c6a44287SMartin K. Petersen 
2652cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2653c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2654c6a44287SMartin K. Petersen 
2655cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2656cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2657cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2658cbf67842SDouglas Gilbert 			else
2659cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2660cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2661cbf67842SDouglas Gilbert 		}
2662cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2663c6a44287SMartin K. Petersen 	}
2664c6a44287SMartin K. Petersen }
2665c6a44287SMartin K. Petersen 
2666c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2667395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2668c6a44287SMartin K. Petersen {
2669be4e11beSAkinobu Mita 	int ret;
2670c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2671be4e11beSAkinobu Mita 	void *daddr;
267265f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2673c6a44287SMartin K. Petersen 	int ppage_offset;
2674be4e11beSAkinobu Mita 	int dpage_offset;
2675be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2676be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2677c6a44287SMartin K. Petersen 
2678c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2679c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2680c6a44287SMartin K. Petersen 
2681be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2682be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2683be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2684be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2685be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2686c6a44287SMartin K. Petersen 
2687be4e11beSAkinobu Mita 	/* For each protection page */
2688be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2689be4e11beSAkinobu Mita 		dpage_offset = 0;
2690be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2691be4e11beSAkinobu Mita 			ret = 0x01;
2692be4e11beSAkinobu Mita 			goto out;
2693c6a44287SMartin K. Petersen 		}
2694c6a44287SMartin K. Petersen 
2695be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2696be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2697be4e11beSAkinobu Mita 			/* If we're at the end of the current
2698be4e11beSAkinobu Mita 			 * data page advance to the next one
2699be4e11beSAkinobu Mita 			 */
2700be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2701be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2702be4e11beSAkinobu Mita 					ret = 0x01;
2703be4e11beSAkinobu Mita 					goto out;
2704be4e11beSAkinobu Mita 				}
2705be4e11beSAkinobu Mita 				dpage_offset = 0;
2706be4e11beSAkinobu Mita 			}
2707c6a44287SMartin K. Petersen 
2708be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2709be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2710be4e11beSAkinobu Mita 
2711be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2712beb40ea4SAkinobu Mita 			if (ret) {
2713773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2714395cef03SMartin K. Petersen 				goto out;
2715395cef03SMartin K. Petersen 			}
2716395cef03SMartin K. Petersen 
2717c6a44287SMartin K. Petersen 			sector++;
2718395cef03SMartin K. Petersen 			ei_lba++;
2719773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2720c6a44287SMartin K. Petersen 		}
2721be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2722be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2723c6a44287SMartin K. Petersen 	}
2724be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2725c6a44287SMartin K. Petersen 
272665f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2727c6a44287SMartin K. Petersen 	dix_writes++;
2728c6a44287SMartin K. Petersen 
2729c6a44287SMartin K. Petersen 	return 0;
2730c6a44287SMartin K. Petersen 
2731c6a44287SMartin K. Petersen out:
2732c6a44287SMartin K. Petersen 	dif_errors++;
2733be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2734be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2735c6a44287SMartin K. Petersen 	return ret;
2736c6a44287SMartin K. Petersen }
2737c6a44287SMartin K. Petersen 
2738b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2739b90ebc3dSAkinobu Mita {
2740773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2741773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2742773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2743b90ebc3dSAkinobu Mita 	return lba;
2744b90ebc3dSAkinobu Mita }
2745b90ebc3dSAkinobu Mita 
2746b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2747b90ebc3dSAkinobu Mita {
2748773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2749a027b5b9SAkinobu Mita 
2750773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2751773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2752a027b5b9SAkinobu Mita 	return lba;
2753a027b5b9SAkinobu Mita }
2754a027b5b9SAkinobu Mita 
275544d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
275644d92694SMartin K. Petersen {
2757b90ebc3dSAkinobu Mita 	sector_t end;
2758b90ebc3dSAkinobu Mita 	unsigned int mapped;
2759b90ebc3dSAkinobu Mita 	unsigned long index;
2760b90ebc3dSAkinobu Mita 	unsigned long next;
276144d92694SMartin K. Petersen 
2762b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2763b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
276444d92694SMartin K. Petersen 
276544d92694SMartin K. Petersen 	if (mapped)
2766b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
276744d92694SMartin K. Petersen 	else
2768b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
276944d92694SMartin K. Petersen 
2770b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
277144d92694SMartin K. Petersen 	*num = end - lba;
277244d92694SMartin K. Petersen 	return mapped;
277344d92694SMartin K. Petersen }
277444d92694SMartin K. Petersen 
277544d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
277644d92694SMartin K. Petersen {
277744d92694SMartin K. Petersen 	sector_t end = lba + len;
277844d92694SMartin K. Petersen 
277944d92694SMartin K. Petersen 	while (lba < end) {
2780b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
278144d92694SMartin K. Petersen 
2782b90ebc3dSAkinobu Mita 		if (index < map_size)
2783b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
278444d92694SMartin K. Petersen 
2785b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
278644d92694SMartin K. Petersen 	}
278744d92694SMartin K. Petersen }
278844d92694SMartin K. Petersen 
278944d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
279044d92694SMartin K. Petersen {
279144d92694SMartin K. Petersen 	sector_t end = lba + len;
279244d92694SMartin K. Petersen 
279344d92694SMartin K. Petersen 	while (lba < end) {
2794b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
279544d92694SMartin K. Petersen 
2796b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2797773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2798b90ebc3dSAkinobu Mita 		    index < map_size) {
2799b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2800760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2801be1dd78dSEric Sandeen 				memset(fake_storep +
2802760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2803760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2804773642d9SDouglas Gilbert 				       sdebug_sector_size *
2805773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2806be1dd78dSEric Sandeen 			}
2807e9926b43SAkinobu Mita 			if (dif_storep) {
2808e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2809e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2810773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2811e9926b43SAkinobu Mita 			}
2812b90ebc3dSAkinobu Mita 		}
2813b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
281444d92694SMartin K. Petersen 	}
281544d92694SMartin K. Petersen }
281644d92694SMartin K. Petersen 
2817fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28181da177e4SLinus Torvalds {
2819c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2820c2248fc9SDouglas Gilbert 	u64 lba;
2821c2248fc9SDouglas Gilbert 	u32 num;
2822c2248fc9SDouglas Gilbert 	u32 ei_lba;
28231da177e4SLinus Torvalds 	unsigned long iflags;
282419789100SFUJITA Tomonori 	int ret;
2825c2248fc9SDouglas Gilbert 	bool check_prot;
28261da177e4SLinus Torvalds 
2827c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2828c2248fc9SDouglas Gilbert 	case WRITE_16:
2829c2248fc9SDouglas Gilbert 		ei_lba = 0;
2830c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2831c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2832c2248fc9SDouglas Gilbert 		check_prot = true;
2833c2248fc9SDouglas Gilbert 		break;
2834c2248fc9SDouglas Gilbert 	case WRITE_10:
2835c2248fc9SDouglas Gilbert 		ei_lba = 0;
2836c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2837c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2838c2248fc9SDouglas Gilbert 		check_prot = true;
2839c2248fc9SDouglas Gilbert 		break;
2840c2248fc9SDouglas Gilbert 	case WRITE_6:
2841c2248fc9SDouglas Gilbert 		ei_lba = 0;
2842c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2843c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2844c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2845c2248fc9SDouglas Gilbert 		check_prot = true;
2846c2248fc9SDouglas Gilbert 		break;
2847c2248fc9SDouglas Gilbert 	case WRITE_12:
2848c2248fc9SDouglas Gilbert 		ei_lba = 0;
2849c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2850c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2851c2248fc9SDouglas Gilbert 		check_prot = true;
2852c2248fc9SDouglas Gilbert 		break;
2853c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2854c2248fc9SDouglas Gilbert 		ei_lba = 0;
2855c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2856c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2857c2248fc9SDouglas Gilbert 		check_prot = false;
2858c2248fc9SDouglas Gilbert 		break;
2859c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2860c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2861c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2862c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2863c2248fc9SDouglas Gilbert 		check_prot = false;
2864c2248fc9SDouglas Gilbert 		break;
2865c2248fc9SDouglas Gilbert 	}
2866f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
2867773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2868c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2869c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2870c2248fc9SDouglas Gilbert 			return check_condition_result;
2871c2248fc9SDouglas Gilbert 		}
2872773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2873773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2874c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2875c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2876c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2877c2248fc9SDouglas Gilbert 	}
2878c2248fc9SDouglas Gilbert 
2879c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2880f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2881c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2882c2248fc9SDouglas Gilbert 		return check_condition_result;
2883c2248fc9SDouglas Gilbert 	}
2884c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2885f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2886c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2887c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2888c2248fc9SDouglas Gilbert 		return check_condition_result;
2889c2248fc9SDouglas Gilbert 	}
28901da177e4SLinus Torvalds 
28916c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
28926c78cc06SAkinobu Mita 
2893c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2894f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2895c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2896c6a44287SMartin K. Petersen 
2897c6a44287SMartin K. Petersen 		if (prot_ret) {
28986c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2899c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2900c6a44287SMartin K. Petersen 			return illegal_condition_result;
2901c6a44287SMartin K. Petersen 		}
2902c6a44287SMartin K. Petersen 	}
2903c6a44287SMartin K. Petersen 
2904c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
2905f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
290644d92694SMartin K. Petersen 		map_region(lba, num);
29071da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
2908f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
2909773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2910c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
2911c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
2912c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2913cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2914773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
291544d92694SMartin K. Petersen 
2916f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2917c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
2918c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
2919c2248fc9SDouglas Gilbert 
2920c4837394SDouglas Gilbert 		if (sqcp) {
2921c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
2922c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
2923c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
2924c2248fc9SDouglas Gilbert 				return check_condition_result;
2925c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
2926c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
2927c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2928c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2929c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
2930c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2931c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2932c2248fc9SDouglas Gilbert 			}
2933c2248fc9SDouglas Gilbert 		}
2934c4837394SDouglas Gilbert 	}
29351da177e4SLinus Torvalds 	return 0;
29361da177e4SLinus Torvalds }
29371da177e4SLinus Torvalds 
2938fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2939fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
294044d92694SMartin K. Petersen {
294144d92694SMartin K. Petersen 	unsigned long iflags;
294244d92694SMartin K. Petersen 	unsigned long long i;
294344d92694SMartin K. Petersen 	int ret;
2944773642d9SDouglas Gilbert 	u64 lba_off;
294544d92694SMartin K. Petersen 
2946c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
294744d92694SMartin K. Petersen 	if (ret)
294844d92694SMartin K. Petersen 		return ret;
294944d92694SMartin K. Petersen 
295044d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
295144d92694SMartin K. Petersen 
29529ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
295344d92694SMartin K. Petersen 		unmap_region(lba, num);
295444d92694SMartin K. Petersen 		goto out;
295544d92694SMartin K. Petersen 	}
295644d92694SMartin K. Petersen 
2957773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
2958c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2959c2248fc9SDouglas Gilbert 	if (ndob) {
2960773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
2961c2248fc9SDouglas Gilbert 		ret = 0;
2962c2248fc9SDouglas Gilbert 	} else
2963773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2964773642d9SDouglas Gilbert 					  sdebug_sector_size);
296544d92694SMartin K. Petersen 
296644d92694SMartin K. Petersen 	if (-1 == ret) {
296744d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
2968773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2969773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
2970c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2971cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2972cbf67842SDouglas Gilbert 			    my_name, "write same",
2973773642d9SDouglas Gilbert 			    num * sdebug_sector_size, ret);
297444d92694SMartin K. Petersen 
297544d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
297644d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
2977773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2978773642d9SDouglas Gilbert 		       fake_storep + lba_off,
2979773642d9SDouglas Gilbert 		       sdebug_sector_size);
298044d92694SMartin K. Petersen 
29819ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
298244d92694SMartin K. Petersen 		map_region(lba, num);
298344d92694SMartin K. Petersen out:
298444d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
298544d92694SMartin K. Petersen 
298644d92694SMartin K. Petersen 	return 0;
298744d92694SMartin K. Petersen }
298844d92694SMartin K. Petersen 
2989fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
2990fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
2991c2248fc9SDouglas Gilbert {
2992c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2993c2248fc9SDouglas Gilbert 	u32 lba;
2994c2248fc9SDouglas Gilbert 	u16 num;
2995c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2996c2248fc9SDouglas Gilbert 	bool unmap = false;
2997c2248fc9SDouglas Gilbert 
2998c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
2999773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3000c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3001c2248fc9SDouglas Gilbert 			return check_condition_result;
3002c2248fc9SDouglas Gilbert 		} else
3003c2248fc9SDouglas Gilbert 			unmap = true;
3004c2248fc9SDouglas Gilbert 	}
3005c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3006c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3007773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3008c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3009c2248fc9SDouglas Gilbert 		return check_condition_result;
3010c2248fc9SDouglas Gilbert 	}
3011c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3012c2248fc9SDouglas Gilbert }
3013c2248fc9SDouglas Gilbert 
3014fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3015fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3016c2248fc9SDouglas Gilbert {
3017c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3018c2248fc9SDouglas Gilbert 	u64 lba;
3019c2248fc9SDouglas Gilbert 	u32 num;
3020c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3021c2248fc9SDouglas Gilbert 	bool unmap = false;
3022c2248fc9SDouglas Gilbert 	bool ndob = false;
3023c2248fc9SDouglas Gilbert 
3024c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3025773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3026c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3027c2248fc9SDouglas Gilbert 			return check_condition_result;
3028c2248fc9SDouglas Gilbert 		} else
3029c2248fc9SDouglas Gilbert 			unmap = true;
3030c2248fc9SDouglas Gilbert 	}
3031c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3032c2248fc9SDouglas Gilbert 		ndob = true;
3033c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3034c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3035773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3036c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3037c2248fc9SDouglas Gilbert 		return check_condition_result;
3038c2248fc9SDouglas Gilbert 	}
3039c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3040c2248fc9SDouglas Gilbert }
3041c2248fc9SDouglas Gilbert 
3042acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3043acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3044acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3045fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3046fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3047acafd0b9SEwan D. Milne {
3048acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3049acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3050acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3051acafd0b9SEwan D. Milne 	u8 mode;
3052acafd0b9SEwan D. Milne 
3053acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3054acafd0b9SEwan D. Milne 	switch (mode) {
3055acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3056acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3057acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3058acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3059acafd0b9SEwan D. Milne 		break;
3060acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3061acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3062acafd0b9SEwan D. Milne 		break;
3063acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3064acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3065acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3066acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3067acafd0b9SEwan D. Milne 				    dev_list)
3068acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3069acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3070acafd0b9SEwan D. Milne 				if (devip != dp)
3071acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3072acafd0b9SEwan D. Milne 						dp->uas_bm);
3073acafd0b9SEwan D. Milne 			}
3074acafd0b9SEwan D. Milne 		break;
3075acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3076acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3077acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3078acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3079acafd0b9SEwan D. Milne 				    dev_list)
3080acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3081acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3082acafd0b9SEwan D. Milne 					dp->uas_bm);
3083acafd0b9SEwan D. Milne 		break;
3084acafd0b9SEwan D. Milne 	default:
3085acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3086acafd0b9SEwan D. Milne 		break;
3087acafd0b9SEwan D. Milne 	}
3088acafd0b9SEwan D. Milne 	return 0;
3089acafd0b9SEwan D. Milne }
3090acafd0b9SEwan D. Milne 
3091fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3092fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
309338d5c833SDouglas Gilbert {
309438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
309538d5c833SDouglas Gilbert 	u8 *arr;
309638d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
309738d5c833SDouglas Gilbert 	u64 lba;
309838d5c833SDouglas Gilbert 	u32 dnum;
3099773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
310038d5c833SDouglas Gilbert 	u8 num;
310138d5c833SDouglas Gilbert 	unsigned long iflags;
310238d5c833SDouglas Gilbert 	int ret;
3103d467d31fSDouglas Gilbert 	int retval = 0;
310438d5c833SDouglas Gilbert 
3105d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
310638d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
310738d5c833SDouglas Gilbert 	if (0 == num)
310838d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
3109773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
311038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
311138d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
311238d5c833SDouglas Gilbert 		return check_condition_result;
311338d5c833SDouglas Gilbert 	}
3114773642d9SDouglas Gilbert 	if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3115773642d9SDouglas Gilbert 	     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
311638d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
311738d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
311838d5c833SDouglas Gilbert 			    "to DIF device\n");
311938d5c833SDouglas Gilbert 
312038d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
312138d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
312238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
312338d5c833SDouglas Gilbert 		return check_condition_result;
312438d5c833SDouglas Gilbert 	}
312538d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
312638d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
312738d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
312838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
312938d5c833SDouglas Gilbert 		return check_condition_result;
313038d5c833SDouglas Gilbert 	}
3131d467d31fSDouglas Gilbert 	dnum = 2 * num;
3132d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3133d467d31fSDouglas Gilbert 	if (NULL == arr) {
3134d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3135d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3136d467d31fSDouglas Gilbert 		return check_condition_result;
3137d467d31fSDouglas Gilbert 	}
313838d5c833SDouglas Gilbert 
313938d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
314038d5c833SDouglas Gilbert 
314138d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
314238d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
314338d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
314438d5c833SDouglas Gilbert 	fake_storep = arr;
314538d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
314638d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
314738d5c833SDouglas Gilbert 	if (ret == -1) {
3148d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3149d467d31fSDouglas Gilbert 		goto cleanup;
3150773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
315138d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
315238d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
315338d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
315438d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
315538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3156d467d31fSDouglas Gilbert 		retval = check_condition_result;
3157d467d31fSDouglas Gilbert 		goto cleanup;
315838d5c833SDouglas Gilbert 	}
315938d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
316038d5c833SDouglas Gilbert 		map_region(lba, num);
3161d467d31fSDouglas Gilbert cleanup:
316238d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3163d467d31fSDouglas Gilbert 	kfree(arr);
3164d467d31fSDouglas Gilbert 	return retval;
316538d5c833SDouglas Gilbert }
316638d5c833SDouglas Gilbert 
316744d92694SMartin K. Petersen struct unmap_block_desc {
316844d92694SMartin K. Petersen 	__be64	lba;
316944d92694SMartin K. Petersen 	__be32	blocks;
317044d92694SMartin K. Petersen 	__be32	__reserved;
317144d92694SMartin K. Petersen };
317244d92694SMartin K. Petersen 
3173fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
317444d92694SMartin K. Petersen {
317544d92694SMartin K. Petersen 	unsigned char *buf;
317644d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
317744d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
317844d92694SMartin K. Petersen 	int ret;
31796c78cc06SAkinobu Mita 	unsigned long iflags;
318044d92694SMartin K. Petersen 
318144d92694SMartin K. Petersen 
3182c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3183c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3184c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3185c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
318644d92694SMartin K. Petersen 
318744d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3188773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3189c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
319044d92694SMartin K. Petersen 		return check_condition_result;
3191c2248fc9SDouglas Gilbert 	}
319244d92694SMartin K. Petersen 
3193b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3194c2248fc9SDouglas Gilbert 	if (!buf) {
3195c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3196c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3197c2248fc9SDouglas Gilbert 		return check_condition_result;
3198c2248fc9SDouglas Gilbert 	}
3199c2248fc9SDouglas Gilbert 
3200c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
320144d92694SMartin K. Petersen 
320244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
320344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
320444d92694SMartin K. Petersen 
320544d92694SMartin K. Petersen 	desc = (void *)&buf[8];
320644d92694SMartin K. Petersen 
32076c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
32086c78cc06SAkinobu Mita 
320944d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
321044d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
321144d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
321244d92694SMartin K. Petersen 
3213c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
321444d92694SMartin K. Petersen 		if (ret)
321544d92694SMartin K. Petersen 			goto out;
321644d92694SMartin K. Petersen 
321744d92694SMartin K. Petersen 		unmap_region(lba, num);
321844d92694SMartin K. Petersen 	}
321944d92694SMartin K. Petersen 
322044d92694SMartin K. Petersen 	ret = 0;
322144d92694SMartin K. Petersen 
322244d92694SMartin K. Petersen out:
32236c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
322444d92694SMartin K. Petersen 	kfree(buf);
322544d92694SMartin K. Petersen 
322644d92694SMartin K. Petersen 	return ret;
322744d92694SMartin K. Petersen }
322844d92694SMartin K. Petersen 
322944d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
323044d92694SMartin K. Petersen 
3231fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3232fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
323344d92694SMartin K. Petersen {
3234c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3235c2248fc9SDouglas Gilbert 	u64 lba;
3236c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3237c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
323844d92694SMartin K. Petersen 	int ret;
323944d92694SMartin K. Petersen 
3240c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3241c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
324244d92694SMartin K. Petersen 
324344d92694SMartin K. Petersen 	if (alloc_len < 24)
324444d92694SMartin K. Petersen 		return 0;
324544d92694SMartin K. Petersen 
3246c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
324744d92694SMartin K. Petersen 	if (ret)
324844d92694SMartin K. Petersen 		return ret;
324944d92694SMartin K. Petersen 
3250c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
325144d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3252c2248fc9SDouglas Gilbert 	else {
3253c2248fc9SDouglas Gilbert 		mapped = 1;
3254c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3255c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3256c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3257c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3258c2248fc9SDouglas Gilbert 		else
3259c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3260c2248fc9SDouglas Gilbert 	}
326144d92694SMartin K. Petersen 
326244d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3263c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3264c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3265c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3266c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
326744d92694SMartin K. Petersen 
3268c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
326944d92694SMartin K. Petersen }
327044d92694SMartin K. Petersen 
32718d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
32728d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
32738d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
32748d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
32758d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
32768d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
32778d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
32788d039e22SDouglas Gilbert  */
32791da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
32801da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
32811da177e4SLinus Torvalds {
328201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
32838d039e22SDouglas Gilbert 	unsigned int alloc_len;
32848d039e22SDouglas Gilbert 	unsigned char select_report;
32858d039e22SDouglas Gilbert 	u64 lun;
32868d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
32878d039e22SDouglas Gilbert 	u8 *arr;
32888d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
32898d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
32908d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
32918d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
32928d039e22SDouglas Gilbert 	int i, res;
32931da177e4SLinus Torvalds 
329419c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
32958d039e22SDouglas Gilbert 
32968d039e22SDouglas Gilbert 	select_report = cmd[2];
32978d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
32988d039e22SDouglas Gilbert 
32998d039e22SDouglas Gilbert 	if (alloc_len < 4) {
33008d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
33018d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
33021da177e4SLinus Torvalds 		return check_condition_result;
33031da177e4SLinus Torvalds 	}
33048d039e22SDouglas Gilbert 
33058d039e22SDouglas Gilbert 	switch (select_report) {
33068d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3307773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33088d039e22SDouglas Gilbert 		wlun_cnt = 0;
33098d039e22SDouglas Gilbert 		break;
33108d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3311c65b1445SDouglas Gilbert 		lun_cnt = 0;
33128d039e22SDouglas Gilbert 		wlun_cnt = 1;
33138d039e22SDouglas Gilbert 		break;
33148d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
33158d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33168d039e22SDouglas Gilbert 		wlun_cnt = 1;
33178d039e22SDouglas Gilbert 		break;
33188d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
33198d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
33208d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
33218d039e22SDouglas Gilbert 	default:
33228d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
33238d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
33248d039e22SDouglas Gilbert 		return check_condition_result;
33258d039e22SDouglas Gilbert 	}
33268d039e22SDouglas Gilbert 
33278d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3328c65b1445SDouglas Gilbert 		--lun_cnt;
33298d039e22SDouglas Gilbert 
33308d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
33318d039e22SDouglas Gilbert 
33328d039e22SDouglas Gilbert 	rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8;
33338d039e22SDouglas Gilbert 	arr = vmalloc(rlen);
33348d039e22SDouglas Gilbert 	if (!arr) {
33358d039e22SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
33368d039e22SDouglas Gilbert 				INSUFF_RES_ASCQ);
33378d039e22SDouglas Gilbert 		return check_condition_result;
3338c65b1445SDouglas Gilbert 	}
33398d039e22SDouglas Gilbert 	memset(arr, 0, rlen);
33408d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
33418d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
33428d039e22SDouglas Gilbert 
33438d039e22SDouglas Gilbert 	/* luns start at byte 8 in response following the header */
33448d039e22SDouglas Gilbert 	lun_p = (struct scsi_lun *)&arr[8];
33458d039e22SDouglas Gilbert 
33468d039e22SDouglas Gilbert 	/* LUNs use single level peripheral device addressing method */
33478d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
33488d039e22SDouglas Gilbert 	for (i = 0; i < lun_cnt; i++)
33498d039e22SDouglas Gilbert 		int_to_scsilun(lun++, lun_p++);
33508d039e22SDouglas Gilbert 
33518d039e22SDouglas Gilbert 	if (wlun_cnt)
33528d039e22SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
33538d039e22SDouglas Gilbert 
33548d039e22SDouglas Gilbert 	put_unaligned_be32(rlen - 8, &arr[0]);
33558d039e22SDouglas Gilbert 
33568d039e22SDouglas Gilbert 	res = fill_from_dev_buffer(scp, arr, rlen);
33578d039e22SDouglas Gilbert 	vfree(arr);
33588d039e22SDouglas Gilbert 	return res;
33591da177e4SLinus Torvalds }
33601da177e4SLinus Torvalds 
3361c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3362c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3363c639d14eSFUJITA Tomonori {
3364be4e11beSAkinobu Mita 	int j;
3365c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3366c639d14eSFUJITA Tomonori 	unsigned int offset;
3367c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3368be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3369c639d14eSFUJITA Tomonori 
3370c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3371b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3372c5af0db9SAkinobu Mita 	if (!buf) {
337322017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
337422017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3375c5af0db9SAkinobu Mita 		return check_condition_result;
3376c5af0db9SAkinobu Mita 	}
3377c639d14eSFUJITA Tomonori 
337821a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3379c639d14eSFUJITA Tomonori 
3380c639d14eSFUJITA Tomonori 	offset = 0;
3381be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3382be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3383c639d14eSFUJITA Tomonori 
3384be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3385be4e11beSAkinobu Mita 		kaddr = miter.addr;
3386be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3387be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3388c639d14eSFUJITA Tomonori 
3389be4e11beSAkinobu Mita 		offset += miter.length;
3390c639d14eSFUJITA Tomonori 	}
3391be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3392c639d14eSFUJITA Tomonori 	kfree(buf);
3393c639d14eSFUJITA Tomonori 
3394be4e11beSAkinobu Mita 	return 0;
3395c639d14eSFUJITA Tomonori }
3396c639d14eSFUJITA Tomonori 
3397fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3398fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3399c2248fc9SDouglas Gilbert {
3400c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3401c2248fc9SDouglas Gilbert 	u64 lba;
3402c2248fc9SDouglas Gilbert 	u32 num;
3403c2248fc9SDouglas Gilbert 	int errsts;
3404c2248fc9SDouglas Gilbert 
3405c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3406c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3407c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3408c2248fc9SDouglas Gilbert 		return check_condition_result;
3409c2248fc9SDouglas Gilbert 	}
3410c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3411c2248fc9SDouglas Gilbert 	if (errsts)
3412c2248fc9SDouglas Gilbert 		return errsts;
3413c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3414c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3415c2248fc9SDouglas Gilbert 		if (errsts)
3416c2248fc9SDouglas Gilbert 			return errsts;
3417c2248fc9SDouglas Gilbert 	}
3418c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3419c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3420c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3421c2248fc9SDouglas Gilbert }
3422c2248fc9SDouglas Gilbert 
3423c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3424c4837394SDouglas Gilbert {
3425c4837394SDouglas Gilbert 	struct sdebug_queue *sqp = sdebug_q_arr;
3426c4837394SDouglas Gilbert 
3427c4837394SDouglas Gilbert 	if (sdebug_mq_active) {
3428c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
3429c4837394SDouglas Gilbert 		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3430c4837394SDouglas Gilbert 
3431c4837394SDouglas Gilbert 		if (unlikely(hwq >= submit_queues)) {
3432c4837394SDouglas Gilbert 			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3433c4837394SDouglas Gilbert 			hwq %= submit_queues;
3434c4837394SDouglas Gilbert 		}
3435c4837394SDouglas Gilbert 		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3436c4837394SDouglas Gilbert 		return sqp + hwq;
3437c4837394SDouglas Gilbert 	} else
3438c4837394SDouglas Gilbert 		return sqp;
3439c4837394SDouglas Gilbert }
3440c4837394SDouglas Gilbert 
3441c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3442fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
34431da177e4SLinus Torvalds {
3444c4837394SDouglas Gilbert 	int qc_idx;
3445cbf67842SDouglas Gilbert 	int retiring = 0;
34461da177e4SLinus Torvalds 	unsigned long iflags;
3447c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3448cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3449cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3450cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
34511da177e4SLinus Torvalds 
3452c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3453c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3454c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3455cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3456c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3457c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3458c4837394SDouglas Gilbert 	}
3459c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3460c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
34611da177e4SLinus Torvalds 		return;
34621da177e4SLinus Torvalds 	}
3463c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3464c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3465cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3466b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3467c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3468c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3469c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
34701da177e4SLinus Torvalds 		return;
34711da177e4SLinus Torvalds 	}
3472cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3473f46eb0e9SDouglas Gilbert 	if (likely(devip))
3474cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3475cbf67842SDouglas Gilbert 	else
3476c1287970STomas Winkler 		pr_err("devip=NULL\n");
3477f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3478cbf67842SDouglas Gilbert 		retiring = 1;
3479cbf67842SDouglas Gilbert 
3480cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3481c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3482c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3483c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3484cbf67842SDouglas Gilbert 		return;
34851da177e4SLinus Torvalds 	}
34861da177e4SLinus Torvalds 
3487cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3488cbf67842SDouglas Gilbert 		int k, retval;
3489cbf67842SDouglas Gilbert 
3490cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3491c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3492c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3493c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3494cbf67842SDouglas Gilbert 			return;
3495cbf67842SDouglas Gilbert 		}
3496c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3497773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3498cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3499cbf67842SDouglas Gilbert 		else
3500cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3501cbf67842SDouglas Gilbert 	}
3502c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3503cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3504cbf67842SDouglas Gilbert }
3505cbf67842SDouglas Gilbert 
3506cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3507fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3508cbf67842SDouglas Gilbert {
3509a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3510a10bc12aSDouglas Gilbert 						  hrt);
3511a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3512cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3513cbf67842SDouglas Gilbert }
35141da177e4SLinus Torvalds 
3515a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3516fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3517a10bc12aSDouglas Gilbert {
3518a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3519a10bc12aSDouglas Gilbert 						  ew.work);
3520a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3521a10bc12aSDouglas Gilbert }
3522a10bc12aSDouglas Gilbert 
352309ba24c1SDouglas Gilbert static bool got_shared_uuid;
352409ba24c1SDouglas Gilbert static uuid_be shared_uuid;
352509ba24c1SDouglas Gilbert 
3526fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3527fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
35285cb2fc06SFUJITA Tomonori {
35295cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
35305cb2fc06SFUJITA Tomonori 
35315cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
35325cb2fc06SFUJITA Tomonori 	if (devip) {
353309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
353409ba24c1SDouglas Gilbert 			uuid_be_gen(&devip->lu_name);
353509ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
353609ba24c1SDouglas Gilbert 			if (got_shared_uuid)
353709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
353809ba24c1SDouglas Gilbert 			else {
353909ba24c1SDouglas Gilbert 				uuid_be_gen(&shared_uuid);
354009ba24c1SDouglas Gilbert 				got_shared_uuid = true;
354109ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
354209ba24c1SDouglas Gilbert 			}
354309ba24c1SDouglas Gilbert 		}
35445cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
35455cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
35465cb2fc06SFUJITA Tomonori 	}
35475cb2fc06SFUJITA Tomonori 	return devip;
35485cb2fc06SFUJITA Tomonori }
35495cb2fc06SFUJITA Tomonori 
3550f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
35511da177e4SLinus Torvalds {
35521da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
35531da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3554f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
35551da177e4SLinus Torvalds 
3556d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
35571da177e4SLinus Torvalds 	if (!sdbg_host) {
3558c1287970STomas Winkler 		pr_err("Host info NULL\n");
35591da177e4SLinus Torvalds 		return NULL;
35601da177e4SLinus Torvalds         }
35611da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
35621da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
35631da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
35641da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
35651da177e4SLinus Torvalds                         return devip;
35661da177e4SLinus Torvalds 		else {
35671da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
35681da177e4SLinus Torvalds 				open_devip = devip;
35691da177e4SLinus Torvalds 		}
35701da177e4SLinus Torvalds 	}
35715cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
35725cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
35735cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3574c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
35751da177e4SLinus Torvalds 			return NULL;
35761da177e4SLinus Torvalds 		}
35771da177e4SLinus Torvalds 	}
3578a75869d1SFUJITA Tomonori 
35791da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
35801da177e4SLinus Torvalds 	open_devip->target = sdev->id;
35811da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
35821da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3583cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3584cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3585c2248fc9SDouglas Gilbert 	open_devip->used = true;
35861da177e4SLinus Torvalds 	return open_devip;
35871da177e4SLinus Torvalds }
35881da177e4SLinus Torvalds 
35898dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
35901da177e4SLinus Torvalds {
3591773642d9SDouglas Gilbert 	if (sdebug_verbose)
3592c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
35938dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
359475ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
35958dea0d02SFUJITA Tomonori 	return 0;
35968dea0d02SFUJITA Tomonori }
35971da177e4SLinus Torvalds 
35988dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
35998dea0d02SFUJITA Tomonori {
3600f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3601f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3602a34c4e98SFUJITA Tomonori 
3603773642d9SDouglas Gilbert 	if (sdebug_verbose)
3604c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
36058dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3606b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3607b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3608b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3609f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3610b01f6f83SDouglas Gilbert 		if (devip == NULL)
36118dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3612f46eb0e9SDouglas Gilbert 	}
3613c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
36146bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3615773642d9SDouglas Gilbert 	if (sdebug_no_uld)
361678d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
36178dea0d02SFUJITA Tomonori 	return 0;
36188dea0d02SFUJITA Tomonori }
36198dea0d02SFUJITA Tomonori 
36208dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
36218dea0d02SFUJITA Tomonori {
36228dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
36238dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
36248dea0d02SFUJITA Tomonori 
3625773642d9SDouglas Gilbert 	if (sdebug_verbose)
3626c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
36278dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
36288dea0d02SFUJITA Tomonori 	if (devip) {
362925985edcSLucas De Marchi 		/* make this slot available for re-use */
3630c2248fc9SDouglas Gilbert 		devip->used = false;
36318dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
36328dea0d02SFUJITA Tomonori 	}
36338dea0d02SFUJITA Tomonori }
36348dea0d02SFUJITA Tomonori 
3635c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp)
3636c4837394SDouglas Gilbert {
3637c4837394SDouglas Gilbert 	if (!sd_dp)
3638c4837394SDouglas Gilbert 		return;
3639c4837394SDouglas Gilbert 	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3640c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
3641c4837394SDouglas Gilbert 	else if (sdebug_jdelay < 0)
3642c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3643c4837394SDouglas Gilbert }
3644c4837394SDouglas Gilbert 
3645a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3646a10bc12aSDouglas Gilbert    returns false */
3647a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
36488dea0d02SFUJITA Tomonori {
36498dea0d02SFUJITA Tomonori 	unsigned long iflags;
3650c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
3651c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
36528dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3653cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3654a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
36558dea0d02SFUJITA Tomonori 
3656c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3657c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3658773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3659cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3660cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3661cbf67842SDouglas Gilbert 			qmax = r_qmax;
3662cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3663c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3664c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3665a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3666a10bc12aSDouglas Gilbert 					continue;
3667c4837394SDouglas Gilbert 				/* found */
3668db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3669db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3670db525fceSDouglas Gilbert 				if (devip)
3671db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3672db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3673a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3674c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3675c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3676c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3677a10bc12aSDouglas Gilbert 				return true;
36788dea0d02SFUJITA Tomonori 			}
3679cbf67842SDouglas Gilbert 		}
3680c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3681c4837394SDouglas Gilbert 	}
3682a10bc12aSDouglas Gilbert 	return false;
36838dea0d02SFUJITA Tomonori }
36848dea0d02SFUJITA Tomonori 
3685a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
36868dea0d02SFUJITA Tomonori static void stop_all_queued(void)
36878dea0d02SFUJITA Tomonori {
36888dea0d02SFUJITA Tomonori 	unsigned long iflags;
3689c4837394SDouglas Gilbert 	int j, k;
3690c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
36918dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3692cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3693a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
36948dea0d02SFUJITA Tomonori 
3695c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3696c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3697c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3698c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3699c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3700c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3701a10bc12aSDouglas Gilbert 					continue;
3702db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3703db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3704db525fceSDouglas Gilbert 				if (devip)
3705db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3706db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3707a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3708c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3709c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3710c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3711c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
37128dea0d02SFUJITA Tomonori 			}
37138dea0d02SFUJITA Tomonori 		}
3714c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3715c4837394SDouglas Gilbert 	}
3716cbf67842SDouglas Gilbert }
3717cbf67842SDouglas Gilbert 
3718cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3719cbf67842SDouglas Gilbert static void free_all_queued(void)
3720cbf67842SDouglas Gilbert {
3721c4837394SDouglas Gilbert 	int j, k;
3722c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3723cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3724cbf67842SDouglas Gilbert 
3725c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3726c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3727c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
3728a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
3729a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
3730cbf67842SDouglas Gilbert 		}
37311da177e4SLinus Torvalds 	}
3732c4837394SDouglas Gilbert }
37331da177e4SLinus Torvalds 
37341da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
37351da177e4SLinus Torvalds {
3736a10bc12aSDouglas Gilbert 	bool ok;
3737a10bc12aSDouglas Gilbert 
37381da177e4SLinus Torvalds 	++num_aborts;
3739cbf67842SDouglas Gilbert 	if (SCpnt) {
3740a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3741a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3742a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3743a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3744a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3745cbf67842SDouglas Gilbert 	}
37461da177e4SLinus Torvalds 	return SUCCESS;
37471da177e4SLinus Torvalds }
37481da177e4SLinus Torvalds 
37491da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
37501da177e4SLinus Torvalds {
37511da177e4SLinus Torvalds 	++num_dev_resets;
3752cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3753cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3754f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3755f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3756cbf67842SDouglas Gilbert 
3757773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3758cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
37591da177e4SLinus Torvalds 		if (devip)
3760cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
37611da177e4SLinus Torvalds 	}
37621da177e4SLinus Torvalds 	return SUCCESS;
37631da177e4SLinus Torvalds }
37641da177e4SLinus Torvalds 
3765cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3766cbf67842SDouglas Gilbert {
3767cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3768cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3769cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3770cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3771cbf67842SDouglas Gilbert 	int k = 0;
3772cbf67842SDouglas Gilbert 
3773cbf67842SDouglas Gilbert 	++num_target_resets;
3774cbf67842SDouglas Gilbert 	if (!SCpnt)
3775cbf67842SDouglas Gilbert 		goto lie;
3776cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3777cbf67842SDouglas Gilbert 	if (!sdp)
3778cbf67842SDouglas Gilbert 		goto lie;
3779773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3780cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3781cbf67842SDouglas Gilbert 	hp = sdp->host;
3782cbf67842SDouglas Gilbert 	if (!hp)
3783cbf67842SDouglas Gilbert 		goto lie;
3784cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3785cbf67842SDouglas Gilbert 	if (sdbg_host) {
3786cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3787cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3788cbf67842SDouglas Gilbert 				    dev_list)
3789cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3790cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3791cbf67842SDouglas Gilbert 				++k;
3792cbf67842SDouglas Gilbert 			}
3793cbf67842SDouglas Gilbert 	}
3794773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3795cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3796cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3797cbf67842SDouglas Gilbert lie:
3798cbf67842SDouglas Gilbert 	return SUCCESS;
3799cbf67842SDouglas Gilbert }
3800cbf67842SDouglas Gilbert 
38011da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
38021da177e4SLinus Torvalds {
38031da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3804cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38051da177e4SLinus Torvalds         struct scsi_device * sdp;
38061da177e4SLinus Torvalds         struct Scsi_Host * hp;
3807cbf67842SDouglas Gilbert 	int k = 0;
38081da177e4SLinus Torvalds 
38091da177e4SLinus Torvalds 	++num_bus_resets;
3810cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3811cbf67842SDouglas Gilbert 		goto lie;
3812cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3813773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3814cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3815cbf67842SDouglas Gilbert 	hp = sdp->host;
3816cbf67842SDouglas Gilbert 	if (hp) {
3817d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
38181da177e4SLinus Torvalds 		if (sdbg_host) {
3819cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
38201da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3821cbf67842SDouglas Gilbert 					    dev_list) {
3822cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3823cbf67842SDouglas Gilbert 				++k;
38241da177e4SLinus Torvalds 			}
38251da177e4SLinus Torvalds 		}
3826cbf67842SDouglas Gilbert 	}
3827773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3828cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3829cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3830cbf67842SDouglas Gilbert lie:
38311da177e4SLinus Torvalds 	return SUCCESS;
38321da177e4SLinus Torvalds }
38331da177e4SLinus Torvalds 
38341da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
38351da177e4SLinus Torvalds {
38361da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3837cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3838cbf67842SDouglas Gilbert 	int k = 0;
38391da177e4SLinus Torvalds 
38401da177e4SLinus Torvalds 	++num_host_resets;
3841773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3842cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
38431da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
38441da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3845cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3846cbf67842SDouglas Gilbert 				    dev_list) {
3847cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3848cbf67842SDouglas Gilbert 			++k;
3849cbf67842SDouglas Gilbert 		}
38501da177e4SLinus Torvalds         }
38511da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
38521da177e4SLinus Torvalds 	stop_all_queued();
3853773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3854cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3855cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
38561da177e4SLinus Torvalds 	return SUCCESS;
38571da177e4SLinus Torvalds }
38581da177e4SLinus Torvalds 
3859f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
38605f2578e5SFUJITA Tomonori 				      unsigned long store_size)
38611da177e4SLinus Torvalds {
38621da177e4SLinus Torvalds 	struct partition * pp;
38631da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
38641da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
38651da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
38661da177e4SLinus Torvalds 
38671da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3868773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
38691da177e4SLinus Torvalds 		return;
3870773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3871773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3872c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
38731da177e4SLinus Torvalds 	}
3874c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
38751da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3876773642d9SDouglas Gilbert 			   / sdebug_num_parts;
38771da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
38781da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3879773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
38801da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
38811da177e4SLinus Torvalds 			    * heads_by_sects;
3882773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3883773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
38841da177e4SLinus Torvalds 
38851da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
38861da177e4SLinus Torvalds 	ramp[511] = 0xAA;
38871da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
38881da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
38891da177e4SLinus Torvalds 		start_sec = starts[k];
38901da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
38911da177e4SLinus Torvalds 		pp->boot_ind = 0;
38921da177e4SLinus Torvalds 
38931da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
38941da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
38951da177e4SLinus Torvalds 			   / sdebug_sectors_per;
38961da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
38971da177e4SLinus Torvalds 
38981da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
38991da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
39001da177e4SLinus Torvalds 			       / sdebug_sectors_per;
39011da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
39021da177e4SLinus Torvalds 
3903150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3904150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
39051da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
39061da177e4SLinus Torvalds 	}
39071da177e4SLinus Torvalds }
39081da177e4SLinus Torvalds 
3909c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
3910c4837394SDouglas Gilbert {
3911c4837394SDouglas Gilbert 	int j;
3912c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3913c4837394SDouglas Gilbert 
3914c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
3915c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
3916c4837394SDouglas Gilbert }
3917c4837394SDouglas Gilbert 
3918c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
3919c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
3920c4837394SDouglas Gilbert  */
3921c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
3922c4837394SDouglas Gilbert {
3923c4837394SDouglas Gilbert 	int count, modulo;
3924c4837394SDouglas Gilbert 
3925c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
3926c4837394SDouglas Gilbert 	if (modulo < 2)
3927c4837394SDouglas Gilbert 		return;
3928c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
3929c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
3930c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
3931c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
3932c4837394SDouglas Gilbert }
3933c4837394SDouglas Gilbert 
3934c4837394SDouglas Gilbert static void clear_queue_stats(void)
3935c4837394SDouglas Gilbert {
3936c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
3937c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
3938c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
3939c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
3940c4837394SDouglas Gilbert }
3941c4837394SDouglas Gilbert 
3942c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
3943c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
3944c4837394SDouglas Gilbert {
3945c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
3946c4837394SDouglas Gilbert 		return;
3947c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
3948c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
3949c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
3950c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
3951c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
3952c4837394SDouglas Gilbert }
3953c4837394SDouglas Gilbert 
3954c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
3955c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
3956c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
3957c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
3958c4837394SDouglas Gilbert  */
3959fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3960cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
39611da177e4SLinus Torvalds {
3962cbf67842SDouglas Gilbert 	unsigned long iflags;
3963cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3964c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3965c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3966299b6c07STomas Winkler 	struct scsi_device *sdp;
3967a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39681da177e4SLinus Torvalds 
3969b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
3970b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
3971f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
3972f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
39731da177e4SLinus Torvalds 	}
3974299b6c07STomas Winkler 	sdp = cmnd->device;
3975299b6c07STomas Winkler 
3976f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
3977cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3978cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3979cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3980cd62b7daSDouglas Gilbert 		goto respond_in_thread;
39811da177e4SLinus Torvalds 
3982cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
3983c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
3984c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3985c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
3986c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3987c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3988c4837394SDouglas Gilbert 	}
3989cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3990cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3991cbf67842SDouglas Gilbert 	inject = 0;
3992f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
3993cd62b7daSDouglas Gilbert 		if (scsi_result) {
3994c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3995cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3996cd62b7daSDouglas Gilbert 		} else
3997cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3998c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
3999773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4000f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4001cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4002cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4003773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4004cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4005cbf67842SDouglas Gilbert 			inject = 1;
4006cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
40071da177e4SLinus Torvalds 		}
4008cbf67842SDouglas Gilbert 	}
4009cbf67842SDouglas Gilbert 
4010c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4011f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4012c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4013cd62b7daSDouglas Gilbert 		if (scsi_result)
4014cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4015773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4016cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4017773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4018cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4019cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4020773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4021cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4022cbf67842SDouglas Gilbert 						    "report: host busy"));
4023cd62b7daSDouglas Gilbert 		if (scsi_result)
4024cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4025cd62b7daSDouglas Gilbert 		else
4026cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
40271da177e4SLinus Torvalds 	}
4028c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4029cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4030c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
40311da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4032c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4033cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4034a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4035c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4036c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4037c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
4038b01f6f83SDouglas Gilbert 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
4039b333a819SDouglas Gilbert 		ktime_t kt;
4040cbf67842SDouglas Gilbert 
4041b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
4042b333a819SDouglas Gilbert 			struct timespec ts;
4043b333a819SDouglas Gilbert 
4044b333a819SDouglas Gilbert 			jiffies_to_timespec(delta_jiff, &ts);
4045b333a819SDouglas Gilbert 			kt = ktime_set(ts.tv_sec, ts.tv_nsec);
4046b333a819SDouglas Gilbert 		} else
4047b333a819SDouglas Gilbert 			kt = ktime_set(0, sdebug_ndelay);
4048a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4049a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4050a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4051cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4052a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4053a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4054c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4055a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4056c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4057c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4058cbf67842SDouglas Gilbert 		}
4059c4837394SDouglas Gilbert 		if (sdebug_statistics)
4060c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4061c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4062c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
4063a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4064a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4065a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4066cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4067a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4068c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4069c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4070a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4071cbf67842SDouglas Gilbert 		}
4072c4837394SDouglas Gilbert 		if (sdebug_statistics)
4073c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4074a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4075cbf67842SDouglas Gilbert 	}
4076f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4077f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4078cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4079cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4080cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4081cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
40821da177e4SLinus Torvalds 	return 0;
4083cd62b7daSDouglas Gilbert 
4084cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4085cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4086cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4087cd62b7daSDouglas Gilbert 	return 0;
40881da177e4SLinus Torvalds }
4089cbf67842SDouglas Gilbert 
409023183910SDouglas Gilbert /* Note: The following macros create attribute files in the
409123183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
409223183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
409323183910SDouglas Gilbert    as it can when the corresponding attribute in the
409423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
409523183910SDouglas Gilbert  */
4096773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4097773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
4098773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4099c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4100773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4101773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4102773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4103773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4104773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4105773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4106773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4107773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4108773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4109773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4110773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4111773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4112773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4113773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4114773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4115773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4116773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4117773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4118773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4119773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4120773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4121773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4122773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4123773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4124773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4125773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4126773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4127c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4128773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4129c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4130773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4131773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4132773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4133773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4134773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
413509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4136773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
413723183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4138773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
41395b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
41401da177e4SLinus Torvalds 
41411da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
41421da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
41431da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4144b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
41451da177e4SLinus Torvalds 
41461da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
41475b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
41480759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4149cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4150c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
41515b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
41525b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4153c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4154beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
415523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
41565b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4157185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
41585b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
41595b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
41605b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4161760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4162760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
41635b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4164c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4165cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4166cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4167c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
416878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
41691da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4170c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
417132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
41726f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
41735b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
41741da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4175d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4176760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4177ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4178c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4179c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4180c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
41815b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
41825b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
41836014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
41846014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
418509ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
418609ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4187c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
41885b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
41895b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
41901da177e4SLinus Torvalds 
4191760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4192760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
41931da177e4SLinus Torvalds 
41941da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
41951da177e4SLinus Torvalds {
4196c4837394SDouglas Gilbert 	int k;
4197c4837394SDouglas Gilbert 
4198760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4199760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4200760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4201c4837394SDouglas Gilbert 		return sdebug_info;
4202760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4203760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4204760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4205760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
42061da177e4SLinus Torvalds 	return sdebug_info;
42071da177e4SLinus Torvalds }
42081da177e4SLinus Torvalds 
4209cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4210fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4211fd32119bSDouglas Gilbert 				 int length)
42121da177e4SLinus Torvalds {
42131da177e4SLinus Torvalds 	char arr[16];
4214c8ed555aSAl Viro 	int opts;
42151da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
42161da177e4SLinus Torvalds 
42171da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
42181da177e4SLinus Torvalds 		return -EACCES;
42191da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
42201da177e4SLinus Torvalds 	arr[minLen] = '\0';
4221c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
42221da177e4SLinus Torvalds 		return -EINVAL;
4223773642d9SDouglas Gilbert 	sdebug_opts = opts;
4224773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4225773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4226773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4227c4837394SDouglas Gilbert 		tweak_cmnd_count();
42281da177e4SLinus Torvalds 	return length;
42291da177e4SLinus Torvalds }
4230c8ed555aSAl Viro 
4231cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4232cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4233cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4234c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4235c8ed555aSAl Viro {
4236c4837394SDouglas Gilbert 	int f, j, l;
4237c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4238cbf67842SDouglas Gilbert 
4239c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4240c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4241c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4242c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4243c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4244c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4245c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4246c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4247c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4248c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4249c4837394SDouglas Gilbert 		   num_aborts);
4250c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4251c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4252c4837394SDouglas Gilbert 		   num_host_resets);
4253c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4254c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4255c4837394SDouglas Gilbert 	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4256c4837394SDouglas Gilbert 		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
4257c4837394SDouglas Gilbert 		   sdebug_mq_active);
4258c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4259c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4260c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4261c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4262c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4263cbf67842SDouglas Gilbert 
4264c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4265c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4266c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4267c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4268773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4269c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4270c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4271c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4272c4837394SDouglas Gilbert 		}
4273cbf67842SDouglas Gilbert 	}
4274c8ed555aSAl Viro 	return 0;
42751da177e4SLinus Torvalds }
42761da177e4SLinus Torvalds 
427782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
42781da177e4SLinus Torvalds {
4279c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
42801da177e4SLinus Torvalds }
4281c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4282c4837394SDouglas Gilbert  * of delay is jiffies.
4283c4837394SDouglas Gilbert  */
428482069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
428582069379SAkinobu Mita 			   size_t count)
42861da177e4SLinus Torvalds {
4287c2206098SDouglas Gilbert 	int jdelay, res;
42881da177e4SLinus Torvalds 
4289b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4290cbf67842SDouglas Gilbert 		res = count;
4291c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4292c4837394SDouglas Gilbert 			int j, k;
4293c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4294cbf67842SDouglas Gilbert 
4295c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4296c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4297c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4298c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4299c4837394SDouglas Gilbert 						   sdebug_max_queue);
4300c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4301c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4302c4837394SDouglas Gilbert 					break;
4303c4837394SDouglas Gilbert 				}
4304c4837394SDouglas Gilbert 			}
4305c4837394SDouglas Gilbert 			if (res > 0) {
4306a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4307a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4308a10bc12aSDouglas Gilbert 				free_all_queued();
4309c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4310773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
43111da177e4SLinus Torvalds 			}
4312c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4313cbf67842SDouglas Gilbert 		}
4314cbf67842SDouglas Gilbert 		return res;
43151da177e4SLinus Torvalds 	}
43161da177e4SLinus Torvalds 	return -EINVAL;
43171da177e4SLinus Torvalds }
431882069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
43191da177e4SLinus Torvalds 
4320cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4321cbf67842SDouglas Gilbert {
4322773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4323cbf67842SDouglas Gilbert }
4324cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4325c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4326cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4327cbf67842SDouglas Gilbert 			    size_t count)
4328cbf67842SDouglas Gilbert {
4329c4837394SDouglas Gilbert 	int ndelay, res;
4330cbf67842SDouglas Gilbert 
4331cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4332c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4333cbf67842SDouglas Gilbert 		res = count;
4334773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4335c4837394SDouglas Gilbert 			int j, k;
4336c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4337c4837394SDouglas Gilbert 
4338c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4339c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4340c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4341c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4342c4837394SDouglas Gilbert 						   sdebug_max_queue);
4343c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4344c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4345c4837394SDouglas Gilbert 					break;
4346c4837394SDouglas Gilbert 				}
4347c4837394SDouglas Gilbert 			}
4348c4837394SDouglas Gilbert 			if (res > 0) {
4349a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4350a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4351a10bc12aSDouglas Gilbert 				free_all_queued();
4352773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4353c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4354c2206098SDouglas Gilbert 							: DEF_JDELAY;
4355cbf67842SDouglas Gilbert 			}
4356c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4357cbf67842SDouglas Gilbert 		}
4358cbf67842SDouglas Gilbert 		return res;
4359cbf67842SDouglas Gilbert 	}
4360cbf67842SDouglas Gilbert 	return -EINVAL;
4361cbf67842SDouglas Gilbert }
4362cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4363cbf67842SDouglas Gilbert 
436482069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
43651da177e4SLinus Torvalds {
4366773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
43671da177e4SLinus Torvalds }
43681da177e4SLinus Torvalds 
436982069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
437082069379SAkinobu Mita 			  size_t count)
43711da177e4SLinus Torvalds {
43721da177e4SLinus Torvalds         int opts;
43731da177e4SLinus Torvalds 	char work[20];
43741da177e4SLinus Torvalds 
43751da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
437648a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
43771da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
43781da177e4SLinus Torvalds 				goto opts_done;
43791da177e4SLinus Torvalds 		} else {
43801da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
43811da177e4SLinus Torvalds 				goto opts_done;
43821da177e4SLinus Torvalds 		}
43831da177e4SLinus Torvalds 	}
43841da177e4SLinus Torvalds 	return -EINVAL;
43851da177e4SLinus Torvalds opts_done:
4386773642d9SDouglas Gilbert 	sdebug_opts = opts;
4387773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4388773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4389c4837394SDouglas Gilbert 	tweak_cmnd_count();
43901da177e4SLinus Torvalds 	return count;
43911da177e4SLinus Torvalds }
439282069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
43931da177e4SLinus Torvalds 
439482069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
43951da177e4SLinus Torvalds {
4396773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
43971da177e4SLinus Torvalds }
439882069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
439982069379SAkinobu Mita 			   size_t count)
44001da177e4SLinus Torvalds {
44011da177e4SLinus Torvalds         int n;
44021da177e4SLinus Torvalds 
44031da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4404773642d9SDouglas Gilbert 		sdebug_ptype = n;
44051da177e4SLinus Torvalds 		return count;
44061da177e4SLinus Torvalds 	}
44071da177e4SLinus Torvalds 	return -EINVAL;
44081da177e4SLinus Torvalds }
440982069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
44101da177e4SLinus Torvalds 
441182069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
44121da177e4SLinus Torvalds {
4413773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
44141da177e4SLinus Torvalds }
441582069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
441682069379SAkinobu Mita 			    size_t count)
44171da177e4SLinus Torvalds {
44181da177e4SLinus Torvalds         int n;
44191da177e4SLinus Torvalds 
44201da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4421773642d9SDouglas Gilbert 		sdebug_dsense = n;
44221da177e4SLinus Torvalds 		return count;
44231da177e4SLinus Torvalds 	}
44241da177e4SLinus Torvalds 	return -EINVAL;
44251da177e4SLinus Torvalds }
442682069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
44271da177e4SLinus Torvalds 
442882069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
442923183910SDouglas Gilbert {
4430773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
443123183910SDouglas Gilbert }
443282069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
443382069379SAkinobu Mita 			     size_t count)
443423183910SDouglas Gilbert {
443523183910SDouglas Gilbert         int n;
443623183910SDouglas Gilbert 
443723183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4438cbf67842SDouglas Gilbert 		n = (n > 0);
4439773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4440773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4441cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4442cbf67842SDouglas Gilbert 				unsigned long sz =
4443773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4444cbf67842SDouglas Gilbert 					1048576;
4445cbf67842SDouglas Gilbert 
4446cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4447cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4448c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4449cbf67842SDouglas Gilbert 					return -ENOMEM;
4450cbf67842SDouglas Gilbert 				}
4451cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4452cbf67842SDouglas Gilbert 			}
4453773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4454cbf67842SDouglas Gilbert 		}
445523183910SDouglas Gilbert 		return count;
445623183910SDouglas Gilbert 	}
445723183910SDouglas Gilbert 	return -EINVAL;
445823183910SDouglas Gilbert }
445982069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
446023183910SDouglas Gilbert 
446182069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4462c65b1445SDouglas Gilbert {
4463773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4464c65b1445SDouglas Gilbert }
446582069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
446682069379SAkinobu Mita 			      size_t count)
4467c65b1445SDouglas Gilbert {
4468c65b1445SDouglas Gilbert         int n;
4469c65b1445SDouglas Gilbert 
4470c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4471773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4472c65b1445SDouglas Gilbert 		return count;
4473c65b1445SDouglas Gilbert 	}
4474c65b1445SDouglas Gilbert 	return -EINVAL;
4475c65b1445SDouglas Gilbert }
447682069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4477c65b1445SDouglas Gilbert 
447882069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
44791da177e4SLinus Torvalds {
4480773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
44811da177e4SLinus Torvalds }
448282069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
448382069379SAkinobu Mita 			      size_t count)
44841da177e4SLinus Torvalds {
44851da177e4SLinus Torvalds         int n;
44861da177e4SLinus Torvalds 
44871da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4488773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
44891da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
44901da177e4SLinus Torvalds 		return count;
44911da177e4SLinus Torvalds 	}
44921da177e4SLinus Torvalds 	return -EINVAL;
44931da177e4SLinus Torvalds }
449482069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
44951da177e4SLinus Torvalds 
449682069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
44971da177e4SLinus Torvalds {
4498773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
44991da177e4SLinus Torvalds }
450082069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
45011da177e4SLinus Torvalds 
450282069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
45031da177e4SLinus Torvalds {
4504773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
45051da177e4SLinus Torvalds }
450682069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
45071da177e4SLinus Torvalds 
450882069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
45091da177e4SLinus Torvalds {
4510773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
45111da177e4SLinus Torvalds }
451282069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
451382069379SAkinobu Mita 			       size_t count)
45141da177e4SLinus Torvalds {
45151da177e4SLinus Torvalds         int nth;
45161da177e4SLinus Torvalds 
45171da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4518773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4519c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4520c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4521c4837394SDouglas Gilbert 			sdebug_statistics = true;
4522c4837394SDouglas Gilbert 		}
4523c4837394SDouglas Gilbert 		tweak_cmnd_count();
45241da177e4SLinus Torvalds 		return count;
45251da177e4SLinus Torvalds 	}
45261da177e4SLinus Torvalds 	return -EINVAL;
45271da177e4SLinus Torvalds }
452882069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
45291da177e4SLinus Torvalds 
453082069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
45311da177e4SLinus Torvalds {
4532773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
45331da177e4SLinus Torvalds }
453482069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
453582069379SAkinobu Mita 			      size_t count)
45361da177e4SLinus Torvalds {
45371da177e4SLinus Torvalds         int n;
453819c8ead7SEwan D. Milne 	bool changed;
45391da177e4SLinus Torvalds 
45401da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
45418d039e22SDouglas Gilbert 		if (n > 256) {
45428d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
45438d039e22SDouglas Gilbert 			return -EINVAL;
45448d039e22SDouglas Gilbert 		}
4545773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4546773642d9SDouglas Gilbert 		sdebug_max_luns = n;
45471da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4548773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
454919c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
455019c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
455119c8ead7SEwan D. Milne 
455219c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
455319c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
455419c8ead7SEwan D. Milne 					    host_list) {
455519c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
455619c8ead7SEwan D. Milne 						    dev_list) {
455719c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
455819c8ead7SEwan D. Milne 						dp->uas_bm);
455919c8ead7SEwan D. Milne 				}
456019c8ead7SEwan D. Milne 			}
456119c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
456219c8ead7SEwan D. Milne 		}
45631da177e4SLinus Torvalds 		return count;
45641da177e4SLinus Torvalds 	}
45651da177e4SLinus Torvalds 	return -EINVAL;
45661da177e4SLinus Torvalds }
456782069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
45681da177e4SLinus Torvalds 
456982069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
457078d4e5a0SDouglas Gilbert {
4571773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
457278d4e5a0SDouglas Gilbert }
4573cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4574cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
457582069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
457682069379SAkinobu Mita 			       size_t count)
457778d4e5a0SDouglas Gilbert {
4578c4837394SDouglas Gilbert 	int j, n, k, a;
4579c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
458078d4e5a0SDouglas Gilbert 
458178d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4582c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4583c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4584c4837394SDouglas Gilbert 		k = 0;
4585c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4586c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4587c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4588c4837394SDouglas Gilbert 			if (a > k)
4589c4837394SDouglas Gilbert 				k = a;
4590c4837394SDouglas Gilbert 		}
4591773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4592c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4593cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4594cbf67842SDouglas Gilbert 		else if (k >= n)
4595cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4596cbf67842SDouglas Gilbert 		else
4597cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4598c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
459978d4e5a0SDouglas Gilbert 		return count;
460078d4e5a0SDouglas Gilbert 	}
460178d4e5a0SDouglas Gilbert 	return -EINVAL;
460278d4e5a0SDouglas Gilbert }
460382069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
460478d4e5a0SDouglas Gilbert 
460582069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
460678d4e5a0SDouglas Gilbert {
4607773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
460878d4e5a0SDouglas Gilbert }
460982069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
461078d4e5a0SDouglas Gilbert 
461182069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
46121da177e4SLinus Torvalds {
4613773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
46141da177e4SLinus Torvalds }
461582069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
46161da177e4SLinus Torvalds 
461782069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4618c65b1445SDouglas Gilbert {
4619773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4620c65b1445SDouglas Gilbert }
462182069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
462282069379SAkinobu Mita 				size_t count)
4623c65b1445SDouglas Gilbert {
4624c65b1445SDouglas Gilbert         int n;
46250d01c5dfSDouglas Gilbert 	bool changed;
4626c65b1445SDouglas Gilbert 
4627c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4628773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4629773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
463028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
46310d01c5dfSDouglas Gilbert 		if (changed) {
46320d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
46330d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
463428898873SFUJITA Tomonori 
46354bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
46360d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
46370d01c5dfSDouglas Gilbert 					    host_list) {
46380d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
46390d01c5dfSDouglas Gilbert 						    dev_list) {
46400d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
46410d01c5dfSDouglas Gilbert 						dp->uas_bm);
46420d01c5dfSDouglas Gilbert 				}
46430d01c5dfSDouglas Gilbert 			}
46444bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
46450d01c5dfSDouglas Gilbert 		}
4646c65b1445SDouglas Gilbert 		return count;
4647c65b1445SDouglas Gilbert 	}
4648c65b1445SDouglas Gilbert 	return -EINVAL;
4649c65b1445SDouglas Gilbert }
465082069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4651c65b1445SDouglas Gilbert 
465282069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
46531da177e4SLinus Torvalds {
4654773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
46551da177e4SLinus Torvalds }
46561da177e4SLinus Torvalds 
4657fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4658fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4659fd32119bSDouglas Gilbert 
466082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
466182069379SAkinobu Mita 			      size_t count)
46621da177e4SLinus Torvalds {
46631da177e4SLinus Torvalds 	int delta_hosts;
46641da177e4SLinus Torvalds 
4665f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
46661da177e4SLinus Torvalds 		return -EINVAL;
46671da177e4SLinus Torvalds 	if (delta_hosts > 0) {
46681da177e4SLinus Torvalds 		do {
46691da177e4SLinus Torvalds 			sdebug_add_adapter();
46701da177e4SLinus Torvalds 		} while (--delta_hosts);
46711da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
46721da177e4SLinus Torvalds 		do {
46731da177e4SLinus Torvalds 			sdebug_remove_adapter();
46741da177e4SLinus Torvalds 		} while (++delta_hosts);
46751da177e4SLinus Torvalds 	}
46761da177e4SLinus Torvalds 	return count;
46771da177e4SLinus Torvalds }
467882069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
46791da177e4SLinus Torvalds 
468082069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
468123183910SDouglas Gilbert {
4682773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
468323183910SDouglas Gilbert }
468482069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
468582069379SAkinobu Mita 				    size_t count)
468623183910SDouglas Gilbert {
468723183910SDouglas Gilbert 	int n;
468823183910SDouglas Gilbert 
468923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4690773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
469123183910SDouglas Gilbert 		return count;
469223183910SDouglas Gilbert 	}
469323183910SDouglas Gilbert 	return -EINVAL;
469423183910SDouglas Gilbert }
469582069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
469623183910SDouglas Gilbert 
4697c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4698c4837394SDouglas Gilbert {
4699c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4700c4837394SDouglas Gilbert }
4701c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4702c4837394SDouglas Gilbert 				size_t count)
4703c4837394SDouglas Gilbert {
4704c4837394SDouglas Gilbert 	int n;
4705c4837394SDouglas Gilbert 
4706c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4707c4837394SDouglas Gilbert 		if (n > 0)
4708c4837394SDouglas Gilbert 			sdebug_statistics = true;
4709c4837394SDouglas Gilbert 		else {
4710c4837394SDouglas Gilbert 			clear_queue_stats();
4711c4837394SDouglas Gilbert 			sdebug_statistics = false;
4712c4837394SDouglas Gilbert 		}
4713c4837394SDouglas Gilbert 		return count;
4714c4837394SDouglas Gilbert 	}
4715c4837394SDouglas Gilbert 	return -EINVAL;
4716c4837394SDouglas Gilbert }
4717c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
4718c4837394SDouglas Gilbert 
471982069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4720597136abSMartin K. Petersen {
4721773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4722597136abSMartin K. Petersen }
472382069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4724597136abSMartin K. Petersen 
4725c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4726c4837394SDouglas Gilbert {
4727c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4728c4837394SDouglas Gilbert }
4729c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
4730c4837394SDouglas Gilbert 
473182069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4732c6a44287SMartin K. Petersen {
4733773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4734c6a44287SMartin K. Petersen }
473582069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4736c6a44287SMartin K. Petersen 
473782069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4738c6a44287SMartin K. Petersen {
4739773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4740c6a44287SMartin K. Petersen }
474182069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4742c6a44287SMartin K. Petersen 
474382069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4744c6a44287SMartin K. Petersen {
4745773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4746c6a44287SMartin K. Petersen }
474782069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4748c6a44287SMartin K. Petersen 
474982069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4750c6a44287SMartin K. Petersen {
4751773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4752c6a44287SMartin K. Petersen }
475382069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4754c6a44287SMartin K. Petersen 
475582069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
475644d92694SMartin K. Petersen {
475744d92694SMartin K. Petersen 	ssize_t count;
475844d92694SMartin K. Petersen 
47595b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
476044d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
476144d92694SMartin K. Petersen 				 sdebug_store_sectors);
476244d92694SMartin K. Petersen 
4763c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4764c7badc90STejun Heo 			  (int)map_size, map_storep);
476544d92694SMartin K. Petersen 	buf[count++] = '\n';
4766c7badc90STejun Heo 	buf[count] = '\0';
476744d92694SMartin K. Petersen 
476844d92694SMartin K. Petersen 	return count;
476944d92694SMartin K. Petersen }
477082069379SAkinobu Mita static DRIVER_ATTR_RO(map);
477144d92694SMartin K. Petersen 
477282069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4773d986788bSMartin Pitt {
4774773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4775d986788bSMartin Pitt }
477682069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
477782069379SAkinobu Mita 			       size_t count)
4778d986788bSMartin Pitt {
4779d986788bSMartin Pitt 	int n;
4780d986788bSMartin Pitt 
4781d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4782773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4783d986788bSMartin Pitt 		return count;
4784d986788bSMartin Pitt 	}
4785d986788bSMartin Pitt 	return -EINVAL;
4786d986788bSMartin Pitt }
478782069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4788d986788bSMartin Pitt 
4789cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4790cbf67842SDouglas Gilbert {
4791773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4792cbf67842SDouglas Gilbert }
4793185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4794cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4795cbf67842SDouglas Gilbert 			       size_t count)
4796cbf67842SDouglas Gilbert {
4797185dd232SDouglas Gilbert 	int n;
4798cbf67842SDouglas Gilbert 
4799cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4800185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4801185dd232SDouglas Gilbert 		return count;
4802cbf67842SDouglas Gilbert 	}
4803cbf67842SDouglas Gilbert 	return -EINVAL;
4804cbf67842SDouglas Gilbert }
4805cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4806cbf67842SDouglas Gilbert 
4807c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4808c2248fc9SDouglas Gilbert {
4809773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4810c2248fc9SDouglas Gilbert }
4811c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4812c2248fc9SDouglas Gilbert 			    size_t count)
4813c2248fc9SDouglas Gilbert {
4814c2248fc9SDouglas Gilbert 	int n;
4815c2248fc9SDouglas Gilbert 
4816c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4817773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4818c2248fc9SDouglas Gilbert 		return count;
4819c2248fc9SDouglas Gilbert 	}
4820c2248fc9SDouglas Gilbert 	return -EINVAL;
4821c2248fc9SDouglas Gilbert }
4822c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4823c2248fc9SDouglas Gilbert 
482409ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
482509ba24c1SDouglas Gilbert {
482609ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
482709ba24c1SDouglas Gilbert }
482809ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
482909ba24c1SDouglas Gilbert 
4830cbf67842SDouglas Gilbert 
483182069379SAkinobu Mita /* Note: The following array creates attribute files in the
483223183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
483323183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
483423183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
483523183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
483623183910SDouglas Gilbert  */
48376ecaff7fSRandy Dunlap 
483882069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
483982069379SAkinobu Mita 	&driver_attr_delay.attr,
484082069379SAkinobu Mita 	&driver_attr_opts.attr,
484182069379SAkinobu Mita 	&driver_attr_ptype.attr,
484282069379SAkinobu Mita 	&driver_attr_dsense.attr,
484382069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
484482069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
484582069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
484682069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
484782069379SAkinobu Mita 	&driver_attr_num_parts.attr,
484882069379SAkinobu Mita 	&driver_attr_every_nth.attr,
484982069379SAkinobu Mita 	&driver_attr_max_luns.attr,
485082069379SAkinobu Mita 	&driver_attr_max_queue.attr,
485182069379SAkinobu Mita 	&driver_attr_no_uld.attr,
485282069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
485382069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
485482069379SAkinobu Mita 	&driver_attr_add_host.attr,
485582069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
485682069379SAkinobu Mita 	&driver_attr_sector_size.attr,
4857c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
4858c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
485982069379SAkinobu Mita 	&driver_attr_dix.attr,
486082069379SAkinobu Mita 	&driver_attr_dif.attr,
486182069379SAkinobu Mita 	&driver_attr_guard.attr,
486282069379SAkinobu Mita 	&driver_attr_ato.attr,
486382069379SAkinobu Mita 	&driver_attr_map.attr,
486482069379SAkinobu Mita 	&driver_attr_removable.attr,
4865cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4866cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4867c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
486809ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
486982069379SAkinobu Mita 	NULL,
487082069379SAkinobu Mita };
487182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
48721da177e4SLinus Torvalds 
487311ddcecaSAkinobu Mita static struct device *pseudo_primary;
48748dea0d02SFUJITA Tomonori 
48751da177e4SLinus Torvalds static int __init scsi_debug_init(void)
48761da177e4SLinus Torvalds {
48775f2578e5SFUJITA Tomonori 	unsigned long sz;
48781da177e4SLinus Torvalds 	int host_to_add;
48791da177e4SLinus Torvalds 	int k;
48806ecaff7fSRandy Dunlap 	int ret;
48811da177e4SLinus Torvalds 
4882cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4883cbf67842SDouglas Gilbert 
4884773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
4885c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4886773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
4887773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
4888c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
4889cbf67842SDouglas Gilbert 
4890773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
4891597136abSMartin K. Petersen 	case  512:
4892597136abSMartin K. Petersen 	case 1024:
4893597136abSMartin K. Petersen 	case 2048:
4894597136abSMartin K. Petersen 	case 4096:
4895597136abSMartin K. Petersen 		break;
4896597136abSMartin K. Petersen 	default:
4897773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
4898597136abSMartin K. Petersen 		return -EINVAL;
4899597136abSMartin K. Petersen 	}
4900597136abSMartin K. Petersen 
4901773642d9SDouglas Gilbert 	switch (sdebug_dif) {
4902c6a44287SMartin K. Petersen 
4903c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
4904f46eb0e9SDouglas Gilbert 		break;
4905c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4906395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4907c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4908f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
4909c6a44287SMartin K. Petersen 		break;
4910c6a44287SMartin K. Petersen 
4911c6a44287SMartin K. Petersen 	default:
4912c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4913c6a44287SMartin K. Petersen 		return -EINVAL;
4914c6a44287SMartin K. Petersen 	}
4915c6a44287SMartin K. Petersen 
4916773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
4917c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4918c6a44287SMartin K. Petersen 		return -EINVAL;
4919c6a44287SMartin K. Petersen 	}
4920c6a44287SMartin K. Petersen 
4921773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
4922c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4923c6a44287SMartin K. Petersen 		return -EINVAL;
4924c6a44287SMartin K. Petersen 	}
4925c6a44287SMartin K. Petersen 
4926773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
4927773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
4928ea61fca5SMartin K. Petersen 		return -EINVAL;
4929ea61fca5SMartin K. Petersen 	}
49308d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
49318d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
49328d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
49338d039e22SDouglas Gilbert 	}
4934ea61fca5SMartin K. Petersen 
4935773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
4936773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
4937ea61fca5SMartin K. Petersen 		return -EINVAL;
4938ea61fca5SMartin K. Petersen 	}
4939ea61fca5SMartin K. Petersen 
4940c4837394SDouglas Gilbert 	if (submit_queues < 1) {
4941c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
4942c4837394SDouglas Gilbert 		return -EINVAL;
4943c4837394SDouglas Gilbert 	}
4944c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
4945c4837394SDouglas Gilbert 			       GFP_KERNEL);
4946c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
4947c4837394SDouglas Gilbert 		return -ENOMEM;
4948c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
4949c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
4950c4837394SDouglas Gilbert 
4951773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
4952773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
4953773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4954773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
495528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
49561da177e4SLinus Torvalds 
49571da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
49581da177e4SLinus Torvalds 	sdebug_heads = 8;
49591da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
4960773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
49611da177e4SLinus Torvalds 		sdebug_heads = 64;
4962773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
4963fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
49641da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
49651da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
49661da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
49671da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
49681da177e4SLinus Torvalds 		sdebug_heads = 255;
49691da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
49701da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
49711da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
49721da177e4SLinus Torvalds 	}
49731da177e4SLinus Torvalds 
4974b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
49751da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
49761da177e4SLinus Torvalds 		if (NULL == fake_storep) {
4977c1287970STomas Winkler 			pr_err("out of memory, 1\n");
4978c4837394SDouglas Gilbert 			ret = -ENOMEM;
4979c4837394SDouglas Gilbert 			goto free_q_arr;
49801da177e4SLinus Torvalds 		}
49811da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
4982773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
4983f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
4984cbf67842SDouglas Gilbert 	}
49851da177e4SLinus Torvalds 
4986773642d9SDouglas Gilbert 	if (sdebug_dix) {
4987c6a44287SMartin K. Petersen 		int dif_size;
4988c6a44287SMartin K. Petersen 
4989c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4990c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
4991c6a44287SMartin K. Petersen 
4992c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
4993c6a44287SMartin K. Petersen 
4994c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
4995c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
4996c6a44287SMartin K. Petersen 			ret = -ENOMEM;
4997c6a44287SMartin K. Petersen 			goto free_vm;
4998c6a44287SMartin K. Petersen 		}
4999c6a44287SMartin K. Petersen 
5000c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5001c6a44287SMartin K. Petersen 	}
5002c6a44287SMartin K. Petersen 
50035b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
50045b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5005773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5006773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
50076014759cSMartin K. Petersen 
5008773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5009773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
50106014759cSMartin K. Petersen 
5011773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5012773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
50136014759cSMartin K. Petersen 
5014773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5015773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5016773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5017c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5018c4837394SDouglas Gilbert 			ret = -EINVAL;
5019c4837394SDouglas Gilbert 			goto free_vm;
502044d92694SMartin K. Petersen 		}
502144d92694SMartin K. Petersen 
5022b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5023b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
502444d92694SMartin K. Petersen 
5025c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
502644d92694SMartin K. Petersen 
502744d92694SMartin K. Petersen 		if (map_storep == NULL) {
5028c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
502944d92694SMartin K. Petersen 			ret = -ENOMEM;
503044d92694SMartin K. Petersen 			goto free_vm;
503144d92694SMartin K. Petersen 		}
503244d92694SMartin K. Petersen 
5033b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
503444d92694SMartin K. Petersen 
503544d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5036773642d9SDouglas Gilbert 		if (sdebug_num_parts)
503744d92694SMartin K. Petersen 			map_region(0, 2);
503844d92694SMartin K. Petersen 	}
503944d92694SMartin K. Petersen 
50409b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
50419b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5042c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
50439b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
50446ecaff7fSRandy Dunlap 		goto free_vm;
50456ecaff7fSRandy Dunlap 	}
50466ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
50476ecaff7fSRandy Dunlap 	if (ret < 0) {
5048c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
50496ecaff7fSRandy Dunlap 		goto dev_unreg;
50506ecaff7fSRandy Dunlap 	}
50516ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
50526ecaff7fSRandy Dunlap 	if (ret < 0) {
5053c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
50546ecaff7fSRandy Dunlap 		goto bus_unreg;
50556ecaff7fSRandy Dunlap 	}
50561da177e4SLinus Torvalds 
5057773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5058773642d9SDouglas Gilbert 	sdebug_add_host = 0;
50591da177e4SLinus Torvalds 
50601da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
50611da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
5062c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
50631da177e4SLinus Torvalds                         break;
50641da177e4SLinus Torvalds                 }
50651da177e4SLinus Torvalds         }
50661da177e4SLinus Torvalds 
5067773642d9SDouglas Gilbert 	if (sdebug_verbose)
5068773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5069c1287970STomas Winkler 
50701da177e4SLinus Torvalds 	return 0;
50716ecaff7fSRandy Dunlap 
50726ecaff7fSRandy Dunlap bus_unreg:
50736ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
50746ecaff7fSRandy Dunlap dev_unreg:
50759b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
50766ecaff7fSRandy Dunlap free_vm:
507744d92694SMartin K. Petersen 	vfree(map_storep);
5078c6a44287SMartin K. Petersen 	vfree(dif_storep);
50796ecaff7fSRandy Dunlap 	vfree(fake_storep);
5080c4837394SDouglas Gilbert free_q_arr:
5081c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
50826ecaff7fSRandy Dunlap 	return ret;
50831da177e4SLinus Torvalds }
50841da177e4SLinus Torvalds 
50851da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
50861da177e4SLinus Torvalds {
5087773642d9SDouglas Gilbert 	int k = sdebug_add_host;
50881da177e4SLinus Torvalds 
50891da177e4SLinus Torvalds 	stop_all_queued();
5090cbf67842SDouglas Gilbert 	free_all_queued();
50911da177e4SLinus Torvalds 	for (; k; k--)
50921da177e4SLinus Torvalds 		sdebug_remove_adapter();
50931da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
50941da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
50959b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
50961da177e4SLinus Torvalds 
5097c6a44287SMartin K. Petersen 	vfree(dif_storep);
50981da177e4SLinus Torvalds 	vfree(fake_storep);
5099c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
51001da177e4SLinus Torvalds }
51011da177e4SLinus Torvalds 
51021da177e4SLinus Torvalds device_initcall(scsi_debug_init);
51031da177e4SLinus Torvalds module_exit(scsi_debug_exit);
51041da177e4SLinus Torvalds 
51051da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
51061da177e4SLinus Torvalds {
51071da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51081da177e4SLinus Torvalds 
51091da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
51101da177e4SLinus Torvalds         kfree(sdbg_host);
51111da177e4SLinus Torvalds }
51121da177e4SLinus Torvalds 
51131da177e4SLinus Torvalds static int sdebug_add_adapter(void)
51141da177e4SLinus Torvalds {
51151da177e4SLinus Torvalds 	int k, devs_per_host;
51161da177e4SLinus Torvalds         int error = 0;
51171da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51188b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
51191da177e4SLinus Torvalds 
512024669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
51211da177e4SLinus Torvalds         if (NULL == sdbg_host) {
5122c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
51231da177e4SLinus Torvalds                 return -ENOMEM;
51241da177e4SLinus Torvalds         }
51251da177e4SLinus Torvalds 
51261da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
51271da177e4SLinus Torvalds 
5128773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
51291da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
51305cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
51315cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5132c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51331da177e4SLinus Torvalds                         error = -ENOMEM;
51341da177e4SLinus Torvalds 			goto clean;
51351da177e4SLinus Torvalds                 }
51361da177e4SLinus Torvalds         }
51371da177e4SLinus Torvalds 
51381da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
51391da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
51401da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
51411da177e4SLinus Torvalds 
51421da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
51439b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
51441da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
5145773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
51461da177e4SLinus Torvalds 
51471da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
51481da177e4SLinus Torvalds 
51491da177e4SLinus Torvalds         if (error)
51501da177e4SLinus Torvalds 		goto clean;
51511da177e4SLinus Torvalds 
5152773642d9SDouglas Gilbert 	++sdebug_add_host;
51531da177e4SLinus Torvalds         return error;
51541da177e4SLinus Torvalds 
51551da177e4SLinus Torvalds clean:
51568b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
51578b40228fSFUJITA Tomonori 				 dev_list) {
51581da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
51591da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
51601da177e4SLinus Torvalds 	}
51611da177e4SLinus Torvalds 
51621da177e4SLinus Torvalds 	kfree(sdbg_host);
51631da177e4SLinus Torvalds         return error;
51641da177e4SLinus Torvalds }
51651da177e4SLinus Torvalds 
51661da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
51671da177e4SLinus Torvalds {
51681da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
51691da177e4SLinus Torvalds 
51701da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
51711da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
51721da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
51731da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
51741da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
51751da177e4SLinus Torvalds 	}
51761da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
51771da177e4SLinus Torvalds 
51781da177e4SLinus Torvalds 	if (!sdbg_host)
51791da177e4SLinus Torvalds 		return;
51801da177e4SLinus Torvalds 
51811da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5182773642d9SDouglas Gilbert 	--sdebug_add_host;
51831da177e4SLinus Torvalds }
51841da177e4SLinus Torvalds 
5185fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5186cbf67842SDouglas Gilbert {
5187cbf67842SDouglas Gilbert 	int num_in_q = 0;
5188cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5189cbf67842SDouglas Gilbert 
5190c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5191cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5192cbf67842SDouglas Gilbert 	if (NULL == devip) {
5193c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5194cbf67842SDouglas Gilbert 		return	-ENODEV;
5195cbf67842SDouglas Gilbert 	}
5196cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5197c40ecc12SChristoph Hellwig 
5198cbf67842SDouglas Gilbert 	if (qdepth < 1)
5199cbf67842SDouglas Gilbert 		qdepth = 1;
5200c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5201c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5202c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5203db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5204cbf67842SDouglas Gilbert 
5205773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5206c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5207c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5208cbf67842SDouglas Gilbert 	}
5209c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5210cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5211cbf67842SDouglas Gilbert }
5212cbf67842SDouglas Gilbert 
5213c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5214817fd66bSDouglas Gilbert {
5215c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5216773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5217773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5218773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5219c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5220773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5221817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5222c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5223817fd66bSDouglas Gilbert 	}
5224c4837394SDouglas Gilbert 	return false;
5225817fd66bSDouglas Gilbert }
5226817fd66bSDouglas Gilbert 
5227fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5228fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5229c2248fc9SDouglas Gilbert {
5230c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5231c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5232c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5233c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5234c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5235c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5236c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5237c2248fc9SDouglas Gilbert 	int k, na;
5238c2248fc9SDouglas Gilbert 	int errsts = 0;
5239c2248fc9SDouglas Gilbert 	u32 flags;
5240c2248fc9SDouglas Gilbert 	u16 sa;
5241c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5242c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5243c2248fc9SDouglas Gilbert 
5244c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5245c4837394SDouglas Gilbert 	if (sdebug_statistics)
5246c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5247f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5248f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5249c2248fc9SDouglas Gilbert 		char b[120];
5250c2248fc9SDouglas Gilbert 		int n, len, sb;
5251c2248fc9SDouglas Gilbert 
5252c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5253c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5254c2248fc9SDouglas Gilbert 		if (len > 32)
5255c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5256c2248fc9SDouglas Gilbert 		else {
5257c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5258c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5259c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5260c2248fc9SDouglas Gilbert 		}
5261c4837394SDouglas Gilbert 		if (sdebug_mq_active)
5262c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5263c4837394SDouglas Gilbert 				    my_name, blk_mq_unique_tag(scp->request),
5264c4837394SDouglas Gilbert 				    b);
5265c4837394SDouglas Gilbert 		else
5266c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5267c4837394SDouglas Gilbert 				    b);
5268c2248fc9SDouglas Gilbert 	}
526934d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5270f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5271f46eb0e9SDouglas Gilbert 		goto err_out;
5272c2248fc9SDouglas Gilbert 
5273c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5274c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5275c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5276f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5277f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5278c2248fc9SDouglas Gilbert 		if (NULL == devip)
5279f46eb0e9SDouglas Gilbert 			goto err_out;
5280c2248fc9SDouglas Gilbert 	}
5281c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5282c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5283c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5284c2248fc9SDouglas Gilbert 		r_oip = oip;
5285c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5286c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5287c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5288c2248fc9SDouglas Gilbert 			else
5289c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5290c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5291c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5292c2248fc9SDouglas Gilbert 					break;
5293c2248fc9SDouglas Gilbert 			}
5294c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5295c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5296c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5297c2248fc9SDouglas Gilbert 					break;
5298c2248fc9SDouglas Gilbert 			}
5299c2248fc9SDouglas Gilbert 		}
5300c2248fc9SDouglas Gilbert 		if (k > na) {
5301c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5302c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5303c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5304c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5305c2248fc9SDouglas Gilbert 			else
5306c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5307c2248fc9SDouglas Gilbert 			goto check_cond;
5308c2248fc9SDouglas Gilbert 		}
5309c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5310c2248fc9SDouglas Gilbert 	flags = oip->flags;
5311f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5312c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5313c2248fc9SDouglas Gilbert 		goto check_cond;
5314c2248fc9SDouglas Gilbert 	}
5315f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5316773642d9SDouglas Gilbert 		if (sdebug_verbose)
5317773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5318773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5319c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5320c2248fc9SDouglas Gilbert 		goto check_cond;
5321c2248fc9SDouglas Gilbert 	}
5322f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5323c2248fc9SDouglas Gilbert 		u8 rem;
5324c2248fc9SDouglas Gilbert 		int j;
5325c2248fc9SDouglas Gilbert 
5326c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5327c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5328c2248fc9SDouglas Gilbert 			if (rem) {
5329c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5330c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5331c2248fc9SDouglas Gilbert 						break;
5332c2248fc9SDouglas Gilbert 				}
5333c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5334c2248fc9SDouglas Gilbert 				goto check_cond;
5335c2248fc9SDouglas Gilbert 			}
5336c2248fc9SDouglas Gilbert 		}
5337c2248fc9SDouglas Gilbert 	}
5338f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5339b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5340b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5341f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5342c2248fc9SDouglas Gilbert 		if (errsts)
5343c2248fc9SDouglas Gilbert 			goto check_cond;
5344c2248fc9SDouglas Gilbert 	}
5345c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5346c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5347773642d9SDouglas Gilbert 		if (sdebug_verbose)
5348c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5349c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5350c2248fc9SDouglas Gilbert 				    "required");
5351c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5352c2248fc9SDouglas Gilbert 		goto fini;
5353c2248fc9SDouglas Gilbert 	}
5354773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5355c2248fc9SDouglas Gilbert 		goto fini;
5356f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5357c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5358c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5359c2248fc9SDouglas Gilbert 	}
5360f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5361f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5362c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5363c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5364c2248fc9SDouglas Gilbert 
5365c2248fc9SDouglas Gilbert fini:
5366c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5367c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5368c2248fc9SDouglas Gilbert check_cond:
5369c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5370f46eb0e9SDouglas Gilbert err_out:
5371f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5372c2248fc9SDouglas Gilbert }
5373c2248fc9SDouglas Gilbert 
53749e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5375c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5376c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
53779e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
53789e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
53799e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
53809e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
53819e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
53829e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
53839e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5384185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5385cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
53869e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
53879e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5388cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5389cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
53909e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5391c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
53929e603ca0SFUJITA Tomonori 	.this_id =		7,
539365e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5394cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
53956bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
53969e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
53979e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5398c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
53999e603ca0SFUJITA Tomonori };
54009e603ca0SFUJITA Tomonori 
54011da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
54021da177e4SLinus Torvalds {
54031da177e4SLinus Torvalds 	int error = 0;
54041da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54051da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5406f46eb0e9SDouglas Gilbert 	int hprot;
54071da177e4SLinus Torvalds 
54081da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54091da177e4SLinus Torvalds 
5410773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5411773642d9SDouglas Gilbert 	if (sdebug_clustering)
54120759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
54131da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
54141da177e4SLinus Torvalds 	if (NULL == hpnt) {
5415c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
54161da177e4SLinus Torvalds 		error = -ENODEV;
54171da177e4SLinus Torvalds 		return error;
54181da177e4SLinus Torvalds 	}
5419c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
5420c4837394SDouglas Gilbert 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n",
5421c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5422c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5423c4837394SDouglas Gilbert 	}
5424c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5425c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5426c4837394SDouglas Gilbert 	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5427c4837394SDouglas Gilbert 	if (sdebug_mq_active)
5428c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
54291da177e4SLinus Torvalds 
54301da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
54311da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5432773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5433773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
54341da177e4SLinus Torvalds 	else
5435773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5436773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5437f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
54381da177e4SLinus Torvalds 
5439f46eb0e9SDouglas Gilbert 	hprot = 0;
5440c6a44287SMartin K. Petersen 
5441773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5442c6a44287SMartin K. Petersen 
5443c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
5444f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5445773642d9SDouglas Gilbert 		if (sdebug_dix)
5446f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5447c6a44287SMartin K. Petersen 		break;
5448c6a44287SMartin K. Petersen 
5449c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
5450f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5451773642d9SDouglas Gilbert 		if (sdebug_dix)
5452f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5453c6a44287SMartin K. Petersen 		break;
5454c6a44287SMartin K. Petersen 
5455c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
5456f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5457773642d9SDouglas Gilbert 		if (sdebug_dix)
5458f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5459c6a44287SMartin K. Petersen 		break;
5460c6a44287SMartin K. Petersen 
5461c6a44287SMartin K. Petersen 	default:
5462773642d9SDouglas Gilbert 		if (sdebug_dix)
5463f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5464c6a44287SMartin K. Petersen 		break;
5465c6a44287SMartin K. Petersen 	}
5466c6a44287SMartin K. Petersen 
5467f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5468c6a44287SMartin K. Petersen 
5469f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5470c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5471f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5472f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5473f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5474f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5475f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5476f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5477f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5478c6a44287SMartin K. Petersen 
5479773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5480c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5481c6a44287SMartin K. Petersen 	else
5482c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5483c6a44287SMartin K. Petersen 
5484773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5485773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5486c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5487c4837394SDouglas Gilbert 		sdebug_statistics = true;
54881da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
54891da177e4SLinus Torvalds         if (error) {
5490c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
54911da177e4SLinus Torvalds                 error = -ENODEV;
54921da177e4SLinus Torvalds 		scsi_host_put(hpnt);
54931da177e4SLinus Torvalds         } else
54941da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
54951da177e4SLinus Torvalds 
54961da177e4SLinus Torvalds 	return error;
54971da177e4SLinus Torvalds }
54981da177e4SLinus Torvalds 
54991da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
55001da177e4SLinus Torvalds {
55011da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
55028b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55031da177e4SLinus Torvalds 
55041da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55051da177e4SLinus Torvalds 
55061da177e4SLinus Torvalds 	if (!sdbg_host) {
5507c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
55081da177e4SLinus Torvalds 		return -ENODEV;
55091da177e4SLinus Torvalds 	}
55101da177e4SLinus Torvalds 
55111da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
55121da177e4SLinus Torvalds 
55138b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55148b40228fSFUJITA Tomonori 				 dev_list) {
55151da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
55161da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
55171da177e4SLinus Torvalds         }
55181da177e4SLinus Torvalds 
55191da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
55201da177e4SLinus Torvalds         return 0;
55211da177e4SLinus Torvalds }
55221da177e4SLinus Torvalds 
55238dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
55248dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
55251da177e4SLinus Torvalds {
55268dea0d02SFUJITA Tomonori 	return 1;
55278dea0d02SFUJITA Tomonori }
55281da177e4SLinus Torvalds 
55298dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
55308dea0d02SFUJITA Tomonori 	.name = "pseudo",
55318dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
55328dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
55338dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
553482069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
55358dea0d02SFUJITA Tomonori };
5536