xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 1b37bd60)
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 '.' */
9281b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
9291b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
9301b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
9311b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
9321da177e4SLinus Torvalds 
933cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
934760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
9355a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
93609ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
93709ba24c1SDouglas Gilbert 			  const uuid_be *lu_name)
9381da177e4SLinus Torvalds {
939c65b1445SDouglas Gilbert 	int num, port_a;
940c65b1445SDouglas Gilbert 	char b[32];
9411da177e4SLinus Torvalds 
942c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9431da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9441da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9451da177e4SLinus Torvalds 	arr[1] = 0x1;
9461da177e4SLinus Torvalds 	arr[2] = 0x0;
9471da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
9481da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
9491da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9501da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9511da177e4SLinus Torvalds 	arr[3] = num;
9521da177e4SLinus Torvalds 	num += 4;
953c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
95409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
95509ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
95609ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
95709ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
95809ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
95909ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
96009ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
96109ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
96209ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
96309ba24c1SDouglas Gilbert 			num += 16;
96409ba24c1SDouglas Gilbert 		} else {
9651b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
966c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
967c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
968c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
969c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
9701b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
971773642d9SDouglas Gilbert 			num += 8;
97209ba24c1SDouglas Gilbert 		}
973c65b1445SDouglas Gilbert 		/* Target relative port number */
974c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
975c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
976c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
977c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
978c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
979c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
980c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
981c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
982c65b1445SDouglas Gilbert 	}
9831b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
984c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
985c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
986c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
987c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
9881b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
989773642d9SDouglas Gilbert 	num += 8;
9901b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
9915a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
9925a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
9935a09e398SHannes Reinecke 	arr[num++] = 0x0;
9945a09e398SHannes Reinecke 	arr[num++] = 0x4;
9955a09e398SHannes Reinecke 	arr[num++] = 0;
9965a09e398SHannes Reinecke 	arr[num++] = 0;
997773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
998773642d9SDouglas Gilbert 	num += 2;
9991b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1000c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1001c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1002c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1003c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10041b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1005773642d9SDouglas Gilbert 	num += 8;
1006c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1007c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1008c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1009c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1010c65b1445SDouglas Gilbert 	arr[num++] = 24;
10111b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1012c65b1445SDouglas Gilbert 	num += 12;
1013c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1014c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1015c65b1445SDouglas Gilbert 	num += 8;
1016c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1017c65b1445SDouglas Gilbert 	num += 4;
1018c65b1445SDouglas Gilbert 	return num;
1019c65b1445SDouglas Gilbert }
1020c65b1445SDouglas Gilbert 
1021c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1022c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1023c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1024c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1025c65b1445SDouglas Gilbert };
1026c65b1445SDouglas Gilbert 
1027cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1028760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1029c65b1445SDouglas Gilbert {
1030c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1031c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1032c65b1445SDouglas Gilbert }
1033c65b1445SDouglas Gilbert 
1034cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1035760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1036c65b1445SDouglas Gilbert {
1037c65b1445SDouglas Gilbert 	int num = 0;
1038c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1039c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1040c65b1445SDouglas Gilbert 	int plen, olen;
1041c65b1445SDouglas Gilbert 
1042c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1043c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1044c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1045c65b1445SDouglas Gilbert 	olen = strlen(na1);
1046c65b1445SDouglas Gilbert 	plen = olen + 1;
1047c65b1445SDouglas Gilbert 	if (plen % 4)
1048c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1049c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1050c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1051c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1052c65b1445SDouglas Gilbert 	num += plen;
1053c65b1445SDouglas Gilbert 
1054c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1055c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1056c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1057c65b1445SDouglas Gilbert 	olen = strlen(na2);
1058c65b1445SDouglas Gilbert 	plen = olen + 1;
1059c65b1445SDouglas Gilbert 	if (plen % 4)
1060c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1061c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1062c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1063c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1064c65b1445SDouglas Gilbert 	num += plen;
1065c65b1445SDouglas Gilbert 
1066c65b1445SDouglas Gilbert 	return num;
1067c65b1445SDouglas Gilbert }
1068c65b1445SDouglas Gilbert 
1069c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1070760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1071c65b1445SDouglas Gilbert {
1072c65b1445SDouglas Gilbert 	int num = 0;
1073c65b1445SDouglas Gilbert 	int port_a, port_b;
1074c65b1445SDouglas Gilbert 
1075c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1076c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1077c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1078c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1079c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1080c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1081c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1082c65b1445SDouglas Gilbert 	num += 6;
1083c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1084c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1085c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1086c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1087c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1088c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1089c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
10901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1091773642d9SDouglas Gilbert 	num += 8;
1092c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1093c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1094c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1095c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1096c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1097c65b1445SDouglas Gilbert 	num += 6;
1098c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1099c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1100c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1101c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1102c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1103c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1104c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11051b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1106773642d9SDouglas Gilbert 	num += 8;
1107c65b1445SDouglas Gilbert 
1108c65b1445SDouglas Gilbert 	return num;
1109c65b1445SDouglas Gilbert }
1110c65b1445SDouglas Gilbert 
1111c65b1445SDouglas Gilbert 
1112c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1113c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1114c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1115c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1116c65b1445SDouglas Gilbert '1','2','3','4',
1117c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1118c65b1445SDouglas Gilbert 0xec,0,0,0,
1119c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1120c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1121c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1122c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1123c65b1445SDouglas Gilbert 0x53,0x41,
1124c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1125c65b1445SDouglas Gilbert 0x20,0x20,
1126c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1127c65b1445SDouglas Gilbert 0x10,0x80,
1128c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1129c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1130c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1131c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1132c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1133c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1134c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1138c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1139c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1140c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1141c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1153c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1154c65b1445SDouglas Gilbert };
1155c65b1445SDouglas Gilbert 
1156cbf67842SDouglas Gilbert /* ATA Information VPD page */
1157760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1158c65b1445SDouglas Gilbert {
1159c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1160c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1161c65b1445SDouglas Gilbert }
1162c65b1445SDouglas Gilbert 
1163c65b1445SDouglas Gilbert 
1164c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11651e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
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,
11681e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1169c65b1445SDouglas Gilbert };
1170c65b1445SDouglas Gilbert 
1171cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1172760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1173c65b1445SDouglas Gilbert {
1174ea61fca5SMartin K. Petersen 	unsigned int gran;
1175ea61fca5SMartin K. Petersen 
1176c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1177e308b3d1SMartin K. Petersen 
1178e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1179773642d9SDouglas Gilbert 	gran = 1 << sdebug_physblk_exp;
1180773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1181e308b3d1SMartin K. Petersen 
1182e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1183773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1184773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
118544d92694SMartin K. Petersen 
1186e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1187773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1188e308b3d1SMartin K. Petersen 
1189773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1190e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1191773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1192e308b3d1SMartin K. Petersen 
1193e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1194773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
119544d92694SMartin K. Petersen 	}
119644d92694SMartin K. Petersen 
1197e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1198773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1199773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
120044d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
120144d92694SMartin K. Petersen 	}
120244d92694SMartin K. Petersen 
1203e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1204773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
12056014759cSMartin K. Petersen 
12065b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1207773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
12085b94e232SMartin K. Petersen 
12095b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
121044d92694SMartin K. Petersen 
1211c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
12141e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1215760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1216eac6e8e4SMatthew Wilcox {
1217eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1218eac6e8e4SMatthew Wilcox 	arr[0] = 0;
12191e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
12201e49f785SDouglas Gilbert 	arr[2] = 0;
12211e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1222eac6e8e4SMatthew Wilcox 
1223eac6e8e4SMatthew Wilcox 	return 0x3c;
1224eac6e8e4SMatthew Wilcox }
12251da177e4SLinus Torvalds 
1226760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1227760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
12286014759cSMartin K. Petersen {
12293f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12306014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1231773642d9SDouglas Gilbert 	if (sdebug_lbpu)
12326014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1233773642d9SDouglas Gilbert 	if (sdebug_lbpws)
12346014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1235773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
12365b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1237760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1238760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1239760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1240760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1241760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
12423f0bc3b3SMartin K. Petersen 	return 0x4;
12436014759cSMartin K. Petersen }
12446014759cSMartin K. Petersen 
12451da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1246c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12471da177e4SLinus Torvalds 
1248c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12491da177e4SLinus Torvalds {
12501da177e4SLinus Torvalds 	unsigned char pq_pdt;
12515a09e398SHannes Reinecke 	unsigned char * arr;
125201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12535a09e398SHannes Reinecke 	int alloc_len, n, ret;
1254760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
12551da177e4SLinus Torvalds 
1256773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
12576f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12586f3cbf55SDouglas Gilbert 	if (! arr)
12596f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1260760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1261b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1262c2248fc9SDouglas Gilbert 	if (have_wlun)
1263b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1264b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1265b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1266c65b1445SDouglas Gilbert 	else
1267773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
12681da177e4SLinus Torvalds 	arr[0] = pq_pdt;
12691da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
127022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
12715a09e398SHannes Reinecke 		kfree(arr);
12721da177e4SLinus Torvalds 		return check_condition_result;
12731da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
12745a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1275c65b1445SDouglas Gilbert 		char lu_id_str[6];
1276c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
12771da177e4SLinus Torvalds 
12785a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
12795a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1280b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
128123183910SDouglas Gilbert 			host_no = 0;
1282c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1283c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1284c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1285c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1286c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
12871da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1288c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1289c65b1445SDouglas Gilbert 			n = 4;
1290c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1291c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1292c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1293c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1294c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1295c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1296c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1297c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1298760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1299c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1300760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1301760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1302760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1303760f3b03SDouglas Gilbert 			}
1304c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
13051da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1306c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13071da177e4SLinus Torvalds 			arr[3] = len;
1308c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
13091da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1310c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1311760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
13125a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
131309ba24c1SDouglas Gilbert 						lu_id_str, len,
131409ba24c1SDouglas Gilbert 						&devip->lu_name);
1315c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1316c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1317760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1318c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1319c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1320760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1321c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1322c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1323c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1324773642d9SDouglas Gilbert 			if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
1325c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1326760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1327c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1328c6a44287SMartin K. Petersen 			else
1329c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1330c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1331c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1332c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1333c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1334c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1335c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1336c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1337c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1338c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1339c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1340760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1341760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1342c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1343760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1344773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1345760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1346c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1347760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1348760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1349eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1350760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1351760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
13526014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1353760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
13541da177e4SLinus Torvalds 		} else {
135522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13565a09e398SHannes Reinecke 			kfree(arr);
13571da177e4SLinus Torvalds 			return check_condition_result;
13581da177e4SLinus Torvalds 		}
1359773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
13605a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1361c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13625a09e398SHannes Reinecke 		kfree(arr);
13635a09e398SHannes Reinecke 		return ret;
13641da177e4SLinus Torvalds 	}
13651da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1366773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1367773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
13681da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
13691da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1370f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1371b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
13725a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1373c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
13741da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1375c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
13761da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
13771da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
13781da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
13791da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1380760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1381760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1382c65b1445SDouglas Gilbert 	n = 62;
1383760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1384760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1385760f3b03SDouglas Gilbert 		n += 2;
1386760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1387760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1388760f3b03SDouglas Gilbert 		n += 2;
13891da177e4SLinus Torvalds 	}
1390760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
13915a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
13921da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
13935a09e398SHannes Reinecke 	kfree(arr);
13945a09e398SHannes Reinecke 	return ret;
13951da177e4SLinus Torvalds }
13961da177e4SLinus Torvalds 
1397fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1398fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1399fd32119bSDouglas Gilbert 
14001da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
14011da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
14021da177e4SLinus Torvalds {
14031da177e4SLinus Torvalds 	unsigned char * sbuff;
140401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1405cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
14062492fc09STomas Winkler 	bool dsense;
14071da177e4SLinus Torvalds 	int len = 18;
14081da177e4SLinus Torvalds 
1409c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1410c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1411cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1412c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1413c2248fc9SDouglas Gilbert 		if (dsense) {
1414c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1415c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1416c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1417c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1418c2248fc9SDouglas Gilbert 			len = 8;
1419c65b1445SDouglas Gilbert 		} else {
1420c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1421c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1422c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1423c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1424c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1425c65b1445SDouglas Gilbert 		}
1426c65b1445SDouglas Gilbert 	} else {
1427cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1428773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1429c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1430c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1431c2248fc9SDouglas Gilbert 			if (dsense) {
1432c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1433c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1434c2248fc9SDouglas Gilbert 				len = 8;
1435c2248fc9SDouglas Gilbert 			} else {
1436c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1437c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1438c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1439c2248fc9SDouglas Gilbert 			}
1440c2248fc9SDouglas Gilbert 		} else if (dsense) {
1441c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14421da177e4SLinus Torvalds 			arr[0] = 0x72;
14431da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14441da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14451da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14461da177e4SLinus Torvalds 			len = 8;
1447c2248fc9SDouglas Gilbert 		} else {
1448c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1449c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1450c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1451c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1452c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1453c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1454c65b1445SDouglas Gilbert 		}
1455c2248fc9SDouglas Gilbert 
1456c65b1445SDouglas Gilbert 	}
1457cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14581da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds 
1461c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1462c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1463c65b1445SDouglas Gilbert {
146401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1465c4837394SDouglas Gilbert 	int power_cond, stop;
1466c65b1445SDouglas Gilbert 
1467c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1468c65b1445SDouglas Gilbert 	if (power_cond) {
146922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1470c65b1445SDouglas Gilbert 		return check_condition_result;
1471c65b1445SDouglas Gilbert 	}
1472c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1473c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
1474c65b1445SDouglas Gilbert 	return 0;
1475c65b1445SDouglas Gilbert }
1476c65b1445SDouglas Gilbert 
147728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
147828898873SFUJITA Tomonori {
1479773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1480773642d9SDouglas Gilbert 
1481773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1482773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1483773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
148428898873SFUJITA Tomonori 	else
148528898873SFUJITA Tomonori 		return sdebug_store_sectors;
148628898873SFUJITA Tomonori }
148728898873SFUJITA Tomonori 
14881da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
14891da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
14901da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
14911da177e4SLinus Torvalds {
14921da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1493c65b1445SDouglas Gilbert 	unsigned int capac;
14941da177e4SLinus Torvalds 
1495c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
149628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
14971da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1498c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1499c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1500773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1501773642d9SDouglas Gilbert 	} else
1502773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1503773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
15041da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
15051da177e4SLinus Torvalds }
15061da177e4SLinus Torvalds 
1507c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1508c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1509c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1510c65b1445SDouglas Gilbert {
151101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1512c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1513773642d9SDouglas Gilbert 	int alloc_len;
1514c65b1445SDouglas Gilbert 
1515773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1516c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
151728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1518c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1519773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1520773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1521773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1522773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
152344d92694SMartin K. Petersen 
1524be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15255b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1526760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1527760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1528760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1529760f3b03SDouglas Gilbert 		 */
1530760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1531760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1532be1dd78dSEric Sandeen 	}
153344d92694SMartin K. Petersen 
1534773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1535c6a44287SMartin K. Petersen 
1536760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1537773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1538c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1539c6a44287SMartin K. Petersen 	}
1540c6a44287SMartin K. Petersen 
1541c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1542c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1543c65b1445SDouglas Gilbert }
1544c65b1445SDouglas Gilbert 
15455a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15465a09e398SHannes Reinecke 
15475a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15485a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15495a09e398SHannes Reinecke {
155001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15515a09e398SHannes Reinecke 	unsigned char * arr;
15525a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15535a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15545a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15555a09e398SHannes Reinecke 
1556773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
15576f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15586f3cbf55SDouglas Gilbert 	if (! arr)
15596f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15605a09e398SHannes Reinecke 	/*
15615a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15625a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15635a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15645a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
15655a09e398SHannes Reinecke 	 */
15665a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
15675a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
15685a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
15695a09e398SHannes Reinecke 			(devip->channel & 0x7f);
15705a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
15715a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
15725a09e398SHannes Reinecke 
15735a09e398SHannes Reinecke 	/*
15745a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
15755a09e398SHannes Reinecke 	 */
15765a09e398SHannes Reinecke 	n = 4;
1577b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
15785a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
15795a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
15805a09e398SHannes Reinecke 	} else {
15815a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1582773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
15835a09e398SHannes Reinecke 	}
1584773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1585773642d9SDouglas Gilbert 	n += 2;
15865a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15875a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15885a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15895a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15905a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15915a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1592773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1593773642d9SDouglas Gilbert 	n += 2;
15945a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
15955a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1596773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1597773642d9SDouglas Gilbert 	n += 2;
15985a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15995a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16005a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16015a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16025a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16035a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1604773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1605773642d9SDouglas Gilbert 	n += 2;
16065a09e398SHannes Reinecke 
16075a09e398SHannes Reinecke 	rlen = n - 4;
1608773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
16095a09e398SHannes Reinecke 
16105a09e398SHannes Reinecke 	/*
16115a09e398SHannes Reinecke 	 * Return the smallest value of either
16125a09e398SHannes Reinecke 	 * - The allocated length
16135a09e398SHannes Reinecke 	 * - The constructed command length
16145a09e398SHannes Reinecke 	 * - The maximum array size
16155a09e398SHannes Reinecke 	 */
16165a09e398SHannes Reinecke 	rlen = min(alen,n);
16175a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16185a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16195a09e398SHannes Reinecke 	kfree(arr);
16205a09e398SHannes Reinecke 	return ret;
16215a09e398SHannes Reinecke }
16225a09e398SHannes Reinecke 
1623fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1624fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
162538d5c833SDouglas Gilbert {
162638d5c833SDouglas Gilbert 	bool rctd;
162738d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
162838d5c833SDouglas Gilbert 	u16 req_sa, u;
162938d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
163038d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
163138d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
163238d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
163338d5c833SDouglas Gilbert 	u8 *arr;
163438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
163538d5c833SDouglas Gilbert 
163638d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
163738d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
163838d5c833SDouglas Gilbert 	req_opcode = cmd[3];
163938d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
164038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16416d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
164238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
164338d5c833SDouglas Gilbert 		return check_condition_result;
164438d5c833SDouglas Gilbert 	}
164538d5c833SDouglas Gilbert 	if (alloc_len > 8192)
164638d5c833SDouglas Gilbert 		a_len = 8192;
164738d5c833SDouglas Gilbert 	else
164838d5c833SDouglas Gilbert 		a_len = alloc_len;
164999531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
165038d5c833SDouglas Gilbert 	if (NULL == arr) {
165138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
165238d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
165338d5c833SDouglas Gilbert 		return check_condition_result;
165438d5c833SDouglas Gilbert 	}
165538d5c833SDouglas Gilbert 	switch (reporting_opts) {
165638d5c833SDouglas Gilbert 	case 0:	/* all commands */
165738d5c833SDouglas Gilbert 		/* count number of commands */
165838d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
165938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
166038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
166138d5c833SDouglas Gilbert 				continue;
166238d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
166338d5c833SDouglas Gilbert 		}
166438d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
166538d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
166638d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
166738d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
166838d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
166938d5c833SDouglas Gilbert 				continue;
167038d5c833SDouglas Gilbert 			na = oip->num_attached;
167138d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
167238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
167338d5c833SDouglas Gilbert 			if (rctd)
167438d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
167538d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
167638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
167738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
167838d5c833SDouglas Gilbert 			if (rctd)
167938d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
168038d5c833SDouglas Gilbert 			r_oip = oip;
168138d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
168238d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
168338d5c833SDouglas Gilbert 					continue;
168438d5c833SDouglas Gilbert 				offset += bump;
168538d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
168638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
168738d5c833SDouglas Gilbert 				if (rctd)
168838d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
168938d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
169038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
169138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
169238d5c833SDouglas Gilbert 						   arr + offset + 6);
169338d5c833SDouglas Gilbert 				if (rctd)
169438d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
169538d5c833SDouglas Gilbert 							   arr + offset + 8);
169638d5c833SDouglas Gilbert 			}
169738d5c833SDouglas Gilbert 			oip = r_oip;
169838d5c833SDouglas Gilbert 			offset += bump;
169938d5c833SDouglas Gilbert 		}
170038d5c833SDouglas Gilbert 		break;
170138d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
170238d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
170338d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
170438d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
170538d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
170638d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
170738d5c833SDouglas Gilbert 			supp = 1;
170838d5c833SDouglas Gilbert 			offset = 4;
170938d5c833SDouglas Gilbert 		} else {
171038d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
171138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
171238d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
171338d5c833SDouglas Gilbert 							     2, 2);
171438d5c833SDouglas Gilbert 					kfree(arr);
171538d5c833SDouglas Gilbert 					return check_condition_result;
171638d5c833SDouglas Gilbert 				}
171738d5c833SDouglas Gilbert 				req_sa = 0;
171838d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
171938d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
172038d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
172138d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
172238d5c833SDouglas Gilbert 				return check_condition_result;
172338d5c833SDouglas Gilbert 			}
172438d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
172538d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
172638d5c833SDouglas Gilbert 				supp = 3;
172738d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
172838d5c833SDouglas Gilbert 				na = oip->num_attached;
172938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
173038d5c833SDouglas Gilbert 				     ++k, ++oip) {
173138d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
173238d5c833SDouglas Gilbert 						break;
173338d5c833SDouglas Gilbert 				}
173438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
173538d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
173638d5c833SDouglas Gilbert 				na = oip->num_attached;
173738d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
173838d5c833SDouglas Gilbert 				     ++k, ++oip) {
173938d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
174038d5c833SDouglas Gilbert 						break;
174138d5c833SDouglas Gilbert 				}
174238d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
174338d5c833SDouglas Gilbert 			} else
174438d5c833SDouglas Gilbert 				supp = 3;
174538d5c833SDouglas Gilbert 			if (3 == supp) {
174638d5c833SDouglas Gilbert 				u = oip->len_mask[0];
174738d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
174838d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
174938d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
175038d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
175138d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
175238d5c833SDouglas Gilbert 				offset = 4 + u;
175338d5c833SDouglas Gilbert 			} else
175438d5c833SDouglas Gilbert 				offset = 4;
175538d5c833SDouglas Gilbert 		}
175638d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
175738d5c833SDouglas Gilbert 		if (rctd) {
175838d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
175938d5c833SDouglas Gilbert 			offset += 12;
176038d5c833SDouglas Gilbert 		}
176138d5c833SDouglas Gilbert 		break;
176238d5c833SDouglas Gilbert 	default:
176338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
176438d5c833SDouglas Gilbert 		kfree(arr);
176538d5c833SDouglas Gilbert 		return check_condition_result;
176638d5c833SDouglas Gilbert 	}
176738d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
176838d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
176938d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
177038d5c833SDouglas Gilbert 	kfree(arr);
177138d5c833SDouglas Gilbert 	return errsts;
177238d5c833SDouglas Gilbert }
177338d5c833SDouglas Gilbert 
1774fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1775fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
177638d5c833SDouglas Gilbert {
177738d5c833SDouglas Gilbert 	bool repd;
177838d5c833SDouglas Gilbert 	u32 alloc_len, len;
177938d5c833SDouglas Gilbert 	u8 arr[16];
178038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
178138d5c833SDouglas Gilbert 
178238d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
178338d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
178438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
178538d5c833SDouglas Gilbert 	if (alloc_len < 4) {
178638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
178738d5c833SDouglas Gilbert 		return check_condition_result;
178838d5c833SDouglas Gilbert 	}
178938d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
179038d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
179138d5c833SDouglas Gilbert 	if (repd) {
179238d5c833SDouglas Gilbert 		arr[3] = 0xc;
179338d5c833SDouglas Gilbert 		len = 16;
179438d5c833SDouglas Gilbert 	} else
179538d5c833SDouglas Gilbert 		len = 4;
179638d5c833SDouglas Gilbert 
179738d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
179838d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
179938d5c833SDouglas Gilbert }
180038d5c833SDouglas Gilbert 
18011da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
18021da177e4SLinus Torvalds 
18031da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
18041da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
18051da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
18061da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
18071da177e4SLinus Torvalds 
18081da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
18091da177e4SLinus Torvalds 	if (1 == pcontrol)
18101da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
18111da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
18121da177e4SLinus Torvalds }
18131da177e4SLinus Torvalds 
18141da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
18151da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18161da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18171da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18181da177e4SLinus Torvalds 
18191da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18201da177e4SLinus Torvalds 	if (1 == pcontrol)
18211da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18221da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18231da177e4SLinus Torvalds }
18241da177e4SLinus Torvalds 
18251da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18261da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18271da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18281da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18291da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18301da177e4SLinus Torvalds 
18311da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1832773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1833773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1834773642d9SDouglas Gilbert 	if (sdebug_removable)
18351da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18361da177e4SLinus Torvalds 	if (1 == pcontrol)
18371da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18381da177e4SLinus Torvalds 	return sizeof(format_pg);
18391da177e4SLinus Torvalds }
18401da177e4SLinus Torvalds 
1841fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1842fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1843fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1844fd32119bSDouglas Gilbert 
18451da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18461da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1847cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1848cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1849cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18501da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18511da177e4SLinus Torvalds 
1852773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1853cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18541da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18551da177e4SLinus Torvalds 	if (1 == pcontrol)
1856cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1857cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1858cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18591da177e4SLinus Torvalds 	return sizeof(caching_pg);
18601da177e4SLinus Torvalds }
18611da177e4SLinus Torvalds 
1862fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1863fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1864fd32119bSDouglas Gilbert 
18651da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
18661da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1867c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1868c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1869c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
18701da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
18711da177e4SLinus Torvalds 
1872773642d9SDouglas Gilbert 	if (sdebug_dsense)
18731da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1874c65b1445SDouglas Gilbert 	else
1875c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1876c6a44287SMartin K. Petersen 
1877773642d9SDouglas Gilbert 	if (sdebug_ato)
1878c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1879c6a44287SMartin K. Petersen 
18801da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
18811da177e4SLinus Torvalds 	if (1 == pcontrol)
1882c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1883c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1884c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
18851da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
18861da177e4SLinus Torvalds }
18871da177e4SLinus Torvalds 
1888c65b1445SDouglas Gilbert 
18891da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
18901da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1891c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
18921da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1893c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1894c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1895c65b1445SDouglas Gilbert 
18961da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
18971da177e4SLinus Torvalds 	if (1 == pcontrol)
1898c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1899c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1900c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
19011da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
19021da177e4SLinus Torvalds }
19031da177e4SLinus Torvalds 
1904c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1905c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1906c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1907c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1908c65b1445SDouglas Gilbert 
1909c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1910c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1911c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1912c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1913c65b1445SDouglas Gilbert }
1914c65b1445SDouglas Gilbert 
1915c65b1445SDouglas Gilbert 
1916c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1917c65b1445SDouglas Gilbert 			      int target_dev_id)
1918c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1919c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1920c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1921773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1922773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1923c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1924c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1925c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1926c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1927773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1928773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1929c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1930c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1931c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1932c65b1445SDouglas Gilbert 		};
1933c65b1445SDouglas Gilbert 	int port_a, port_b;
1934c65b1445SDouglas Gilbert 
19351b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
19361b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
19371b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
19381b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
1939c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1940c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1941c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1942773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
1943773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
1944c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1945c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1946c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1947c65b1445SDouglas Gilbert }
1948c65b1445SDouglas Gilbert 
1949c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1950c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1951c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1952c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1953c65b1445SDouglas Gilbert 		};
1954c65b1445SDouglas Gilbert 
1955c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1956c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1957c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1958c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1959c65b1445SDouglas Gilbert }
1960c65b1445SDouglas Gilbert 
19611da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19621da177e4SLinus Torvalds 
1963fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
1964fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
19651da177e4SLinus Torvalds {
196623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
19671da177e4SLinus Torvalds 	unsigned char dev_spec;
1968760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
1969c2248fc9SDouglas Gilbert 	int target = scp->device->id;
19701da177e4SLinus Torvalds 	unsigned char * ap;
19711da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
197201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1973760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
19741da177e4SLinus Torvalds 
1975760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
19761da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
19771da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
19781da177e4SLinus Torvalds 	subpcode = cmd[3];
19791da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
1980760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
1981760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1982760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
198323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
198423183910SDouglas Gilbert 	else
198523183910SDouglas Gilbert 		bd_len = 0;
1986773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
19871da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
19881da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
1989cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
19901da177e4SLinus Torvalds 		return check_condition_result;
19911da177e4SLinus Torvalds 	}
1992c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1993c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
1994b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
1995760f3b03SDouglas Gilbert 	if (is_disk)
1996b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
199723183910SDouglas Gilbert 	else
199823183910SDouglas Gilbert 		dev_spec = 0x0;
19991da177e4SLinus Torvalds 	if (msense_6) {
20001da177e4SLinus Torvalds 		arr[2] = dev_spec;
200123183910SDouglas Gilbert 		arr[3] = bd_len;
20021da177e4SLinus Torvalds 		offset = 4;
20031da177e4SLinus Torvalds 	} else {
20041da177e4SLinus Torvalds 		arr[3] = dev_spec;
200523183910SDouglas Gilbert 		if (16 == bd_len)
200623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
200723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
20081da177e4SLinus Torvalds 		offset = 8;
20091da177e4SLinus Torvalds 	}
20101da177e4SLinus Torvalds 	ap = arr + offset;
201128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
201228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
201328898873SFUJITA Tomonori 
201423183910SDouglas Gilbert 	if (8 == bd_len) {
2015773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2016773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2017773642d9SDouglas Gilbert 		else
2018773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2019773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
202023183910SDouglas Gilbert 		offset += bd_len;
202123183910SDouglas Gilbert 		ap = arr + offset;
202223183910SDouglas Gilbert 	} else if (16 == bd_len) {
2023773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2024773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
202523183910SDouglas Gilbert 		offset += bd_len;
202623183910SDouglas Gilbert 		ap = arr + offset;
202723183910SDouglas Gilbert 	}
20281da177e4SLinus Torvalds 
2029c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2030c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
203122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20321da177e4SLinus Torvalds 		return check_condition_result;
20331da177e4SLinus Torvalds 	}
2034760f3b03SDouglas Gilbert 	bad_pcode = false;
2035760f3b03SDouglas Gilbert 
20361da177e4SLinus Torvalds 	switch (pcode) {
20371da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20381da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20391da177e4SLinus Torvalds 		offset += len;
20401da177e4SLinus Torvalds 		break;
20411da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20421da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20431da177e4SLinus Torvalds 		offset += len;
20441da177e4SLinus Torvalds 		break;
20451da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
2046760f3b03SDouglas Gilbert 		if (is_disk) {
20471da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
20481da177e4SLinus Torvalds 			offset += len;
2049760f3b03SDouglas Gilbert 		} else
2050760f3b03SDouglas Gilbert 			bad_pcode = true;
20511da177e4SLinus Torvalds                 break;
20521da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2053760f3b03SDouglas Gilbert 		if (is_disk) {
20541da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
20551da177e4SLinus Torvalds 			offset += len;
2056760f3b03SDouglas Gilbert 		} else
2057760f3b03SDouglas Gilbert 			bad_pcode = true;
20581da177e4SLinus Torvalds 		break;
20591da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20601da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20611da177e4SLinus Torvalds 		offset += len;
20621da177e4SLinus Torvalds 		break;
2063c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2064c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
206522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2066c65b1445SDouglas Gilbert 			return check_condition_result;
2067c65b1445SDouglas Gilbert 	        }
2068c65b1445SDouglas Gilbert 		len = 0;
2069c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2070c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2071c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2072c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2073c65b1445SDouglas Gilbert 						  target_dev_id);
2074c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2075c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2076c65b1445SDouglas Gilbert 		offset += len;
2077c65b1445SDouglas Gilbert 		break;
20781da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
20791da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
20801da177e4SLinus Torvalds 		offset += len;
20811da177e4SLinus Torvalds 		break;
20821da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2083c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
20841da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
20851da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2086760f3b03SDouglas Gilbert 			if (is_disk) {
2087760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2088760f3b03SDouglas Gilbert 						      target);
2089760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2090760f3b03SDouglas Gilbert 						       target);
2091760f3b03SDouglas Gilbert 			}
20921da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2093c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2094c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2095c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2096c65b1445SDouglas Gilbert 						  target, target_dev_id);
2097c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2098c65b1445SDouglas Gilbert 			}
20991da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2100760f3b03SDouglas Gilbert 			offset += len;
2101c65b1445SDouglas Gilbert 		} else {
210222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2103c65b1445SDouglas Gilbert 			return check_condition_result;
2104c65b1445SDouglas Gilbert                 }
21051da177e4SLinus Torvalds 		break;
21061da177e4SLinus Torvalds 	default:
2107760f3b03SDouglas Gilbert 		bad_pcode = true;
2108760f3b03SDouglas Gilbert 		break;
2109760f3b03SDouglas Gilbert 	}
2110760f3b03SDouglas Gilbert 	if (bad_pcode) {
211122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
21121da177e4SLinus Torvalds 		return check_condition_result;
21131da177e4SLinus Torvalds 	}
21141da177e4SLinus Torvalds 	if (msense_6)
21151da177e4SLinus Torvalds 		arr[0] = offset - 1;
2116773642d9SDouglas Gilbert 	else
2117773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
21181da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
21191da177e4SLinus Torvalds }
21201da177e4SLinus Torvalds 
2121c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2122c65b1445SDouglas Gilbert 
2123fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2124fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2125c65b1445SDouglas Gilbert {
2126c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2127c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2128c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
212901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2130c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2131c65b1445SDouglas Gilbert 
2132c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2133c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2134c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2135773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2136c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
213722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2138c65b1445SDouglas Gilbert 		return check_condition_result;
2139c65b1445SDouglas Gilbert 	}
2140c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2141c65b1445SDouglas Gilbert         if (-1 == res)
2142773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2143773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2144cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2145cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2146cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2147773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2148773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
214923183910SDouglas Gilbert 	if (md_len > 2) {
215022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2151c65b1445SDouglas Gilbert 		return check_condition_result;
2152c65b1445SDouglas Gilbert 	}
2153c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2154c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2155c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2156c65b1445SDouglas Gilbert 	if (ps) {
215722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2158c65b1445SDouglas Gilbert 		return check_condition_result;
2159c65b1445SDouglas Gilbert 	}
2160c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2161773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2162c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2163c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2164cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2165c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2166c65b1445SDouglas Gilbert 		return check_condition_result;
2167c65b1445SDouglas Gilbert 	}
2168c65b1445SDouglas Gilbert 	switch (mpage) {
2169cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2170cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2171cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2172cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2173cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2174cbf67842SDouglas Gilbert 		}
2175cbf67842SDouglas Gilbert 		break;
2176c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2177c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2178c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2179c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2180773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2181cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2182c65b1445SDouglas Gilbert 		}
2183c65b1445SDouglas Gilbert 		break;
2184c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2185c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2186c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2187c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2188cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2189c65b1445SDouglas Gilbert 		}
2190c65b1445SDouglas Gilbert 		break;
2191c65b1445SDouglas Gilbert 	default:
2192c65b1445SDouglas Gilbert 		break;
2193c65b1445SDouglas Gilbert 	}
219422017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2195c65b1445SDouglas Gilbert 	return check_condition_result;
2196cbf67842SDouglas Gilbert set_mode_changed_ua:
2197cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2198cbf67842SDouglas Gilbert 	return 0;
2199c65b1445SDouglas Gilbert }
2200c65b1445SDouglas Gilbert 
2201c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2202c65b1445SDouglas Gilbert {
2203c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2204c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2205c65b1445SDouglas Gilbert 		};
2206c65b1445SDouglas Gilbert 
2207c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2208c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2209c65b1445SDouglas Gilbert }
2210c65b1445SDouglas Gilbert 
2211c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2212c65b1445SDouglas Gilbert {
2213c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2214c65b1445SDouglas Gilbert 		};
2215c65b1445SDouglas Gilbert 
2216c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2217c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2218c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2219c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2220c65b1445SDouglas Gilbert 	}
2221c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2222c65b1445SDouglas Gilbert }
2223c65b1445SDouglas Gilbert 
2224c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2225c65b1445SDouglas Gilbert 
2226c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2227c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2228c65b1445SDouglas Gilbert {
2229c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2230c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
223101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2232c65b1445SDouglas Gilbert 
2233c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2234c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2235c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2236c65b1445SDouglas Gilbert 	if (ppc || sp) {
223722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2238c65b1445SDouglas Gilbert 		return check_condition_result;
2239c65b1445SDouglas Gilbert 	}
2240c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2241c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
224223183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2243773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2244c65b1445SDouglas Gilbert 	arr[0] = pcode;
224523183910SDouglas Gilbert 	if (0 == subpcode) {
2246c65b1445SDouglas Gilbert 		switch (pcode) {
2247c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2248c65b1445SDouglas Gilbert 			n = 4;
2249c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2250c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2251c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2252c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2253c65b1445SDouglas Gilbert 			break;
2254c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2255c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2256c65b1445SDouglas Gilbert 			break;
2257c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2258c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2259c65b1445SDouglas Gilbert 			break;
2260c65b1445SDouglas Gilbert 		default:
226122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2262c65b1445SDouglas Gilbert 			return check_condition_result;
2263c65b1445SDouglas Gilbert 		}
226423183910SDouglas Gilbert 	} else if (0xff == subpcode) {
226523183910SDouglas Gilbert 		arr[0] |= 0x40;
226623183910SDouglas Gilbert 		arr[1] = subpcode;
226723183910SDouglas Gilbert 		switch (pcode) {
226823183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
226923183910SDouglas Gilbert 			n = 4;
227023183910SDouglas Gilbert 			arr[n++] = 0x0;
227123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
227223183910SDouglas Gilbert 			arr[n++] = 0x0;
227323183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
227423183910SDouglas Gilbert 			arr[n++] = 0xd;
227523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
227623183910SDouglas Gilbert 			arr[n++] = 0x2f;
227723183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
227823183910SDouglas Gilbert 			arr[3] = n - 4;
227923183910SDouglas Gilbert 			break;
228023183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
228123183910SDouglas Gilbert 			n = 4;
228223183910SDouglas Gilbert 			arr[n++] = 0xd;
228323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
228423183910SDouglas Gilbert 			arr[3] = n - 4;
228523183910SDouglas Gilbert 			break;
228623183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
228723183910SDouglas Gilbert 			n = 4;
228823183910SDouglas Gilbert 			arr[n++] = 0x2f;
228923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
229023183910SDouglas Gilbert 			arr[3] = n - 4;
229123183910SDouglas Gilbert 			break;
229223183910SDouglas Gilbert 		default:
229322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
229423183910SDouglas Gilbert 			return check_condition_result;
229523183910SDouglas Gilbert 		}
229623183910SDouglas Gilbert 	} else {
229722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
229823183910SDouglas Gilbert 		return check_condition_result;
229923183910SDouglas Gilbert 	}
2300773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2301c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2302c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2303c65b1445SDouglas Gilbert }
2304c65b1445SDouglas Gilbert 
2305cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
230619789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
23071da177e4SLinus Torvalds {
2308c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
230922017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
23101da177e4SLinus Torvalds 		return check_condition_result;
23111da177e4SLinus Torvalds 	}
2312c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2313c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
231422017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2315cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2316c65b1445SDouglas Gilbert 		return check_condition_result;
2317c65b1445SDouglas Gilbert 	}
231819789100SFUJITA Tomonori 	return 0;
231919789100SFUJITA Tomonori }
232019789100SFUJITA Tomonori 
2321a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2322fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2323fd32119bSDouglas Gilbert 			    bool do_write)
232419789100SFUJITA Tomonori {
232519789100SFUJITA Tomonori 	int ret;
2326c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2327a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2328a4517511SAkinobu Mita 	enum dma_data_direction dir;
232919789100SFUJITA Tomonori 
2330c2248fc9SDouglas Gilbert 	if (do_write) {
2331a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2332a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2333a4517511SAkinobu Mita 	} else {
2334a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2335a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2336a4517511SAkinobu Mita 	}
2337a4517511SAkinobu Mita 
2338a4517511SAkinobu Mita 	if (!sdb->length)
2339a4517511SAkinobu Mita 		return 0;
2340a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2341a4517511SAkinobu Mita 		return -1;
234219789100SFUJITA Tomonori 
234319789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
234419789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
234519789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
234619789100SFUJITA Tomonori 
2347386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2348773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2349773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2350773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2351a4517511SAkinobu Mita 		return ret;
2352a4517511SAkinobu Mita 
2353a4517511SAkinobu Mita 	if (rest) {
2354386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2355773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2356773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2357a4517511SAkinobu Mita 	}
235819789100SFUJITA Tomonori 
235919789100SFUJITA Tomonori 	return ret;
236019789100SFUJITA Tomonori }
236119789100SFUJITA Tomonori 
236238d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
236338d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
236438d5c833SDouglas Gilbert  * return false. */
2365fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
236638d5c833SDouglas Gilbert {
236738d5c833SDouglas Gilbert 	bool res;
236838d5c833SDouglas Gilbert 	u64 block, rest = 0;
236938d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2370773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
237138d5c833SDouglas Gilbert 
237238d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
237338d5c833SDouglas Gilbert 	if (block + num > store_blks)
237438d5c833SDouglas Gilbert 		rest = block + num - store_blks;
237538d5c833SDouglas Gilbert 
237638d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
237738d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
237838d5c833SDouglas Gilbert 	if (!res)
237938d5c833SDouglas Gilbert 		return res;
238038d5c833SDouglas Gilbert 	if (rest)
238138d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
238238d5c833SDouglas Gilbert 			     rest * lb_size);
238338d5c833SDouglas Gilbert 	if (!res)
238438d5c833SDouglas Gilbert 		return res;
238538d5c833SDouglas Gilbert 	arr += num * lb_size;
238638d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
238738d5c833SDouglas Gilbert 	if (rest)
238838d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
238938d5c833SDouglas Gilbert 		       rest * lb_size);
239038d5c833SDouglas Gilbert 	return res;
239138d5c833SDouglas Gilbert }
239238d5c833SDouglas Gilbert 
239351d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2394beb40ea4SAkinobu Mita {
239551d648afSAkinobu Mita 	__be16 csum;
2396beb40ea4SAkinobu Mita 
2397773642d9SDouglas Gilbert 	if (sdebug_guard)
239851d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
239951d648afSAkinobu Mita 	else
2400beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
240151d648afSAkinobu Mita 
2402beb40ea4SAkinobu Mita 	return csum;
2403beb40ea4SAkinobu Mita }
2404beb40ea4SAkinobu Mita 
2405beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2406beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2407beb40ea4SAkinobu Mita {
2408773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2409beb40ea4SAkinobu Mita 
2410beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2411c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2412beb40ea4SAkinobu Mita 			(unsigned long)sector,
2413beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2414beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2415beb40ea4SAkinobu Mita 		return 0x01;
2416beb40ea4SAkinobu Mita 	}
2417773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
2418beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2419c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2420c1287970STomas Winkler 			(unsigned long)sector);
2421beb40ea4SAkinobu Mita 		return 0x03;
2422beb40ea4SAkinobu Mita 	}
2423773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2424beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2425c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2426c1287970STomas Winkler 			(unsigned long)sector);
2427beb40ea4SAkinobu Mita 		return 0x03;
2428beb40ea4SAkinobu Mita 	}
2429beb40ea4SAkinobu Mita 	return 0;
2430beb40ea4SAkinobu Mita }
2431beb40ea4SAkinobu Mita 
2432bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
243365f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2434c6a44287SMartin K. Petersen {
2435be4e11beSAkinobu Mita 	size_t resid;
2436c6a44287SMartin K. Petersen 	void *paddr;
243714faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2438be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2439c6a44287SMartin K. Petersen 
2440e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2441e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2442c6a44287SMartin K. Petersen 
2443be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2444be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2445be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2446be4e11beSAkinobu Mita 
2447be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2448be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
244914faa944SAkinobu Mita 		void *start = dif_store(sector);
2450be4e11beSAkinobu Mita 		size_t rest = 0;
245114faa944SAkinobu Mita 
245214faa944SAkinobu Mita 		if (dif_store_end < start + len)
245314faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2454c6a44287SMartin K. Petersen 
2455be4e11beSAkinobu Mita 		paddr = miter.addr;
245614faa944SAkinobu Mita 
245765f72f2aSAkinobu Mita 		if (read)
245865f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
245965f72f2aSAkinobu Mita 		else
246065f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
246165f72f2aSAkinobu Mita 
246265f72f2aSAkinobu Mita 		if (rest) {
246365f72f2aSAkinobu Mita 			if (read)
246414faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
246565f72f2aSAkinobu Mita 			else
246665f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
246765f72f2aSAkinobu Mita 		}
2468c6a44287SMartin K. Petersen 
2469e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2470c6a44287SMartin K. Petersen 		resid -= len;
2471c6a44287SMartin K. Petersen 	}
2472be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2473bb8c063cSAkinobu Mita }
2474c6a44287SMartin K. Petersen 
2475bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2476bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2477bb8c063cSAkinobu Mita {
2478bb8c063cSAkinobu Mita 	unsigned int i;
2479bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
2480bb8c063cSAkinobu Mita 	sector_t sector;
2481bb8c063cSAkinobu Mita 
2482c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2483bb8c063cSAkinobu Mita 		int ret;
2484bb8c063cSAkinobu Mita 
2485bb8c063cSAkinobu Mita 		sector = start_sec + i;
2486bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2487bb8c063cSAkinobu Mita 
248851d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2489bb8c063cSAkinobu Mita 			continue;
2490bb8c063cSAkinobu Mita 
2491bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2492bb8c063cSAkinobu Mita 		if (ret) {
2493bb8c063cSAkinobu Mita 			dif_errors++;
2494bb8c063cSAkinobu Mita 			return ret;
2495bb8c063cSAkinobu Mita 		}
2496bb8c063cSAkinobu Mita 	}
2497bb8c063cSAkinobu Mita 
249865f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2499c6a44287SMartin K. Petersen 	dix_reads++;
2500c6a44287SMartin K. Petersen 
2501c6a44287SMartin K. Petersen 	return 0;
2502c6a44287SMartin K. Petersen }
2503c6a44287SMartin K. Petersen 
2504fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
250519789100SFUJITA Tomonori {
2506c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2507c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2508c2248fc9SDouglas Gilbert 	u64 lba;
2509c2248fc9SDouglas Gilbert 	u32 num;
2510c2248fc9SDouglas Gilbert 	u32 ei_lba;
251119789100SFUJITA Tomonori 	unsigned long iflags;
251219789100SFUJITA Tomonori 	int ret;
2513c2248fc9SDouglas Gilbert 	bool check_prot;
251419789100SFUJITA Tomonori 
2515c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2516c2248fc9SDouglas Gilbert 	case READ_16:
2517c2248fc9SDouglas Gilbert 		ei_lba = 0;
2518c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2519c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2520c2248fc9SDouglas Gilbert 		check_prot = true;
2521c2248fc9SDouglas Gilbert 		break;
2522c2248fc9SDouglas Gilbert 	case READ_10:
2523c2248fc9SDouglas Gilbert 		ei_lba = 0;
2524c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2525c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2526c2248fc9SDouglas Gilbert 		check_prot = true;
2527c2248fc9SDouglas Gilbert 		break;
2528c2248fc9SDouglas Gilbert 	case READ_6:
2529c2248fc9SDouglas Gilbert 		ei_lba = 0;
2530c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2531c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2532c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2533c2248fc9SDouglas Gilbert 		check_prot = true;
2534c2248fc9SDouglas Gilbert 		break;
2535c2248fc9SDouglas Gilbert 	case READ_12:
2536c2248fc9SDouglas Gilbert 		ei_lba = 0;
2537c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2538c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2539c2248fc9SDouglas Gilbert 		check_prot = true;
2540c2248fc9SDouglas Gilbert 		break;
2541c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2542c2248fc9SDouglas Gilbert 		ei_lba = 0;
2543c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2544c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2545c2248fc9SDouglas Gilbert 		check_prot = false;
2546c2248fc9SDouglas Gilbert 		break;
2547c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2548c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2549c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2550c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2551c2248fc9SDouglas Gilbert 		check_prot = false;
2552c2248fc9SDouglas Gilbert 		break;
2553c2248fc9SDouglas Gilbert 	}
2554f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
2555773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2556c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2557c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2558c2248fc9SDouglas Gilbert 			return check_condition_result;
2559c2248fc9SDouglas Gilbert 		}
2560773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2561773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2562c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2563c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2564c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2565c2248fc9SDouglas Gilbert 	}
2566f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2567c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2568c2248fc9SDouglas Gilbert 
2569c4837394SDouglas Gilbert 		if (sqcp) {
2570c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2571c2248fc9SDouglas Gilbert 				num /= 2;
2572c2248fc9SDouglas Gilbert 		}
2573c4837394SDouglas Gilbert 	} else
2574c4837394SDouglas Gilbert 		sqcp = NULL;
2575c2248fc9SDouglas Gilbert 
2576c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2577f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2578c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2579c2248fc9SDouglas Gilbert 		return check_condition_result;
2580c2248fc9SDouglas Gilbert 	}
2581c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2582f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2583c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2584c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2585c2248fc9SDouglas Gilbert 		return check_condition_result;
2586c2248fc9SDouglas Gilbert 	}
258719789100SFUJITA Tomonori 
2588f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
258932f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2590f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2591c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2592c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2593c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2594c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2595c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
259632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
259732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2598c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2599c65b1445SDouglas Gilbert 		}
2600c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
26011da177e4SLinus Torvalds 		return check_condition_result;
26021da177e4SLinus Torvalds 	}
2603c6a44287SMartin K. Petersen 
26046c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
26056c78cc06SAkinobu Mita 
2606c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2607f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2608c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2609c6a44287SMartin K. Petersen 
2610c6a44287SMartin K. Petersen 		if (prot_ret) {
26116c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2612c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2613c6a44287SMartin K. Petersen 			return illegal_condition_result;
2614c6a44287SMartin K. Petersen 		}
2615c6a44287SMartin K. Petersen 	}
2616c6a44287SMartin K. Petersen 
2617c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
26181da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2619f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2620a4517511SAkinobu Mita 		return DID_ERROR << 16;
2621a4517511SAkinobu Mita 
2622c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2623a4517511SAkinobu Mita 
2624c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2625c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2626c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2627c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2628c2248fc9SDouglas Gilbert 			return check_condition_result;
2629c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2630c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2631c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2632c2248fc9SDouglas Gilbert 			return check_condition_result;
2633c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2634c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2635c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2636c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2637c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2638c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2639c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2640c2248fc9SDouglas Gilbert 		}
2641c2248fc9SDouglas Gilbert 	}
2642a4517511SAkinobu Mita 	return 0;
26431da177e4SLinus Torvalds }
26441da177e4SLinus Torvalds 
264558a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2646c6a44287SMartin K. Petersen {
2647cbf67842SDouglas Gilbert 	int i, j, n;
2648c6a44287SMartin K. Petersen 
2649cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2650c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2651cbf67842SDouglas Gilbert 		char b[128];
2652c6a44287SMartin K. Petersen 
2653cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2654c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2655c6a44287SMartin K. Petersen 
2656cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2657cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2658cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2659cbf67842SDouglas Gilbert 			else
2660cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2661cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2662cbf67842SDouglas Gilbert 		}
2663cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2664c6a44287SMartin K. Petersen 	}
2665c6a44287SMartin K. Petersen }
2666c6a44287SMartin K. Petersen 
2667c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2668395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2669c6a44287SMartin K. Petersen {
2670be4e11beSAkinobu Mita 	int ret;
2671c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2672be4e11beSAkinobu Mita 	void *daddr;
267365f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2674c6a44287SMartin K. Petersen 	int ppage_offset;
2675be4e11beSAkinobu Mita 	int dpage_offset;
2676be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2677be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2678c6a44287SMartin K. Petersen 
2679c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2680c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2681c6a44287SMartin K. Petersen 
2682be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2683be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2684be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2685be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2686be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2687c6a44287SMartin K. Petersen 
2688be4e11beSAkinobu Mita 	/* For each protection page */
2689be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2690be4e11beSAkinobu Mita 		dpage_offset = 0;
2691be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2692be4e11beSAkinobu Mita 			ret = 0x01;
2693be4e11beSAkinobu Mita 			goto out;
2694c6a44287SMartin K. Petersen 		}
2695c6a44287SMartin K. Petersen 
2696be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2697be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2698be4e11beSAkinobu Mita 			/* If we're at the end of the current
2699be4e11beSAkinobu Mita 			 * data page advance to the next one
2700be4e11beSAkinobu Mita 			 */
2701be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2702be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2703be4e11beSAkinobu Mita 					ret = 0x01;
2704be4e11beSAkinobu Mita 					goto out;
2705be4e11beSAkinobu Mita 				}
2706be4e11beSAkinobu Mita 				dpage_offset = 0;
2707be4e11beSAkinobu Mita 			}
2708c6a44287SMartin K. Petersen 
2709be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2710be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2711be4e11beSAkinobu Mita 
2712be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2713beb40ea4SAkinobu Mita 			if (ret) {
2714773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2715395cef03SMartin K. Petersen 				goto out;
2716395cef03SMartin K. Petersen 			}
2717395cef03SMartin K. Petersen 
2718c6a44287SMartin K. Petersen 			sector++;
2719395cef03SMartin K. Petersen 			ei_lba++;
2720773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2721c6a44287SMartin K. Petersen 		}
2722be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2723be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2724c6a44287SMartin K. Petersen 	}
2725be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2726c6a44287SMartin K. Petersen 
272765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2728c6a44287SMartin K. Petersen 	dix_writes++;
2729c6a44287SMartin K. Petersen 
2730c6a44287SMartin K. Petersen 	return 0;
2731c6a44287SMartin K. Petersen 
2732c6a44287SMartin K. Petersen out:
2733c6a44287SMartin K. Petersen 	dif_errors++;
2734be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2735be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2736c6a44287SMartin K. Petersen 	return ret;
2737c6a44287SMartin K. Petersen }
2738c6a44287SMartin K. Petersen 
2739b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2740b90ebc3dSAkinobu Mita {
2741773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2742773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2743773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2744b90ebc3dSAkinobu Mita 	return lba;
2745b90ebc3dSAkinobu Mita }
2746b90ebc3dSAkinobu Mita 
2747b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2748b90ebc3dSAkinobu Mita {
2749773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2750a027b5b9SAkinobu Mita 
2751773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2752773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2753a027b5b9SAkinobu Mita 	return lba;
2754a027b5b9SAkinobu Mita }
2755a027b5b9SAkinobu Mita 
275644d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
275744d92694SMartin K. Petersen {
2758b90ebc3dSAkinobu Mita 	sector_t end;
2759b90ebc3dSAkinobu Mita 	unsigned int mapped;
2760b90ebc3dSAkinobu Mita 	unsigned long index;
2761b90ebc3dSAkinobu Mita 	unsigned long next;
276244d92694SMartin K. Petersen 
2763b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2764b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
276544d92694SMartin K. Petersen 
276644d92694SMartin K. Petersen 	if (mapped)
2767b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
276844d92694SMartin K. Petersen 	else
2769b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
277044d92694SMartin K. Petersen 
2771b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
277244d92694SMartin K. Petersen 	*num = end - lba;
277344d92694SMartin K. Petersen 	return mapped;
277444d92694SMartin K. Petersen }
277544d92694SMartin K. Petersen 
277644d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
277744d92694SMartin K. Petersen {
277844d92694SMartin K. Petersen 	sector_t end = lba + len;
277944d92694SMartin K. Petersen 
278044d92694SMartin K. Petersen 	while (lba < end) {
2781b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
278244d92694SMartin K. Petersen 
2783b90ebc3dSAkinobu Mita 		if (index < map_size)
2784b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
278544d92694SMartin K. Petersen 
2786b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
278744d92694SMartin K. Petersen 	}
278844d92694SMartin K. Petersen }
278944d92694SMartin K. Petersen 
279044d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
279144d92694SMartin K. Petersen {
279244d92694SMartin K. Petersen 	sector_t end = lba + len;
279344d92694SMartin K. Petersen 
279444d92694SMartin K. Petersen 	while (lba < end) {
2795b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
279644d92694SMartin K. Petersen 
2797b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2798773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2799b90ebc3dSAkinobu Mita 		    index < map_size) {
2800b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2801760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2802be1dd78dSEric Sandeen 				memset(fake_storep +
2803760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2804760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2805773642d9SDouglas Gilbert 				       sdebug_sector_size *
2806773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2807be1dd78dSEric Sandeen 			}
2808e9926b43SAkinobu Mita 			if (dif_storep) {
2809e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2810e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2811773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2812e9926b43SAkinobu Mita 			}
2813b90ebc3dSAkinobu Mita 		}
2814b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
281544d92694SMartin K. Petersen 	}
281644d92694SMartin K. Petersen }
281744d92694SMartin K. Petersen 
2818fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28191da177e4SLinus Torvalds {
2820c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2821c2248fc9SDouglas Gilbert 	u64 lba;
2822c2248fc9SDouglas Gilbert 	u32 num;
2823c2248fc9SDouglas Gilbert 	u32 ei_lba;
28241da177e4SLinus Torvalds 	unsigned long iflags;
282519789100SFUJITA Tomonori 	int ret;
2826c2248fc9SDouglas Gilbert 	bool check_prot;
28271da177e4SLinus Torvalds 
2828c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2829c2248fc9SDouglas Gilbert 	case WRITE_16:
2830c2248fc9SDouglas Gilbert 		ei_lba = 0;
2831c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2832c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2833c2248fc9SDouglas Gilbert 		check_prot = true;
2834c2248fc9SDouglas Gilbert 		break;
2835c2248fc9SDouglas Gilbert 	case WRITE_10:
2836c2248fc9SDouglas Gilbert 		ei_lba = 0;
2837c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2838c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2839c2248fc9SDouglas Gilbert 		check_prot = true;
2840c2248fc9SDouglas Gilbert 		break;
2841c2248fc9SDouglas Gilbert 	case WRITE_6:
2842c2248fc9SDouglas Gilbert 		ei_lba = 0;
2843c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2844c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2845c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2846c2248fc9SDouglas Gilbert 		check_prot = true;
2847c2248fc9SDouglas Gilbert 		break;
2848c2248fc9SDouglas Gilbert 	case WRITE_12:
2849c2248fc9SDouglas Gilbert 		ei_lba = 0;
2850c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2851c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2852c2248fc9SDouglas Gilbert 		check_prot = true;
2853c2248fc9SDouglas Gilbert 		break;
2854c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2855c2248fc9SDouglas Gilbert 		ei_lba = 0;
2856c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2857c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2858c2248fc9SDouglas Gilbert 		check_prot = false;
2859c2248fc9SDouglas Gilbert 		break;
2860c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2861c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2862c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2863c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2864c2248fc9SDouglas Gilbert 		check_prot = false;
2865c2248fc9SDouglas Gilbert 		break;
2866c2248fc9SDouglas Gilbert 	}
2867f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
2868773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2869c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2870c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2871c2248fc9SDouglas Gilbert 			return check_condition_result;
2872c2248fc9SDouglas Gilbert 		}
2873773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2874773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2875c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2876c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2877c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2878c2248fc9SDouglas Gilbert 	}
2879c2248fc9SDouglas Gilbert 
2880c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2881f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2882c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2883c2248fc9SDouglas Gilbert 		return check_condition_result;
2884c2248fc9SDouglas Gilbert 	}
2885c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2886f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2887c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2888c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2889c2248fc9SDouglas Gilbert 		return check_condition_result;
2890c2248fc9SDouglas Gilbert 	}
28911da177e4SLinus Torvalds 
28926c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
28936c78cc06SAkinobu Mita 
2894c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2895f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2896c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2897c6a44287SMartin K. Petersen 
2898c6a44287SMartin K. Petersen 		if (prot_ret) {
28996c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2900c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2901c6a44287SMartin K. Petersen 			return illegal_condition_result;
2902c6a44287SMartin K. Petersen 		}
2903c6a44287SMartin K. Petersen 	}
2904c6a44287SMartin K. Petersen 
2905c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
2906f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
290744d92694SMartin K. Petersen 		map_region(lba, num);
29081da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
2909f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
2910773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2911c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
2912c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
2913c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2914cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2915773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
291644d92694SMartin K. Petersen 
2917f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2918c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
2919c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
2920c2248fc9SDouglas Gilbert 
2921c4837394SDouglas Gilbert 		if (sqcp) {
2922c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
2923c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
2924c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
2925c2248fc9SDouglas Gilbert 				return check_condition_result;
2926c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
2927c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
2928c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2929c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2930c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
2931c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2932c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2933c2248fc9SDouglas Gilbert 			}
2934c2248fc9SDouglas Gilbert 		}
2935c4837394SDouglas Gilbert 	}
29361da177e4SLinus Torvalds 	return 0;
29371da177e4SLinus Torvalds }
29381da177e4SLinus Torvalds 
2939fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2940fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
294144d92694SMartin K. Petersen {
294244d92694SMartin K. Petersen 	unsigned long iflags;
294344d92694SMartin K. Petersen 	unsigned long long i;
294444d92694SMartin K. Petersen 	int ret;
2945773642d9SDouglas Gilbert 	u64 lba_off;
294644d92694SMartin K. Petersen 
2947c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
294844d92694SMartin K. Petersen 	if (ret)
294944d92694SMartin K. Petersen 		return ret;
295044d92694SMartin K. Petersen 
295144d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
295244d92694SMartin K. Petersen 
29539ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
295444d92694SMartin K. Petersen 		unmap_region(lba, num);
295544d92694SMartin K. Petersen 		goto out;
295644d92694SMartin K. Petersen 	}
295744d92694SMartin K. Petersen 
2958773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
2959c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2960c2248fc9SDouglas Gilbert 	if (ndob) {
2961773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
2962c2248fc9SDouglas Gilbert 		ret = 0;
2963c2248fc9SDouglas Gilbert 	} else
2964773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2965773642d9SDouglas Gilbert 					  sdebug_sector_size);
296644d92694SMartin K. Petersen 
296744d92694SMartin K. Petersen 	if (-1 == ret) {
296844d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
2969773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2970773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
2971c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2972cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2973cbf67842SDouglas Gilbert 			    my_name, "write same",
2974773642d9SDouglas Gilbert 			    num * sdebug_sector_size, ret);
297544d92694SMartin K. Petersen 
297644d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
297744d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
2978773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2979773642d9SDouglas Gilbert 		       fake_storep + lba_off,
2980773642d9SDouglas Gilbert 		       sdebug_sector_size);
298144d92694SMartin K. Petersen 
29829ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
298344d92694SMartin K. Petersen 		map_region(lba, num);
298444d92694SMartin K. Petersen out:
298544d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
298644d92694SMartin K. Petersen 
298744d92694SMartin K. Petersen 	return 0;
298844d92694SMartin K. Petersen }
298944d92694SMartin K. Petersen 
2990fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
2991fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
2992c2248fc9SDouglas Gilbert {
2993c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2994c2248fc9SDouglas Gilbert 	u32 lba;
2995c2248fc9SDouglas Gilbert 	u16 num;
2996c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2997c2248fc9SDouglas Gilbert 	bool unmap = false;
2998c2248fc9SDouglas Gilbert 
2999c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3000773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3001c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3002c2248fc9SDouglas Gilbert 			return check_condition_result;
3003c2248fc9SDouglas Gilbert 		} else
3004c2248fc9SDouglas Gilbert 			unmap = true;
3005c2248fc9SDouglas Gilbert 	}
3006c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3007c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3008773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3009c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3010c2248fc9SDouglas Gilbert 		return check_condition_result;
3011c2248fc9SDouglas Gilbert 	}
3012c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3013c2248fc9SDouglas Gilbert }
3014c2248fc9SDouglas Gilbert 
3015fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3016fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3017c2248fc9SDouglas Gilbert {
3018c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3019c2248fc9SDouglas Gilbert 	u64 lba;
3020c2248fc9SDouglas Gilbert 	u32 num;
3021c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3022c2248fc9SDouglas Gilbert 	bool unmap = false;
3023c2248fc9SDouglas Gilbert 	bool ndob = false;
3024c2248fc9SDouglas Gilbert 
3025c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3026773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3027c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3028c2248fc9SDouglas Gilbert 			return check_condition_result;
3029c2248fc9SDouglas Gilbert 		} else
3030c2248fc9SDouglas Gilbert 			unmap = true;
3031c2248fc9SDouglas Gilbert 	}
3032c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3033c2248fc9SDouglas Gilbert 		ndob = true;
3034c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3035c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3036773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3037c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3038c2248fc9SDouglas Gilbert 		return check_condition_result;
3039c2248fc9SDouglas Gilbert 	}
3040c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3041c2248fc9SDouglas Gilbert }
3042c2248fc9SDouglas Gilbert 
3043acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3044acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3045acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3046fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3047fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3048acafd0b9SEwan D. Milne {
3049acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3050acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3051acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3052acafd0b9SEwan D. Milne 	u8 mode;
3053acafd0b9SEwan D. Milne 
3054acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3055acafd0b9SEwan D. Milne 	switch (mode) {
3056acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3057acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3058acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3059acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3060acafd0b9SEwan D. Milne 		break;
3061acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3062acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3063acafd0b9SEwan D. Milne 		break;
3064acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3065acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3066acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3067acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3068acafd0b9SEwan D. Milne 				    dev_list)
3069acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3070acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3071acafd0b9SEwan D. Milne 				if (devip != dp)
3072acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3073acafd0b9SEwan D. Milne 						dp->uas_bm);
3074acafd0b9SEwan D. Milne 			}
3075acafd0b9SEwan D. Milne 		break;
3076acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3077acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3078acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3079acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3080acafd0b9SEwan D. Milne 				    dev_list)
3081acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3082acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3083acafd0b9SEwan D. Milne 					dp->uas_bm);
3084acafd0b9SEwan D. Milne 		break;
3085acafd0b9SEwan D. Milne 	default:
3086acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3087acafd0b9SEwan D. Milne 		break;
3088acafd0b9SEwan D. Milne 	}
3089acafd0b9SEwan D. Milne 	return 0;
3090acafd0b9SEwan D. Milne }
3091acafd0b9SEwan D. Milne 
3092fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3093fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
309438d5c833SDouglas Gilbert {
309538d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
309638d5c833SDouglas Gilbert 	u8 *arr;
309738d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
309838d5c833SDouglas Gilbert 	u64 lba;
309938d5c833SDouglas Gilbert 	u32 dnum;
3100773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
310138d5c833SDouglas Gilbert 	u8 num;
310238d5c833SDouglas Gilbert 	unsigned long iflags;
310338d5c833SDouglas Gilbert 	int ret;
3104d467d31fSDouglas Gilbert 	int retval = 0;
310538d5c833SDouglas Gilbert 
3106d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
310738d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
310838d5c833SDouglas Gilbert 	if (0 == num)
310938d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
3110773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
311138d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
311238d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
311338d5c833SDouglas Gilbert 		return check_condition_result;
311438d5c833SDouglas Gilbert 	}
3115773642d9SDouglas Gilbert 	if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3116773642d9SDouglas Gilbert 	     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
311738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
311838d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
311938d5c833SDouglas Gilbert 			    "to DIF device\n");
312038d5c833SDouglas Gilbert 
312138d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
312238d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
312338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
312438d5c833SDouglas Gilbert 		return check_condition_result;
312538d5c833SDouglas Gilbert 	}
312638d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
312738d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
312838d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
312938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
313038d5c833SDouglas Gilbert 		return check_condition_result;
313138d5c833SDouglas Gilbert 	}
3132d467d31fSDouglas Gilbert 	dnum = 2 * num;
3133d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3134d467d31fSDouglas Gilbert 	if (NULL == arr) {
3135d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3136d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3137d467d31fSDouglas Gilbert 		return check_condition_result;
3138d467d31fSDouglas Gilbert 	}
313938d5c833SDouglas Gilbert 
314038d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
314138d5c833SDouglas Gilbert 
314238d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
314338d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
314438d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
314538d5c833SDouglas Gilbert 	fake_storep = arr;
314638d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
314738d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
314838d5c833SDouglas Gilbert 	if (ret == -1) {
3149d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3150d467d31fSDouglas Gilbert 		goto cleanup;
3151773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
315238d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
315338d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
315438d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
315538d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
315638d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3157d467d31fSDouglas Gilbert 		retval = check_condition_result;
3158d467d31fSDouglas Gilbert 		goto cleanup;
315938d5c833SDouglas Gilbert 	}
316038d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
316138d5c833SDouglas Gilbert 		map_region(lba, num);
3162d467d31fSDouglas Gilbert cleanup:
316338d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3164d467d31fSDouglas Gilbert 	kfree(arr);
3165d467d31fSDouglas Gilbert 	return retval;
316638d5c833SDouglas Gilbert }
316738d5c833SDouglas Gilbert 
316844d92694SMartin K. Petersen struct unmap_block_desc {
316944d92694SMartin K. Petersen 	__be64	lba;
317044d92694SMartin K. Petersen 	__be32	blocks;
317144d92694SMartin K. Petersen 	__be32	__reserved;
317244d92694SMartin K. Petersen };
317344d92694SMartin K. Petersen 
3174fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
317544d92694SMartin K. Petersen {
317644d92694SMartin K. Petersen 	unsigned char *buf;
317744d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
317844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
317944d92694SMartin K. Petersen 	int ret;
31806c78cc06SAkinobu Mita 	unsigned long iflags;
318144d92694SMartin K. Petersen 
318244d92694SMartin K. Petersen 
3183c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3184c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3185c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3186c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
318744d92694SMartin K. Petersen 
318844d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3189773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3190c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
319144d92694SMartin K. Petersen 		return check_condition_result;
3192c2248fc9SDouglas Gilbert 	}
319344d92694SMartin K. Petersen 
3194b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3195c2248fc9SDouglas Gilbert 	if (!buf) {
3196c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3197c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3198c2248fc9SDouglas Gilbert 		return check_condition_result;
3199c2248fc9SDouglas Gilbert 	}
3200c2248fc9SDouglas Gilbert 
3201c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
320244d92694SMartin K. Petersen 
320344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
320444d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
320544d92694SMartin K. Petersen 
320644d92694SMartin K. Petersen 	desc = (void *)&buf[8];
320744d92694SMartin K. Petersen 
32086c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
32096c78cc06SAkinobu Mita 
321044d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
321144d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
321244d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
321344d92694SMartin K. Petersen 
3214c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
321544d92694SMartin K. Petersen 		if (ret)
321644d92694SMartin K. Petersen 			goto out;
321744d92694SMartin K. Petersen 
321844d92694SMartin K. Petersen 		unmap_region(lba, num);
321944d92694SMartin K. Petersen 	}
322044d92694SMartin K. Petersen 
322144d92694SMartin K. Petersen 	ret = 0;
322244d92694SMartin K. Petersen 
322344d92694SMartin K. Petersen out:
32246c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
322544d92694SMartin K. Petersen 	kfree(buf);
322644d92694SMartin K. Petersen 
322744d92694SMartin K. Petersen 	return ret;
322844d92694SMartin K. Petersen }
322944d92694SMartin K. Petersen 
323044d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
323144d92694SMartin K. Petersen 
3232fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3233fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
323444d92694SMartin K. Petersen {
3235c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3236c2248fc9SDouglas Gilbert 	u64 lba;
3237c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3238c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
323944d92694SMartin K. Petersen 	int ret;
324044d92694SMartin K. Petersen 
3241c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3242c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
324344d92694SMartin K. Petersen 
324444d92694SMartin K. Petersen 	if (alloc_len < 24)
324544d92694SMartin K. Petersen 		return 0;
324644d92694SMartin K. Petersen 
3247c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
324844d92694SMartin K. Petersen 	if (ret)
324944d92694SMartin K. Petersen 		return ret;
325044d92694SMartin K. Petersen 
3251c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
325244d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3253c2248fc9SDouglas Gilbert 	else {
3254c2248fc9SDouglas Gilbert 		mapped = 1;
3255c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3256c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3257c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3258c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3259c2248fc9SDouglas Gilbert 		else
3260c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3261c2248fc9SDouglas Gilbert 	}
326244d92694SMartin K. Petersen 
326344d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3264c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3265c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3266c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3267c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
326844d92694SMartin K. Petersen 
3269c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
327044d92694SMartin K. Petersen }
327144d92694SMartin K. Petersen 
32728d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
32738d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
32748d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
32758d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
32768d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
32778d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
32788d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
32798d039e22SDouglas Gilbert  */
32801da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
32811da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
32821da177e4SLinus Torvalds {
328301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
32848d039e22SDouglas Gilbert 	unsigned int alloc_len;
32858d039e22SDouglas Gilbert 	unsigned char select_report;
32868d039e22SDouglas Gilbert 	u64 lun;
32878d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
32888d039e22SDouglas Gilbert 	u8 *arr;
32898d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
32908d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
32918d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
32928d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
32938d039e22SDouglas Gilbert 	int i, res;
32941da177e4SLinus Torvalds 
329519c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
32968d039e22SDouglas Gilbert 
32978d039e22SDouglas Gilbert 	select_report = cmd[2];
32988d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
32998d039e22SDouglas Gilbert 
33008d039e22SDouglas Gilbert 	if (alloc_len < 4) {
33018d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
33028d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
33031da177e4SLinus Torvalds 		return check_condition_result;
33041da177e4SLinus Torvalds 	}
33058d039e22SDouglas Gilbert 
33068d039e22SDouglas Gilbert 	switch (select_report) {
33078d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3308773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33098d039e22SDouglas Gilbert 		wlun_cnt = 0;
33108d039e22SDouglas Gilbert 		break;
33118d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3312c65b1445SDouglas Gilbert 		lun_cnt = 0;
33138d039e22SDouglas Gilbert 		wlun_cnt = 1;
33148d039e22SDouglas Gilbert 		break;
33158d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
33168d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33178d039e22SDouglas Gilbert 		wlun_cnt = 1;
33188d039e22SDouglas Gilbert 		break;
33198d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
33208d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
33218d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
33228d039e22SDouglas Gilbert 	default:
33238d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
33248d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
33258d039e22SDouglas Gilbert 		return check_condition_result;
33268d039e22SDouglas Gilbert 	}
33278d039e22SDouglas Gilbert 
33288d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3329c65b1445SDouglas Gilbert 		--lun_cnt;
33308d039e22SDouglas Gilbert 
33318d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
33328d039e22SDouglas Gilbert 
33338d039e22SDouglas Gilbert 	rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8;
33348d039e22SDouglas Gilbert 	arr = vmalloc(rlen);
33358d039e22SDouglas Gilbert 	if (!arr) {
33368d039e22SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
33378d039e22SDouglas Gilbert 				INSUFF_RES_ASCQ);
33388d039e22SDouglas Gilbert 		return check_condition_result;
3339c65b1445SDouglas Gilbert 	}
33408d039e22SDouglas Gilbert 	memset(arr, 0, rlen);
33418d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
33428d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
33438d039e22SDouglas Gilbert 
33448d039e22SDouglas Gilbert 	/* luns start at byte 8 in response following the header */
33458d039e22SDouglas Gilbert 	lun_p = (struct scsi_lun *)&arr[8];
33468d039e22SDouglas Gilbert 
33478d039e22SDouglas Gilbert 	/* LUNs use single level peripheral device addressing method */
33488d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
33498d039e22SDouglas Gilbert 	for (i = 0; i < lun_cnt; i++)
33508d039e22SDouglas Gilbert 		int_to_scsilun(lun++, lun_p++);
33518d039e22SDouglas Gilbert 
33528d039e22SDouglas Gilbert 	if (wlun_cnt)
33538d039e22SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
33548d039e22SDouglas Gilbert 
33558d039e22SDouglas Gilbert 	put_unaligned_be32(rlen - 8, &arr[0]);
33568d039e22SDouglas Gilbert 
33578d039e22SDouglas Gilbert 	res = fill_from_dev_buffer(scp, arr, rlen);
33588d039e22SDouglas Gilbert 	vfree(arr);
33598d039e22SDouglas Gilbert 	return res;
33601da177e4SLinus Torvalds }
33611da177e4SLinus Torvalds 
3362c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3363c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3364c639d14eSFUJITA Tomonori {
3365be4e11beSAkinobu Mita 	int j;
3366c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3367c639d14eSFUJITA Tomonori 	unsigned int offset;
3368c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3369be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3370c639d14eSFUJITA Tomonori 
3371c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3372b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3373c5af0db9SAkinobu Mita 	if (!buf) {
337422017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
337522017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3376c5af0db9SAkinobu Mita 		return check_condition_result;
3377c5af0db9SAkinobu Mita 	}
3378c639d14eSFUJITA Tomonori 
337921a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3380c639d14eSFUJITA Tomonori 
3381c639d14eSFUJITA Tomonori 	offset = 0;
3382be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3383be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3384c639d14eSFUJITA Tomonori 
3385be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3386be4e11beSAkinobu Mita 		kaddr = miter.addr;
3387be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3388be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3389c639d14eSFUJITA Tomonori 
3390be4e11beSAkinobu Mita 		offset += miter.length;
3391c639d14eSFUJITA Tomonori 	}
3392be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3393c639d14eSFUJITA Tomonori 	kfree(buf);
3394c639d14eSFUJITA Tomonori 
3395be4e11beSAkinobu Mita 	return 0;
3396c639d14eSFUJITA Tomonori }
3397c639d14eSFUJITA Tomonori 
3398fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3399fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3400c2248fc9SDouglas Gilbert {
3401c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3402c2248fc9SDouglas Gilbert 	u64 lba;
3403c2248fc9SDouglas Gilbert 	u32 num;
3404c2248fc9SDouglas Gilbert 	int errsts;
3405c2248fc9SDouglas Gilbert 
3406c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3407c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3408c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3409c2248fc9SDouglas Gilbert 		return check_condition_result;
3410c2248fc9SDouglas Gilbert 	}
3411c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3412c2248fc9SDouglas Gilbert 	if (errsts)
3413c2248fc9SDouglas Gilbert 		return errsts;
3414c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3415c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3416c2248fc9SDouglas Gilbert 		if (errsts)
3417c2248fc9SDouglas Gilbert 			return errsts;
3418c2248fc9SDouglas Gilbert 	}
3419c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3420c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3421c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3422c2248fc9SDouglas Gilbert }
3423c2248fc9SDouglas Gilbert 
3424c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3425c4837394SDouglas Gilbert {
3426c4837394SDouglas Gilbert 	struct sdebug_queue *sqp = sdebug_q_arr;
3427c4837394SDouglas Gilbert 
3428c4837394SDouglas Gilbert 	if (sdebug_mq_active) {
3429c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
3430c4837394SDouglas Gilbert 		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3431c4837394SDouglas Gilbert 
3432c4837394SDouglas Gilbert 		if (unlikely(hwq >= submit_queues)) {
3433c4837394SDouglas Gilbert 			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3434c4837394SDouglas Gilbert 			hwq %= submit_queues;
3435c4837394SDouglas Gilbert 		}
3436c4837394SDouglas Gilbert 		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3437c4837394SDouglas Gilbert 		return sqp + hwq;
3438c4837394SDouglas Gilbert 	} else
3439c4837394SDouglas Gilbert 		return sqp;
3440c4837394SDouglas Gilbert }
3441c4837394SDouglas Gilbert 
3442c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3443fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
34441da177e4SLinus Torvalds {
3445c4837394SDouglas Gilbert 	int qc_idx;
3446cbf67842SDouglas Gilbert 	int retiring = 0;
34471da177e4SLinus Torvalds 	unsigned long iflags;
3448c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3449cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3450cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3451cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
34521da177e4SLinus Torvalds 
3453c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3454c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3455c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3456cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3457c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3458c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3459c4837394SDouglas Gilbert 	}
3460c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3461c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
34621da177e4SLinus Torvalds 		return;
34631da177e4SLinus Torvalds 	}
3464c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3465c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3466cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3467b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3468c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3469c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3470c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
34711da177e4SLinus Torvalds 		return;
34721da177e4SLinus Torvalds 	}
3473cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3474f46eb0e9SDouglas Gilbert 	if (likely(devip))
3475cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3476cbf67842SDouglas Gilbert 	else
3477c1287970STomas Winkler 		pr_err("devip=NULL\n");
3478f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3479cbf67842SDouglas Gilbert 		retiring = 1;
3480cbf67842SDouglas Gilbert 
3481cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3482c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3483c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3484c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3485cbf67842SDouglas Gilbert 		return;
34861da177e4SLinus Torvalds 	}
34871da177e4SLinus Torvalds 
3488cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3489cbf67842SDouglas Gilbert 		int k, retval;
3490cbf67842SDouglas Gilbert 
3491cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3492c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3493c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3494c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3495cbf67842SDouglas Gilbert 			return;
3496cbf67842SDouglas Gilbert 		}
3497c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3498773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3499cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3500cbf67842SDouglas Gilbert 		else
3501cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3502cbf67842SDouglas Gilbert 	}
3503c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3504cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3505cbf67842SDouglas Gilbert }
3506cbf67842SDouglas Gilbert 
3507cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3508fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3509cbf67842SDouglas Gilbert {
3510a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3511a10bc12aSDouglas Gilbert 						  hrt);
3512a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3513cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3514cbf67842SDouglas Gilbert }
35151da177e4SLinus Torvalds 
3516a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3517fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3518a10bc12aSDouglas Gilbert {
3519a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3520a10bc12aSDouglas Gilbert 						  ew.work);
3521a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3522a10bc12aSDouglas Gilbert }
3523a10bc12aSDouglas Gilbert 
352409ba24c1SDouglas Gilbert static bool got_shared_uuid;
352509ba24c1SDouglas Gilbert static uuid_be shared_uuid;
352609ba24c1SDouglas Gilbert 
3527fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3528fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
35295cb2fc06SFUJITA Tomonori {
35305cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
35315cb2fc06SFUJITA Tomonori 
35325cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
35335cb2fc06SFUJITA Tomonori 	if (devip) {
353409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
353509ba24c1SDouglas Gilbert 			uuid_be_gen(&devip->lu_name);
353609ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
353709ba24c1SDouglas Gilbert 			if (got_shared_uuid)
353809ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
353909ba24c1SDouglas Gilbert 			else {
354009ba24c1SDouglas Gilbert 				uuid_be_gen(&shared_uuid);
354109ba24c1SDouglas Gilbert 				got_shared_uuid = true;
354209ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
354309ba24c1SDouglas Gilbert 			}
354409ba24c1SDouglas Gilbert 		}
35455cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
35465cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
35475cb2fc06SFUJITA Tomonori 	}
35485cb2fc06SFUJITA Tomonori 	return devip;
35495cb2fc06SFUJITA Tomonori }
35505cb2fc06SFUJITA Tomonori 
3551f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
35521da177e4SLinus Torvalds {
35531da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
35541da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3555f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
35561da177e4SLinus Torvalds 
3557d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
35581da177e4SLinus Torvalds 	if (!sdbg_host) {
3559c1287970STomas Winkler 		pr_err("Host info NULL\n");
35601da177e4SLinus Torvalds 		return NULL;
35611da177e4SLinus Torvalds         }
35621da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
35631da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
35641da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
35651da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
35661da177e4SLinus Torvalds                         return devip;
35671da177e4SLinus Torvalds 		else {
35681da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
35691da177e4SLinus Torvalds 				open_devip = devip;
35701da177e4SLinus Torvalds 		}
35711da177e4SLinus Torvalds 	}
35725cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
35735cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
35745cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3575c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
35761da177e4SLinus Torvalds 			return NULL;
35771da177e4SLinus Torvalds 		}
35781da177e4SLinus Torvalds 	}
3579a75869d1SFUJITA Tomonori 
35801da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
35811da177e4SLinus Torvalds 	open_devip->target = sdev->id;
35821da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
35831da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3584cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3585cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3586c2248fc9SDouglas Gilbert 	open_devip->used = true;
35871da177e4SLinus Torvalds 	return open_devip;
35881da177e4SLinus Torvalds }
35891da177e4SLinus Torvalds 
35908dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
35911da177e4SLinus Torvalds {
3592773642d9SDouglas Gilbert 	if (sdebug_verbose)
3593c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
35948dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
359575ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
35968dea0d02SFUJITA Tomonori 	return 0;
35978dea0d02SFUJITA Tomonori }
35981da177e4SLinus Torvalds 
35998dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
36008dea0d02SFUJITA Tomonori {
3601f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3602f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3603a34c4e98SFUJITA Tomonori 
3604773642d9SDouglas Gilbert 	if (sdebug_verbose)
3605c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
36068dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3607b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3608b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3609b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3610f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3611b01f6f83SDouglas Gilbert 		if (devip == NULL)
36128dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3613f46eb0e9SDouglas Gilbert 	}
3614c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
36156bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3616773642d9SDouglas Gilbert 	if (sdebug_no_uld)
361778d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
36188dea0d02SFUJITA Tomonori 	return 0;
36198dea0d02SFUJITA Tomonori }
36208dea0d02SFUJITA Tomonori 
36218dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
36228dea0d02SFUJITA Tomonori {
36238dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
36248dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
36258dea0d02SFUJITA Tomonori 
3626773642d9SDouglas Gilbert 	if (sdebug_verbose)
3627c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
36288dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
36298dea0d02SFUJITA Tomonori 	if (devip) {
363025985edcSLucas De Marchi 		/* make this slot available for re-use */
3631c2248fc9SDouglas Gilbert 		devip->used = false;
36328dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
36338dea0d02SFUJITA Tomonori 	}
36348dea0d02SFUJITA Tomonori }
36358dea0d02SFUJITA Tomonori 
3636c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp)
3637c4837394SDouglas Gilbert {
3638c4837394SDouglas Gilbert 	if (!sd_dp)
3639c4837394SDouglas Gilbert 		return;
3640c4837394SDouglas Gilbert 	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3641c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
3642c4837394SDouglas Gilbert 	else if (sdebug_jdelay < 0)
3643c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3644c4837394SDouglas Gilbert }
3645c4837394SDouglas Gilbert 
3646a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3647a10bc12aSDouglas Gilbert    returns false */
3648a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
36498dea0d02SFUJITA Tomonori {
36508dea0d02SFUJITA Tomonori 	unsigned long iflags;
3651c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
3652c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
36538dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3654cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3655a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
36568dea0d02SFUJITA Tomonori 
3657c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3658c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3659773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3660cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3661cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3662cbf67842SDouglas Gilbert 			qmax = r_qmax;
3663cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3664c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3665c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3666a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3667a10bc12aSDouglas Gilbert 					continue;
3668c4837394SDouglas Gilbert 				/* found */
3669db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3670db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3671db525fceSDouglas Gilbert 				if (devip)
3672db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3673db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3674a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3675c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3676c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3677c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3678a10bc12aSDouglas Gilbert 				return true;
36798dea0d02SFUJITA Tomonori 			}
3680cbf67842SDouglas Gilbert 		}
3681c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3682c4837394SDouglas Gilbert 	}
3683a10bc12aSDouglas Gilbert 	return false;
36848dea0d02SFUJITA Tomonori }
36858dea0d02SFUJITA Tomonori 
3686a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
36878dea0d02SFUJITA Tomonori static void stop_all_queued(void)
36888dea0d02SFUJITA Tomonori {
36898dea0d02SFUJITA Tomonori 	unsigned long iflags;
3690c4837394SDouglas Gilbert 	int j, k;
3691c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
36928dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3693cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3694a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
36958dea0d02SFUJITA Tomonori 
3696c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3697c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3698c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3699c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3700c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3701c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3702a10bc12aSDouglas Gilbert 					continue;
3703db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3704db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3705db525fceSDouglas Gilbert 				if (devip)
3706db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3707db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3708a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3709c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3710c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3711c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3712c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
37138dea0d02SFUJITA Tomonori 			}
37148dea0d02SFUJITA Tomonori 		}
3715c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3716c4837394SDouglas Gilbert 	}
3717cbf67842SDouglas Gilbert }
3718cbf67842SDouglas Gilbert 
3719cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3720cbf67842SDouglas Gilbert static void free_all_queued(void)
3721cbf67842SDouglas Gilbert {
3722c4837394SDouglas Gilbert 	int j, k;
3723c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3724cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3725cbf67842SDouglas Gilbert 
3726c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3727c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3728c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
3729a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
3730a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
3731cbf67842SDouglas Gilbert 		}
37321da177e4SLinus Torvalds 	}
3733c4837394SDouglas Gilbert }
37341da177e4SLinus Torvalds 
37351da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
37361da177e4SLinus Torvalds {
3737a10bc12aSDouglas Gilbert 	bool ok;
3738a10bc12aSDouglas Gilbert 
37391da177e4SLinus Torvalds 	++num_aborts;
3740cbf67842SDouglas Gilbert 	if (SCpnt) {
3741a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3742a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3743a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3744a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3745a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3746cbf67842SDouglas Gilbert 	}
37471da177e4SLinus Torvalds 	return SUCCESS;
37481da177e4SLinus Torvalds }
37491da177e4SLinus Torvalds 
37501da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
37511da177e4SLinus Torvalds {
37521da177e4SLinus Torvalds 	++num_dev_resets;
3753cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3754cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3755f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3756f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3757cbf67842SDouglas Gilbert 
3758773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3759cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
37601da177e4SLinus Torvalds 		if (devip)
3761cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
37621da177e4SLinus Torvalds 	}
37631da177e4SLinus Torvalds 	return SUCCESS;
37641da177e4SLinus Torvalds }
37651da177e4SLinus Torvalds 
3766cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3767cbf67842SDouglas Gilbert {
3768cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3769cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3770cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3771cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3772cbf67842SDouglas Gilbert 	int k = 0;
3773cbf67842SDouglas Gilbert 
3774cbf67842SDouglas Gilbert 	++num_target_resets;
3775cbf67842SDouglas Gilbert 	if (!SCpnt)
3776cbf67842SDouglas Gilbert 		goto lie;
3777cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3778cbf67842SDouglas Gilbert 	if (!sdp)
3779cbf67842SDouglas Gilbert 		goto lie;
3780773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3781cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3782cbf67842SDouglas Gilbert 	hp = sdp->host;
3783cbf67842SDouglas Gilbert 	if (!hp)
3784cbf67842SDouglas Gilbert 		goto lie;
3785cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3786cbf67842SDouglas Gilbert 	if (sdbg_host) {
3787cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3788cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3789cbf67842SDouglas Gilbert 				    dev_list)
3790cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3791cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3792cbf67842SDouglas Gilbert 				++k;
3793cbf67842SDouglas Gilbert 			}
3794cbf67842SDouglas Gilbert 	}
3795773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3796cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3797cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3798cbf67842SDouglas Gilbert lie:
3799cbf67842SDouglas Gilbert 	return SUCCESS;
3800cbf67842SDouglas Gilbert }
3801cbf67842SDouglas Gilbert 
38021da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
38031da177e4SLinus Torvalds {
38041da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3805cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38061da177e4SLinus Torvalds         struct scsi_device * sdp;
38071da177e4SLinus Torvalds         struct Scsi_Host * hp;
3808cbf67842SDouglas Gilbert 	int k = 0;
38091da177e4SLinus Torvalds 
38101da177e4SLinus Torvalds 	++num_bus_resets;
3811cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3812cbf67842SDouglas Gilbert 		goto lie;
3813cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3814773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3815cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3816cbf67842SDouglas Gilbert 	hp = sdp->host;
3817cbf67842SDouglas Gilbert 	if (hp) {
3818d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
38191da177e4SLinus Torvalds 		if (sdbg_host) {
3820cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
38211da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3822cbf67842SDouglas Gilbert 					    dev_list) {
3823cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3824cbf67842SDouglas Gilbert 				++k;
38251da177e4SLinus Torvalds 			}
38261da177e4SLinus Torvalds 		}
3827cbf67842SDouglas Gilbert 	}
3828773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3829cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3830cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3831cbf67842SDouglas Gilbert lie:
38321da177e4SLinus Torvalds 	return SUCCESS;
38331da177e4SLinus Torvalds }
38341da177e4SLinus Torvalds 
38351da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
38361da177e4SLinus Torvalds {
38371da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3838cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3839cbf67842SDouglas Gilbert 	int k = 0;
38401da177e4SLinus Torvalds 
38411da177e4SLinus Torvalds 	++num_host_resets;
3842773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3843cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
38441da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
38451da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3846cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3847cbf67842SDouglas Gilbert 				    dev_list) {
3848cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3849cbf67842SDouglas Gilbert 			++k;
3850cbf67842SDouglas Gilbert 		}
38511da177e4SLinus Torvalds         }
38521da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
38531da177e4SLinus Torvalds 	stop_all_queued();
3854773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3855cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3856cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
38571da177e4SLinus Torvalds 	return SUCCESS;
38581da177e4SLinus Torvalds }
38591da177e4SLinus Torvalds 
3860f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
38615f2578e5SFUJITA Tomonori 				      unsigned long store_size)
38621da177e4SLinus Torvalds {
38631da177e4SLinus Torvalds 	struct partition * pp;
38641da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
38651da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
38661da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
38671da177e4SLinus Torvalds 
38681da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3869773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
38701da177e4SLinus Torvalds 		return;
3871773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3872773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3873c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
38741da177e4SLinus Torvalds 	}
3875c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
38761da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3877773642d9SDouglas Gilbert 			   / sdebug_num_parts;
38781da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
38791da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3880773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
38811da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
38821da177e4SLinus Torvalds 			    * heads_by_sects;
3883773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3884773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
38851da177e4SLinus Torvalds 
38861da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
38871da177e4SLinus Torvalds 	ramp[511] = 0xAA;
38881da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
38891da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
38901da177e4SLinus Torvalds 		start_sec = starts[k];
38911da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
38921da177e4SLinus Torvalds 		pp->boot_ind = 0;
38931da177e4SLinus Torvalds 
38941da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
38951da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
38961da177e4SLinus Torvalds 			   / sdebug_sectors_per;
38971da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
38981da177e4SLinus Torvalds 
38991da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
39001da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
39011da177e4SLinus Torvalds 			       / sdebug_sectors_per;
39021da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
39031da177e4SLinus Torvalds 
3904150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3905150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
39061da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
39071da177e4SLinus Torvalds 	}
39081da177e4SLinus Torvalds }
39091da177e4SLinus Torvalds 
3910c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
3911c4837394SDouglas Gilbert {
3912c4837394SDouglas Gilbert 	int j;
3913c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3914c4837394SDouglas Gilbert 
3915c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
3916c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
3917c4837394SDouglas Gilbert }
3918c4837394SDouglas Gilbert 
3919c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
3920c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
3921c4837394SDouglas Gilbert  */
3922c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
3923c4837394SDouglas Gilbert {
3924c4837394SDouglas Gilbert 	int count, modulo;
3925c4837394SDouglas Gilbert 
3926c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
3927c4837394SDouglas Gilbert 	if (modulo < 2)
3928c4837394SDouglas Gilbert 		return;
3929c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
3930c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
3931c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
3932c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
3933c4837394SDouglas Gilbert }
3934c4837394SDouglas Gilbert 
3935c4837394SDouglas Gilbert static void clear_queue_stats(void)
3936c4837394SDouglas Gilbert {
3937c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
3938c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
3939c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
3940c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
3941c4837394SDouglas Gilbert }
3942c4837394SDouglas Gilbert 
3943c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
3944c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
3945c4837394SDouglas Gilbert {
3946c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
3947c4837394SDouglas Gilbert 		return;
3948c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
3949c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
3950c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
3951c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
3952c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
3953c4837394SDouglas Gilbert }
3954c4837394SDouglas Gilbert 
3955c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
3956c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
3957c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
3958c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
3959c4837394SDouglas Gilbert  */
3960fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3961cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
39621da177e4SLinus Torvalds {
3963cbf67842SDouglas Gilbert 	unsigned long iflags;
3964cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3965c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3966c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3967299b6c07STomas Winkler 	struct scsi_device *sdp;
3968a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39691da177e4SLinus Torvalds 
3970b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
3971b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
3972f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
3973f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
39741da177e4SLinus Torvalds 	}
3975299b6c07STomas Winkler 	sdp = cmnd->device;
3976299b6c07STomas Winkler 
3977f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
3978cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3979cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3980cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3981cd62b7daSDouglas Gilbert 		goto respond_in_thread;
39821da177e4SLinus Torvalds 
3983cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
3984c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
3985c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3986c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
3987c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3988c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3989c4837394SDouglas Gilbert 	}
3990cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3991cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3992cbf67842SDouglas Gilbert 	inject = 0;
3993f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
3994cd62b7daSDouglas Gilbert 		if (scsi_result) {
3995c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3996cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3997cd62b7daSDouglas Gilbert 		} else
3998cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3999c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4000773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4001f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4002cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4003cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4004773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4005cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4006cbf67842SDouglas Gilbert 			inject = 1;
4007cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
40081da177e4SLinus Torvalds 		}
4009cbf67842SDouglas Gilbert 	}
4010cbf67842SDouglas Gilbert 
4011c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4012f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4013c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4014cd62b7daSDouglas Gilbert 		if (scsi_result)
4015cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4016773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4017cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4018773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4019cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4020cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4021773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4022cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4023cbf67842SDouglas Gilbert 						    "report: host busy"));
4024cd62b7daSDouglas Gilbert 		if (scsi_result)
4025cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4026cd62b7daSDouglas Gilbert 		else
4027cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
40281da177e4SLinus Torvalds 	}
4029c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4030cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4031c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
40321da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4033c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4034cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4035a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4036c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4037c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4038c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
4039b01f6f83SDouglas Gilbert 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
4040b333a819SDouglas Gilbert 		ktime_t kt;
4041cbf67842SDouglas Gilbert 
4042b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
4043b333a819SDouglas Gilbert 			struct timespec ts;
4044b333a819SDouglas Gilbert 
4045b333a819SDouglas Gilbert 			jiffies_to_timespec(delta_jiff, &ts);
4046b333a819SDouglas Gilbert 			kt = ktime_set(ts.tv_sec, ts.tv_nsec);
4047b333a819SDouglas Gilbert 		} else
4048b333a819SDouglas Gilbert 			kt = ktime_set(0, sdebug_ndelay);
4049a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4050a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4051a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4052cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4053a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4054a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4055c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4056a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4057c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4058c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4059cbf67842SDouglas Gilbert 		}
4060c4837394SDouglas Gilbert 		if (sdebug_statistics)
4061c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4062c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4063c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
4064a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4065a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4066a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4067cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4068a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4069c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4070c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4071a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4072cbf67842SDouglas Gilbert 		}
4073c4837394SDouglas Gilbert 		if (sdebug_statistics)
4074c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4075a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4076cbf67842SDouglas Gilbert 	}
4077f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4078f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4079cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4080cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4081cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4082cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
40831da177e4SLinus Torvalds 	return 0;
4084cd62b7daSDouglas Gilbert 
4085cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4086cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4087cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4088cd62b7daSDouglas Gilbert 	return 0;
40891da177e4SLinus Torvalds }
4090cbf67842SDouglas Gilbert 
409123183910SDouglas Gilbert /* Note: The following macros create attribute files in the
409223183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
409323183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
409423183910SDouglas Gilbert    as it can when the corresponding attribute in the
409523183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
409623183910SDouglas Gilbert  */
4097773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4098773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
4099773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4100c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4101773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4102773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4103773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4104773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4105773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4106773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4107773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4108773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4109773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4110773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4111773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4112773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4113773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4114773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4115773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4116773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4117773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4118773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4119773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4120773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4121773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4122773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4123773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4124773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4125773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4126773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4127773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4128c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4129773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4130c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4131773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4132773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4133773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4134773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4135773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
413609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4137773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
413823183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4139773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
41405b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
41411da177e4SLinus Torvalds 
41421da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
41431da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
41441da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4145b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
41461da177e4SLinus Torvalds 
41471da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
41485b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
41490759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4150cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4151c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
41525b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
41535b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4154c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4155beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
415623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
41575b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4158185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
41595b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
41605b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
41615b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4162760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4163760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
41645b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4165c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4166cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4167cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4168c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
416978d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
41701da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4171c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
417232c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
41736f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
41745b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
41751da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4176d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4177760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4178ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4179c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4180c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4181c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
41825b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
41835b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
41846014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
41856014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
418609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
418709ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4188c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
41895b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
41905b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
41911da177e4SLinus Torvalds 
4192760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4193760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
41941da177e4SLinus Torvalds 
41951da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
41961da177e4SLinus Torvalds {
4197c4837394SDouglas Gilbert 	int k;
4198c4837394SDouglas Gilbert 
4199760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4200760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4201760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4202c4837394SDouglas Gilbert 		return sdebug_info;
4203760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4204760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4205760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4206760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
42071da177e4SLinus Torvalds 	return sdebug_info;
42081da177e4SLinus Torvalds }
42091da177e4SLinus Torvalds 
4210cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4211fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4212fd32119bSDouglas Gilbert 				 int length)
42131da177e4SLinus Torvalds {
42141da177e4SLinus Torvalds 	char arr[16];
4215c8ed555aSAl Viro 	int opts;
42161da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
42171da177e4SLinus Torvalds 
42181da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
42191da177e4SLinus Torvalds 		return -EACCES;
42201da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
42211da177e4SLinus Torvalds 	arr[minLen] = '\0';
4222c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
42231da177e4SLinus Torvalds 		return -EINVAL;
4224773642d9SDouglas Gilbert 	sdebug_opts = opts;
4225773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4226773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4227773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4228c4837394SDouglas Gilbert 		tweak_cmnd_count();
42291da177e4SLinus Torvalds 	return length;
42301da177e4SLinus Torvalds }
4231c8ed555aSAl Viro 
4232cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4233cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4234cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4235c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4236c8ed555aSAl Viro {
4237c4837394SDouglas Gilbert 	int f, j, l;
4238c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4239cbf67842SDouglas Gilbert 
4240c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4241c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4242c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4243c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4244c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4245c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4246c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4247c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4248c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4249c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4250c4837394SDouglas Gilbert 		   num_aborts);
4251c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4252c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4253c4837394SDouglas Gilbert 		   num_host_resets);
4254c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4255c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4256c4837394SDouglas Gilbert 	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4257c4837394SDouglas Gilbert 		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
4258c4837394SDouglas Gilbert 		   sdebug_mq_active);
4259c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4260c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4261c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4262c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4263c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4264cbf67842SDouglas Gilbert 
4265c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4266c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4267c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4268c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4269773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4270c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4271c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4272c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4273c4837394SDouglas Gilbert 		}
4274cbf67842SDouglas Gilbert 	}
4275c8ed555aSAl Viro 	return 0;
42761da177e4SLinus Torvalds }
42771da177e4SLinus Torvalds 
427882069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
42791da177e4SLinus Torvalds {
4280c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
42811da177e4SLinus Torvalds }
4282c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4283c4837394SDouglas Gilbert  * of delay is jiffies.
4284c4837394SDouglas Gilbert  */
428582069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
428682069379SAkinobu Mita 			   size_t count)
42871da177e4SLinus Torvalds {
4288c2206098SDouglas Gilbert 	int jdelay, res;
42891da177e4SLinus Torvalds 
4290b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4291cbf67842SDouglas Gilbert 		res = count;
4292c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4293c4837394SDouglas Gilbert 			int j, k;
4294c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4295cbf67842SDouglas Gilbert 
4296c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4297c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4298c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4299c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4300c4837394SDouglas Gilbert 						   sdebug_max_queue);
4301c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4302c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4303c4837394SDouglas Gilbert 					break;
4304c4837394SDouglas Gilbert 				}
4305c4837394SDouglas Gilbert 			}
4306c4837394SDouglas Gilbert 			if (res > 0) {
4307a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4308a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4309a10bc12aSDouglas Gilbert 				free_all_queued();
4310c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4311773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
43121da177e4SLinus Torvalds 			}
4313c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4314cbf67842SDouglas Gilbert 		}
4315cbf67842SDouglas Gilbert 		return res;
43161da177e4SLinus Torvalds 	}
43171da177e4SLinus Torvalds 	return -EINVAL;
43181da177e4SLinus Torvalds }
431982069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
43201da177e4SLinus Torvalds 
4321cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4322cbf67842SDouglas Gilbert {
4323773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4324cbf67842SDouglas Gilbert }
4325cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4326c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4327cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4328cbf67842SDouglas Gilbert 			    size_t count)
4329cbf67842SDouglas Gilbert {
4330c4837394SDouglas Gilbert 	int ndelay, res;
4331cbf67842SDouglas Gilbert 
4332cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4333c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4334cbf67842SDouglas Gilbert 		res = count;
4335773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4336c4837394SDouglas Gilbert 			int j, k;
4337c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4338c4837394SDouglas Gilbert 
4339c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4340c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4341c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4342c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4343c4837394SDouglas Gilbert 						   sdebug_max_queue);
4344c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4345c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4346c4837394SDouglas Gilbert 					break;
4347c4837394SDouglas Gilbert 				}
4348c4837394SDouglas Gilbert 			}
4349c4837394SDouglas Gilbert 			if (res > 0) {
4350a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4351a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4352a10bc12aSDouglas Gilbert 				free_all_queued();
4353773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4354c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4355c2206098SDouglas Gilbert 							: DEF_JDELAY;
4356cbf67842SDouglas Gilbert 			}
4357c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4358cbf67842SDouglas Gilbert 		}
4359cbf67842SDouglas Gilbert 		return res;
4360cbf67842SDouglas Gilbert 	}
4361cbf67842SDouglas Gilbert 	return -EINVAL;
4362cbf67842SDouglas Gilbert }
4363cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4364cbf67842SDouglas Gilbert 
436582069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
43661da177e4SLinus Torvalds {
4367773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
43681da177e4SLinus Torvalds }
43691da177e4SLinus Torvalds 
437082069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
437182069379SAkinobu Mita 			  size_t count)
43721da177e4SLinus Torvalds {
43731da177e4SLinus Torvalds         int opts;
43741da177e4SLinus Torvalds 	char work[20];
43751da177e4SLinus Torvalds 
43761da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
437748a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
43781da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
43791da177e4SLinus Torvalds 				goto opts_done;
43801da177e4SLinus Torvalds 		} else {
43811da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
43821da177e4SLinus Torvalds 				goto opts_done;
43831da177e4SLinus Torvalds 		}
43841da177e4SLinus Torvalds 	}
43851da177e4SLinus Torvalds 	return -EINVAL;
43861da177e4SLinus Torvalds opts_done:
4387773642d9SDouglas Gilbert 	sdebug_opts = opts;
4388773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4389773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4390c4837394SDouglas Gilbert 	tweak_cmnd_count();
43911da177e4SLinus Torvalds 	return count;
43921da177e4SLinus Torvalds }
439382069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
43941da177e4SLinus Torvalds 
439582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
43961da177e4SLinus Torvalds {
4397773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
43981da177e4SLinus Torvalds }
439982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
440082069379SAkinobu Mita 			   size_t count)
44011da177e4SLinus Torvalds {
44021da177e4SLinus Torvalds         int n;
44031da177e4SLinus Torvalds 
44041da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4405773642d9SDouglas Gilbert 		sdebug_ptype = n;
44061da177e4SLinus Torvalds 		return count;
44071da177e4SLinus Torvalds 	}
44081da177e4SLinus Torvalds 	return -EINVAL;
44091da177e4SLinus Torvalds }
441082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
44111da177e4SLinus Torvalds 
441282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
44131da177e4SLinus Torvalds {
4414773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
44151da177e4SLinus Torvalds }
441682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
441782069379SAkinobu Mita 			    size_t count)
44181da177e4SLinus Torvalds {
44191da177e4SLinus Torvalds         int n;
44201da177e4SLinus Torvalds 
44211da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4422773642d9SDouglas Gilbert 		sdebug_dsense = n;
44231da177e4SLinus Torvalds 		return count;
44241da177e4SLinus Torvalds 	}
44251da177e4SLinus Torvalds 	return -EINVAL;
44261da177e4SLinus Torvalds }
442782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
44281da177e4SLinus Torvalds 
442982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
443023183910SDouglas Gilbert {
4431773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
443223183910SDouglas Gilbert }
443382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
443482069379SAkinobu Mita 			     size_t count)
443523183910SDouglas Gilbert {
443623183910SDouglas Gilbert         int n;
443723183910SDouglas Gilbert 
443823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4439cbf67842SDouglas Gilbert 		n = (n > 0);
4440773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4441773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4442cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4443cbf67842SDouglas Gilbert 				unsigned long sz =
4444773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4445cbf67842SDouglas Gilbert 					1048576;
4446cbf67842SDouglas Gilbert 
4447cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4448cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4449c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4450cbf67842SDouglas Gilbert 					return -ENOMEM;
4451cbf67842SDouglas Gilbert 				}
4452cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4453cbf67842SDouglas Gilbert 			}
4454773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4455cbf67842SDouglas Gilbert 		}
445623183910SDouglas Gilbert 		return count;
445723183910SDouglas Gilbert 	}
445823183910SDouglas Gilbert 	return -EINVAL;
445923183910SDouglas Gilbert }
446082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
446123183910SDouglas Gilbert 
446282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4463c65b1445SDouglas Gilbert {
4464773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4465c65b1445SDouglas Gilbert }
446682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
446782069379SAkinobu Mita 			      size_t count)
4468c65b1445SDouglas Gilbert {
4469c65b1445SDouglas Gilbert         int n;
4470c65b1445SDouglas Gilbert 
4471c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4472773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4473c65b1445SDouglas Gilbert 		return count;
4474c65b1445SDouglas Gilbert 	}
4475c65b1445SDouglas Gilbert 	return -EINVAL;
4476c65b1445SDouglas Gilbert }
447782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4478c65b1445SDouglas Gilbert 
447982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
44801da177e4SLinus Torvalds {
4481773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
44821da177e4SLinus Torvalds }
448382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
448482069379SAkinobu Mita 			      size_t count)
44851da177e4SLinus Torvalds {
44861da177e4SLinus Torvalds         int n;
44871da177e4SLinus Torvalds 
44881da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4489773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
44901da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
44911da177e4SLinus Torvalds 		return count;
44921da177e4SLinus Torvalds 	}
44931da177e4SLinus Torvalds 	return -EINVAL;
44941da177e4SLinus Torvalds }
449582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
44961da177e4SLinus Torvalds 
449782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
44981da177e4SLinus Torvalds {
4499773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
45001da177e4SLinus Torvalds }
450182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
45021da177e4SLinus Torvalds 
450382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
45041da177e4SLinus Torvalds {
4505773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
45061da177e4SLinus Torvalds }
450782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
45081da177e4SLinus Torvalds 
450982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
45101da177e4SLinus Torvalds {
4511773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
45121da177e4SLinus Torvalds }
451382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
451482069379SAkinobu Mita 			       size_t count)
45151da177e4SLinus Torvalds {
45161da177e4SLinus Torvalds         int nth;
45171da177e4SLinus Torvalds 
45181da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4519773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4520c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4521c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4522c4837394SDouglas Gilbert 			sdebug_statistics = true;
4523c4837394SDouglas Gilbert 		}
4524c4837394SDouglas Gilbert 		tweak_cmnd_count();
45251da177e4SLinus Torvalds 		return count;
45261da177e4SLinus Torvalds 	}
45271da177e4SLinus Torvalds 	return -EINVAL;
45281da177e4SLinus Torvalds }
452982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
45301da177e4SLinus Torvalds 
453182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
45321da177e4SLinus Torvalds {
4533773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
45341da177e4SLinus Torvalds }
453582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
453682069379SAkinobu Mita 			      size_t count)
45371da177e4SLinus Torvalds {
45381da177e4SLinus Torvalds         int n;
453919c8ead7SEwan D. Milne 	bool changed;
45401da177e4SLinus Torvalds 
45411da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
45428d039e22SDouglas Gilbert 		if (n > 256) {
45438d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
45448d039e22SDouglas Gilbert 			return -EINVAL;
45458d039e22SDouglas Gilbert 		}
4546773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4547773642d9SDouglas Gilbert 		sdebug_max_luns = n;
45481da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4549773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
455019c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
455119c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
455219c8ead7SEwan D. Milne 
455319c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
455419c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
455519c8ead7SEwan D. Milne 					    host_list) {
455619c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
455719c8ead7SEwan D. Milne 						    dev_list) {
455819c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
455919c8ead7SEwan D. Milne 						dp->uas_bm);
456019c8ead7SEwan D. Milne 				}
456119c8ead7SEwan D. Milne 			}
456219c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
456319c8ead7SEwan D. Milne 		}
45641da177e4SLinus Torvalds 		return count;
45651da177e4SLinus Torvalds 	}
45661da177e4SLinus Torvalds 	return -EINVAL;
45671da177e4SLinus Torvalds }
456882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
45691da177e4SLinus Torvalds 
457082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
457178d4e5a0SDouglas Gilbert {
4572773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
457378d4e5a0SDouglas Gilbert }
4574cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4575cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
457682069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
457782069379SAkinobu Mita 			       size_t count)
457878d4e5a0SDouglas Gilbert {
4579c4837394SDouglas Gilbert 	int j, n, k, a;
4580c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
458178d4e5a0SDouglas Gilbert 
458278d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4583c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4584c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4585c4837394SDouglas Gilbert 		k = 0;
4586c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4587c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4588c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4589c4837394SDouglas Gilbert 			if (a > k)
4590c4837394SDouglas Gilbert 				k = a;
4591c4837394SDouglas Gilbert 		}
4592773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4593c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4594cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4595cbf67842SDouglas Gilbert 		else if (k >= n)
4596cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4597cbf67842SDouglas Gilbert 		else
4598cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4599c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
460078d4e5a0SDouglas Gilbert 		return count;
460178d4e5a0SDouglas Gilbert 	}
460278d4e5a0SDouglas Gilbert 	return -EINVAL;
460378d4e5a0SDouglas Gilbert }
460482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
460578d4e5a0SDouglas Gilbert 
460682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
460778d4e5a0SDouglas Gilbert {
4608773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
460978d4e5a0SDouglas Gilbert }
461082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
461178d4e5a0SDouglas Gilbert 
461282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
46131da177e4SLinus Torvalds {
4614773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
46151da177e4SLinus Torvalds }
461682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
46171da177e4SLinus Torvalds 
461882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4619c65b1445SDouglas Gilbert {
4620773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4621c65b1445SDouglas Gilbert }
462282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
462382069379SAkinobu Mita 				size_t count)
4624c65b1445SDouglas Gilbert {
4625c65b1445SDouglas Gilbert         int n;
46260d01c5dfSDouglas Gilbert 	bool changed;
4627c65b1445SDouglas Gilbert 
4628c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4629773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4630773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
463128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
46320d01c5dfSDouglas Gilbert 		if (changed) {
46330d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
46340d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
463528898873SFUJITA Tomonori 
46364bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
46370d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
46380d01c5dfSDouglas Gilbert 					    host_list) {
46390d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
46400d01c5dfSDouglas Gilbert 						    dev_list) {
46410d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
46420d01c5dfSDouglas Gilbert 						dp->uas_bm);
46430d01c5dfSDouglas Gilbert 				}
46440d01c5dfSDouglas Gilbert 			}
46454bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
46460d01c5dfSDouglas Gilbert 		}
4647c65b1445SDouglas Gilbert 		return count;
4648c65b1445SDouglas Gilbert 	}
4649c65b1445SDouglas Gilbert 	return -EINVAL;
4650c65b1445SDouglas Gilbert }
465182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4652c65b1445SDouglas Gilbert 
465382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
46541da177e4SLinus Torvalds {
4655773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
46561da177e4SLinus Torvalds }
46571da177e4SLinus Torvalds 
4658fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4659fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4660fd32119bSDouglas Gilbert 
466182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
466282069379SAkinobu Mita 			      size_t count)
46631da177e4SLinus Torvalds {
46641da177e4SLinus Torvalds 	int delta_hosts;
46651da177e4SLinus Torvalds 
4666f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
46671da177e4SLinus Torvalds 		return -EINVAL;
46681da177e4SLinus Torvalds 	if (delta_hosts > 0) {
46691da177e4SLinus Torvalds 		do {
46701da177e4SLinus Torvalds 			sdebug_add_adapter();
46711da177e4SLinus Torvalds 		} while (--delta_hosts);
46721da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
46731da177e4SLinus Torvalds 		do {
46741da177e4SLinus Torvalds 			sdebug_remove_adapter();
46751da177e4SLinus Torvalds 		} while (++delta_hosts);
46761da177e4SLinus Torvalds 	}
46771da177e4SLinus Torvalds 	return count;
46781da177e4SLinus Torvalds }
467982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
46801da177e4SLinus Torvalds 
468182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
468223183910SDouglas Gilbert {
4683773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
468423183910SDouglas Gilbert }
468582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
468682069379SAkinobu Mita 				    size_t count)
468723183910SDouglas Gilbert {
468823183910SDouglas Gilbert 	int n;
468923183910SDouglas Gilbert 
469023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4691773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
469223183910SDouglas Gilbert 		return count;
469323183910SDouglas Gilbert 	}
469423183910SDouglas Gilbert 	return -EINVAL;
469523183910SDouglas Gilbert }
469682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
469723183910SDouglas Gilbert 
4698c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4699c4837394SDouglas Gilbert {
4700c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4701c4837394SDouglas Gilbert }
4702c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4703c4837394SDouglas Gilbert 				size_t count)
4704c4837394SDouglas Gilbert {
4705c4837394SDouglas Gilbert 	int n;
4706c4837394SDouglas Gilbert 
4707c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4708c4837394SDouglas Gilbert 		if (n > 0)
4709c4837394SDouglas Gilbert 			sdebug_statistics = true;
4710c4837394SDouglas Gilbert 		else {
4711c4837394SDouglas Gilbert 			clear_queue_stats();
4712c4837394SDouglas Gilbert 			sdebug_statistics = false;
4713c4837394SDouglas Gilbert 		}
4714c4837394SDouglas Gilbert 		return count;
4715c4837394SDouglas Gilbert 	}
4716c4837394SDouglas Gilbert 	return -EINVAL;
4717c4837394SDouglas Gilbert }
4718c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
4719c4837394SDouglas Gilbert 
472082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4721597136abSMartin K. Petersen {
4722773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4723597136abSMartin K. Petersen }
472482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4725597136abSMartin K. Petersen 
4726c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4727c4837394SDouglas Gilbert {
4728c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4729c4837394SDouglas Gilbert }
4730c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
4731c4837394SDouglas Gilbert 
473282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4733c6a44287SMartin K. Petersen {
4734773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4735c6a44287SMartin K. Petersen }
473682069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4737c6a44287SMartin K. Petersen 
473882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4739c6a44287SMartin K. Petersen {
4740773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4741c6a44287SMartin K. Petersen }
474282069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4743c6a44287SMartin K. Petersen 
474482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4745c6a44287SMartin K. Petersen {
4746773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4747c6a44287SMartin K. Petersen }
474882069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4749c6a44287SMartin K. Petersen 
475082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4751c6a44287SMartin K. Petersen {
4752773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4753c6a44287SMartin K. Petersen }
475482069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4755c6a44287SMartin K. Petersen 
475682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
475744d92694SMartin K. Petersen {
475844d92694SMartin K. Petersen 	ssize_t count;
475944d92694SMartin K. Petersen 
47605b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
476144d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
476244d92694SMartin K. Petersen 				 sdebug_store_sectors);
476344d92694SMartin K. Petersen 
4764c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4765c7badc90STejun Heo 			  (int)map_size, map_storep);
476644d92694SMartin K. Petersen 	buf[count++] = '\n';
4767c7badc90STejun Heo 	buf[count] = '\0';
476844d92694SMartin K. Petersen 
476944d92694SMartin K. Petersen 	return count;
477044d92694SMartin K. Petersen }
477182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
477244d92694SMartin K. Petersen 
477382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4774d986788bSMartin Pitt {
4775773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4776d986788bSMartin Pitt }
477782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
477882069379SAkinobu Mita 			       size_t count)
4779d986788bSMartin Pitt {
4780d986788bSMartin Pitt 	int n;
4781d986788bSMartin Pitt 
4782d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4783773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4784d986788bSMartin Pitt 		return count;
4785d986788bSMartin Pitt 	}
4786d986788bSMartin Pitt 	return -EINVAL;
4787d986788bSMartin Pitt }
478882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4789d986788bSMartin Pitt 
4790cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4791cbf67842SDouglas Gilbert {
4792773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4793cbf67842SDouglas Gilbert }
4794185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4795cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4796cbf67842SDouglas Gilbert 			       size_t count)
4797cbf67842SDouglas Gilbert {
4798185dd232SDouglas Gilbert 	int n;
4799cbf67842SDouglas Gilbert 
4800cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4801185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4802185dd232SDouglas Gilbert 		return count;
4803cbf67842SDouglas Gilbert 	}
4804cbf67842SDouglas Gilbert 	return -EINVAL;
4805cbf67842SDouglas Gilbert }
4806cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4807cbf67842SDouglas Gilbert 
4808c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4809c2248fc9SDouglas Gilbert {
4810773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4811c2248fc9SDouglas Gilbert }
4812c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4813c2248fc9SDouglas Gilbert 			    size_t count)
4814c2248fc9SDouglas Gilbert {
4815c2248fc9SDouglas Gilbert 	int n;
4816c2248fc9SDouglas Gilbert 
4817c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4818773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4819c2248fc9SDouglas Gilbert 		return count;
4820c2248fc9SDouglas Gilbert 	}
4821c2248fc9SDouglas Gilbert 	return -EINVAL;
4822c2248fc9SDouglas Gilbert }
4823c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4824c2248fc9SDouglas Gilbert 
482509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
482609ba24c1SDouglas Gilbert {
482709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
482809ba24c1SDouglas Gilbert }
482909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
483009ba24c1SDouglas Gilbert 
4831cbf67842SDouglas Gilbert 
483282069379SAkinobu Mita /* Note: The following array creates attribute files in the
483323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
483423183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
483523183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
483623183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
483723183910SDouglas Gilbert  */
48386ecaff7fSRandy Dunlap 
483982069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
484082069379SAkinobu Mita 	&driver_attr_delay.attr,
484182069379SAkinobu Mita 	&driver_attr_opts.attr,
484282069379SAkinobu Mita 	&driver_attr_ptype.attr,
484382069379SAkinobu Mita 	&driver_attr_dsense.attr,
484482069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
484582069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
484682069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
484782069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
484882069379SAkinobu Mita 	&driver_attr_num_parts.attr,
484982069379SAkinobu Mita 	&driver_attr_every_nth.attr,
485082069379SAkinobu Mita 	&driver_attr_max_luns.attr,
485182069379SAkinobu Mita 	&driver_attr_max_queue.attr,
485282069379SAkinobu Mita 	&driver_attr_no_uld.attr,
485382069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
485482069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
485582069379SAkinobu Mita 	&driver_attr_add_host.attr,
485682069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
485782069379SAkinobu Mita 	&driver_attr_sector_size.attr,
4858c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
4859c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
486082069379SAkinobu Mita 	&driver_attr_dix.attr,
486182069379SAkinobu Mita 	&driver_attr_dif.attr,
486282069379SAkinobu Mita 	&driver_attr_guard.attr,
486382069379SAkinobu Mita 	&driver_attr_ato.attr,
486482069379SAkinobu Mita 	&driver_attr_map.attr,
486582069379SAkinobu Mita 	&driver_attr_removable.attr,
4866cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4867cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4868c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
486909ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
487082069379SAkinobu Mita 	NULL,
487182069379SAkinobu Mita };
487282069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
48731da177e4SLinus Torvalds 
487411ddcecaSAkinobu Mita static struct device *pseudo_primary;
48758dea0d02SFUJITA Tomonori 
48761da177e4SLinus Torvalds static int __init scsi_debug_init(void)
48771da177e4SLinus Torvalds {
48785f2578e5SFUJITA Tomonori 	unsigned long sz;
48791da177e4SLinus Torvalds 	int host_to_add;
48801da177e4SLinus Torvalds 	int k;
48816ecaff7fSRandy Dunlap 	int ret;
48821da177e4SLinus Torvalds 
4883cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4884cbf67842SDouglas Gilbert 
4885773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
4886c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4887773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
4888773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
4889c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
4890cbf67842SDouglas Gilbert 
4891773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
4892597136abSMartin K. Petersen 	case  512:
4893597136abSMartin K. Petersen 	case 1024:
4894597136abSMartin K. Petersen 	case 2048:
4895597136abSMartin K. Petersen 	case 4096:
4896597136abSMartin K. Petersen 		break;
4897597136abSMartin K. Petersen 	default:
4898773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
4899597136abSMartin K. Petersen 		return -EINVAL;
4900597136abSMartin K. Petersen 	}
4901597136abSMartin K. Petersen 
4902773642d9SDouglas Gilbert 	switch (sdebug_dif) {
4903c6a44287SMartin K. Petersen 
4904c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
4905f46eb0e9SDouglas Gilbert 		break;
4906c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4907395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4908c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4909f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
4910c6a44287SMartin K. Petersen 		break;
4911c6a44287SMartin K. Petersen 
4912c6a44287SMartin K. Petersen 	default:
4913c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4914c6a44287SMartin K. Petersen 		return -EINVAL;
4915c6a44287SMartin K. Petersen 	}
4916c6a44287SMartin K. Petersen 
4917773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
4918c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4919c6a44287SMartin K. Petersen 		return -EINVAL;
4920c6a44287SMartin K. Petersen 	}
4921c6a44287SMartin K. Petersen 
4922773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
4923c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4924c6a44287SMartin K. Petersen 		return -EINVAL;
4925c6a44287SMartin K. Petersen 	}
4926c6a44287SMartin K. Petersen 
4927773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
4928773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
4929ea61fca5SMartin K. Petersen 		return -EINVAL;
4930ea61fca5SMartin K. Petersen 	}
49318d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
49328d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
49338d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
49348d039e22SDouglas Gilbert 	}
4935ea61fca5SMartin K. Petersen 
4936773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
4937773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
4938ea61fca5SMartin K. Petersen 		return -EINVAL;
4939ea61fca5SMartin K. Petersen 	}
4940ea61fca5SMartin K. Petersen 
4941c4837394SDouglas Gilbert 	if (submit_queues < 1) {
4942c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
4943c4837394SDouglas Gilbert 		return -EINVAL;
4944c4837394SDouglas Gilbert 	}
4945c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
4946c4837394SDouglas Gilbert 			       GFP_KERNEL);
4947c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
4948c4837394SDouglas Gilbert 		return -ENOMEM;
4949c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
4950c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
4951c4837394SDouglas Gilbert 
4952773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
4953773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
4954773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4955773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
495628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
49571da177e4SLinus Torvalds 
49581da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
49591da177e4SLinus Torvalds 	sdebug_heads = 8;
49601da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
4961773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
49621da177e4SLinus Torvalds 		sdebug_heads = 64;
4963773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
4964fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
49651da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
49661da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
49671da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
49681da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
49691da177e4SLinus Torvalds 		sdebug_heads = 255;
49701da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
49711da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
49721da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
49731da177e4SLinus Torvalds 	}
49741da177e4SLinus Torvalds 
4975b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
49761da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
49771da177e4SLinus Torvalds 		if (NULL == fake_storep) {
4978c1287970STomas Winkler 			pr_err("out of memory, 1\n");
4979c4837394SDouglas Gilbert 			ret = -ENOMEM;
4980c4837394SDouglas Gilbert 			goto free_q_arr;
49811da177e4SLinus Torvalds 		}
49821da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
4983773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
4984f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
4985cbf67842SDouglas Gilbert 	}
49861da177e4SLinus Torvalds 
4987773642d9SDouglas Gilbert 	if (sdebug_dix) {
4988c6a44287SMartin K. Petersen 		int dif_size;
4989c6a44287SMartin K. Petersen 
4990c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4991c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
4992c6a44287SMartin K. Petersen 
4993c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
4994c6a44287SMartin K. Petersen 
4995c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
4996c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
4997c6a44287SMartin K. Petersen 			ret = -ENOMEM;
4998c6a44287SMartin K. Petersen 			goto free_vm;
4999c6a44287SMartin K. Petersen 		}
5000c6a44287SMartin K. Petersen 
5001c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5002c6a44287SMartin K. Petersen 	}
5003c6a44287SMartin K. Petersen 
50045b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
50055b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5006773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5007773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
50086014759cSMartin K. Petersen 
5009773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5010773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
50116014759cSMartin K. Petersen 
5012773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5013773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
50146014759cSMartin K. Petersen 
5015773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5016773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5017773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5018c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5019c4837394SDouglas Gilbert 			ret = -EINVAL;
5020c4837394SDouglas Gilbert 			goto free_vm;
502144d92694SMartin K. Petersen 		}
502244d92694SMartin K. Petersen 
5023b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5024b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
502544d92694SMartin K. Petersen 
5026c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
502744d92694SMartin K. Petersen 
502844d92694SMartin K. Petersen 		if (map_storep == NULL) {
5029c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
503044d92694SMartin K. Petersen 			ret = -ENOMEM;
503144d92694SMartin K. Petersen 			goto free_vm;
503244d92694SMartin K. Petersen 		}
503344d92694SMartin K. Petersen 
5034b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
503544d92694SMartin K. Petersen 
503644d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5037773642d9SDouglas Gilbert 		if (sdebug_num_parts)
503844d92694SMartin K. Petersen 			map_region(0, 2);
503944d92694SMartin K. Petersen 	}
504044d92694SMartin K. Petersen 
50419b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
50429b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5043c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
50449b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
50456ecaff7fSRandy Dunlap 		goto free_vm;
50466ecaff7fSRandy Dunlap 	}
50476ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
50486ecaff7fSRandy Dunlap 	if (ret < 0) {
5049c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
50506ecaff7fSRandy Dunlap 		goto dev_unreg;
50516ecaff7fSRandy Dunlap 	}
50526ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
50536ecaff7fSRandy Dunlap 	if (ret < 0) {
5054c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
50556ecaff7fSRandy Dunlap 		goto bus_unreg;
50566ecaff7fSRandy Dunlap 	}
50571da177e4SLinus Torvalds 
5058773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5059773642d9SDouglas Gilbert 	sdebug_add_host = 0;
50601da177e4SLinus Torvalds 
50611da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
50621da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
5063c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
50641da177e4SLinus Torvalds                         break;
50651da177e4SLinus Torvalds                 }
50661da177e4SLinus Torvalds         }
50671da177e4SLinus Torvalds 
5068773642d9SDouglas Gilbert 	if (sdebug_verbose)
5069773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5070c1287970STomas Winkler 
50711da177e4SLinus Torvalds 	return 0;
50726ecaff7fSRandy Dunlap 
50736ecaff7fSRandy Dunlap bus_unreg:
50746ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
50756ecaff7fSRandy Dunlap dev_unreg:
50769b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
50776ecaff7fSRandy Dunlap free_vm:
507844d92694SMartin K. Petersen 	vfree(map_storep);
5079c6a44287SMartin K. Petersen 	vfree(dif_storep);
50806ecaff7fSRandy Dunlap 	vfree(fake_storep);
5081c4837394SDouglas Gilbert free_q_arr:
5082c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
50836ecaff7fSRandy Dunlap 	return ret;
50841da177e4SLinus Torvalds }
50851da177e4SLinus Torvalds 
50861da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
50871da177e4SLinus Torvalds {
5088773642d9SDouglas Gilbert 	int k = sdebug_add_host;
50891da177e4SLinus Torvalds 
50901da177e4SLinus Torvalds 	stop_all_queued();
5091cbf67842SDouglas Gilbert 	free_all_queued();
50921da177e4SLinus Torvalds 	for (; k; k--)
50931da177e4SLinus Torvalds 		sdebug_remove_adapter();
50941da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
50951da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
50969b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
50971da177e4SLinus Torvalds 
5098c6a44287SMartin K. Petersen 	vfree(dif_storep);
50991da177e4SLinus Torvalds 	vfree(fake_storep);
5100c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
51011da177e4SLinus Torvalds }
51021da177e4SLinus Torvalds 
51031da177e4SLinus Torvalds device_initcall(scsi_debug_init);
51041da177e4SLinus Torvalds module_exit(scsi_debug_exit);
51051da177e4SLinus Torvalds 
51061da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
51071da177e4SLinus Torvalds {
51081da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51091da177e4SLinus Torvalds 
51101da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
51111da177e4SLinus Torvalds         kfree(sdbg_host);
51121da177e4SLinus Torvalds }
51131da177e4SLinus Torvalds 
51141da177e4SLinus Torvalds static int sdebug_add_adapter(void)
51151da177e4SLinus Torvalds {
51161da177e4SLinus Torvalds 	int k, devs_per_host;
51171da177e4SLinus Torvalds         int error = 0;
51181da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51198b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
51201da177e4SLinus Torvalds 
512124669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
51221da177e4SLinus Torvalds         if (NULL == sdbg_host) {
5123c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
51241da177e4SLinus Torvalds                 return -ENOMEM;
51251da177e4SLinus Torvalds         }
51261da177e4SLinus Torvalds 
51271da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
51281da177e4SLinus Torvalds 
5129773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
51301da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
51315cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
51325cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5133c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51341da177e4SLinus Torvalds                         error = -ENOMEM;
51351da177e4SLinus Torvalds 			goto clean;
51361da177e4SLinus Torvalds                 }
51371da177e4SLinus Torvalds         }
51381da177e4SLinus Torvalds 
51391da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
51401da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
51411da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
51421da177e4SLinus Torvalds 
51431da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
51449b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
51451da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
5146773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
51471da177e4SLinus Torvalds 
51481da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
51491da177e4SLinus Torvalds 
51501da177e4SLinus Torvalds         if (error)
51511da177e4SLinus Torvalds 		goto clean;
51521da177e4SLinus Torvalds 
5153773642d9SDouglas Gilbert 	++sdebug_add_host;
51541da177e4SLinus Torvalds         return error;
51551da177e4SLinus Torvalds 
51561da177e4SLinus Torvalds clean:
51578b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
51588b40228fSFUJITA Tomonori 				 dev_list) {
51591da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
51601da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
51611da177e4SLinus Torvalds 	}
51621da177e4SLinus Torvalds 
51631da177e4SLinus Torvalds 	kfree(sdbg_host);
51641da177e4SLinus Torvalds         return error;
51651da177e4SLinus Torvalds }
51661da177e4SLinus Torvalds 
51671da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
51681da177e4SLinus Torvalds {
51691da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
51701da177e4SLinus Torvalds 
51711da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
51721da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
51731da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
51741da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
51751da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
51761da177e4SLinus Torvalds 	}
51771da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
51781da177e4SLinus Torvalds 
51791da177e4SLinus Torvalds 	if (!sdbg_host)
51801da177e4SLinus Torvalds 		return;
51811da177e4SLinus Torvalds 
51821da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5183773642d9SDouglas Gilbert 	--sdebug_add_host;
51841da177e4SLinus Torvalds }
51851da177e4SLinus Torvalds 
5186fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5187cbf67842SDouglas Gilbert {
5188cbf67842SDouglas Gilbert 	int num_in_q = 0;
5189cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5190cbf67842SDouglas Gilbert 
5191c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5192cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5193cbf67842SDouglas Gilbert 	if (NULL == devip) {
5194c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5195cbf67842SDouglas Gilbert 		return	-ENODEV;
5196cbf67842SDouglas Gilbert 	}
5197cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5198c40ecc12SChristoph Hellwig 
5199cbf67842SDouglas Gilbert 	if (qdepth < 1)
5200cbf67842SDouglas Gilbert 		qdepth = 1;
5201c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5202c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5203c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5204db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5205cbf67842SDouglas Gilbert 
5206773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5207c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5208c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5209cbf67842SDouglas Gilbert 	}
5210c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5211cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5212cbf67842SDouglas Gilbert }
5213cbf67842SDouglas Gilbert 
5214c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5215817fd66bSDouglas Gilbert {
5216c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5217773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5218773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5219773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5220c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5221773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5222817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5223c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5224817fd66bSDouglas Gilbert 	}
5225c4837394SDouglas Gilbert 	return false;
5226817fd66bSDouglas Gilbert }
5227817fd66bSDouglas Gilbert 
5228fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5229fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5230c2248fc9SDouglas Gilbert {
5231c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5232c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5233c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5234c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5235c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5236c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5237c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5238c2248fc9SDouglas Gilbert 	int k, na;
5239c2248fc9SDouglas Gilbert 	int errsts = 0;
5240c2248fc9SDouglas Gilbert 	u32 flags;
5241c2248fc9SDouglas Gilbert 	u16 sa;
5242c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5243c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5244c2248fc9SDouglas Gilbert 
5245c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5246c4837394SDouglas Gilbert 	if (sdebug_statistics)
5247c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5248f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5249f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5250c2248fc9SDouglas Gilbert 		char b[120];
5251c2248fc9SDouglas Gilbert 		int n, len, sb;
5252c2248fc9SDouglas Gilbert 
5253c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5254c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5255c2248fc9SDouglas Gilbert 		if (len > 32)
5256c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5257c2248fc9SDouglas Gilbert 		else {
5258c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5259c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5260c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5261c2248fc9SDouglas Gilbert 		}
5262c4837394SDouglas Gilbert 		if (sdebug_mq_active)
5263c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5264c4837394SDouglas Gilbert 				    my_name, blk_mq_unique_tag(scp->request),
5265c4837394SDouglas Gilbert 				    b);
5266c4837394SDouglas Gilbert 		else
5267c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5268c4837394SDouglas Gilbert 				    b);
5269c2248fc9SDouglas Gilbert 	}
527034d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5271f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5272f46eb0e9SDouglas Gilbert 		goto err_out;
5273c2248fc9SDouglas Gilbert 
5274c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5275c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5276c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5277f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5278f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5279c2248fc9SDouglas Gilbert 		if (NULL == devip)
5280f46eb0e9SDouglas Gilbert 			goto err_out;
5281c2248fc9SDouglas Gilbert 	}
5282c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5283c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5284c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5285c2248fc9SDouglas Gilbert 		r_oip = oip;
5286c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5287c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5288c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5289c2248fc9SDouglas Gilbert 			else
5290c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5291c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5292c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5293c2248fc9SDouglas Gilbert 					break;
5294c2248fc9SDouglas Gilbert 			}
5295c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5296c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5297c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5298c2248fc9SDouglas Gilbert 					break;
5299c2248fc9SDouglas Gilbert 			}
5300c2248fc9SDouglas Gilbert 		}
5301c2248fc9SDouglas Gilbert 		if (k > na) {
5302c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5303c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5304c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5305c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5306c2248fc9SDouglas Gilbert 			else
5307c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5308c2248fc9SDouglas Gilbert 			goto check_cond;
5309c2248fc9SDouglas Gilbert 		}
5310c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5311c2248fc9SDouglas Gilbert 	flags = oip->flags;
5312f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5313c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5314c2248fc9SDouglas Gilbert 		goto check_cond;
5315c2248fc9SDouglas Gilbert 	}
5316f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5317773642d9SDouglas Gilbert 		if (sdebug_verbose)
5318773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5319773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5320c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5321c2248fc9SDouglas Gilbert 		goto check_cond;
5322c2248fc9SDouglas Gilbert 	}
5323f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5324c2248fc9SDouglas Gilbert 		u8 rem;
5325c2248fc9SDouglas Gilbert 		int j;
5326c2248fc9SDouglas Gilbert 
5327c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5328c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5329c2248fc9SDouglas Gilbert 			if (rem) {
5330c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5331c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5332c2248fc9SDouglas Gilbert 						break;
5333c2248fc9SDouglas Gilbert 				}
5334c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5335c2248fc9SDouglas Gilbert 				goto check_cond;
5336c2248fc9SDouglas Gilbert 			}
5337c2248fc9SDouglas Gilbert 		}
5338c2248fc9SDouglas Gilbert 	}
5339f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5340b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5341b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5342f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5343c2248fc9SDouglas Gilbert 		if (errsts)
5344c2248fc9SDouglas Gilbert 			goto check_cond;
5345c2248fc9SDouglas Gilbert 	}
5346c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5347c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5348773642d9SDouglas Gilbert 		if (sdebug_verbose)
5349c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5350c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5351c2248fc9SDouglas Gilbert 				    "required");
5352c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5353c2248fc9SDouglas Gilbert 		goto fini;
5354c2248fc9SDouglas Gilbert 	}
5355773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5356c2248fc9SDouglas Gilbert 		goto fini;
5357f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5358c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5359c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5360c2248fc9SDouglas Gilbert 	}
5361f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5362f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5363c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5364c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5365c2248fc9SDouglas Gilbert 
5366c2248fc9SDouglas Gilbert fini:
5367c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5368c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5369c2248fc9SDouglas Gilbert check_cond:
5370c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5371f46eb0e9SDouglas Gilbert err_out:
5372f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5373c2248fc9SDouglas Gilbert }
5374c2248fc9SDouglas Gilbert 
53759e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5376c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5377c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
53789e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
53799e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
53809e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
53819e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
53829e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
53839e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
53849e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5385185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5386cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
53879e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
53889e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5389cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5390cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
53919e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5392c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
53939e603ca0SFUJITA Tomonori 	.this_id =		7,
539465e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5395cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
53966bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
53979e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
53989e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5399c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
54009e603ca0SFUJITA Tomonori };
54019e603ca0SFUJITA Tomonori 
54021da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
54031da177e4SLinus Torvalds {
54041da177e4SLinus Torvalds 	int error = 0;
54051da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54061da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5407f46eb0e9SDouglas Gilbert 	int hprot;
54081da177e4SLinus Torvalds 
54091da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54101da177e4SLinus Torvalds 
5411773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5412773642d9SDouglas Gilbert 	if (sdebug_clustering)
54130759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
54141da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
54151da177e4SLinus Torvalds 	if (NULL == hpnt) {
5416c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
54171da177e4SLinus Torvalds 		error = -ENODEV;
54181da177e4SLinus Torvalds 		return error;
54191da177e4SLinus Torvalds 	}
5420c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
5421c4837394SDouglas Gilbert 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n",
5422c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5423c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5424c4837394SDouglas Gilbert 	}
5425c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5426c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5427c4837394SDouglas Gilbert 	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5428c4837394SDouglas Gilbert 	if (sdebug_mq_active)
5429c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
54301da177e4SLinus Torvalds 
54311da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
54321da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5433773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5434773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
54351da177e4SLinus Torvalds 	else
5436773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5437773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5438f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
54391da177e4SLinus Torvalds 
5440f46eb0e9SDouglas Gilbert 	hprot = 0;
5441c6a44287SMartin K. Petersen 
5442773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5443c6a44287SMartin K. Petersen 
5444c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
5445f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5446773642d9SDouglas Gilbert 		if (sdebug_dix)
5447f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5448c6a44287SMartin K. Petersen 		break;
5449c6a44287SMartin K. Petersen 
5450c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
5451f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5452773642d9SDouglas Gilbert 		if (sdebug_dix)
5453f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5454c6a44287SMartin K. Petersen 		break;
5455c6a44287SMartin K. Petersen 
5456c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
5457f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5458773642d9SDouglas Gilbert 		if (sdebug_dix)
5459f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5460c6a44287SMartin K. Petersen 		break;
5461c6a44287SMartin K. Petersen 
5462c6a44287SMartin K. Petersen 	default:
5463773642d9SDouglas Gilbert 		if (sdebug_dix)
5464f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5465c6a44287SMartin K. Petersen 		break;
5466c6a44287SMartin K. Petersen 	}
5467c6a44287SMartin K. Petersen 
5468f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5469c6a44287SMartin K. Petersen 
5470f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5471c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5472f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5473f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5474f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5475f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5476f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5477f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5478f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5479c6a44287SMartin K. Petersen 
5480773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5481c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5482c6a44287SMartin K. Petersen 	else
5483c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5484c6a44287SMartin K. Petersen 
5485773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5486773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5487c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5488c4837394SDouglas Gilbert 		sdebug_statistics = true;
54891da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
54901da177e4SLinus Torvalds         if (error) {
5491c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
54921da177e4SLinus Torvalds                 error = -ENODEV;
54931da177e4SLinus Torvalds 		scsi_host_put(hpnt);
54941da177e4SLinus Torvalds         } else
54951da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
54961da177e4SLinus Torvalds 
54971da177e4SLinus Torvalds 	return error;
54981da177e4SLinus Torvalds }
54991da177e4SLinus Torvalds 
55001da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
55011da177e4SLinus Torvalds {
55021da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
55038b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55041da177e4SLinus Torvalds 
55051da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55061da177e4SLinus Torvalds 
55071da177e4SLinus Torvalds 	if (!sdbg_host) {
5508c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
55091da177e4SLinus Torvalds 		return -ENODEV;
55101da177e4SLinus Torvalds 	}
55111da177e4SLinus Torvalds 
55121da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
55131da177e4SLinus Torvalds 
55148b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55158b40228fSFUJITA Tomonori 				 dev_list) {
55161da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
55171da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
55181da177e4SLinus Torvalds         }
55191da177e4SLinus Torvalds 
55201da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
55211da177e4SLinus Torvalds         return 0;
55221da177e4SLinus Torvalds }
55231da177e4SLinus Torvalds 
55248dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
55258dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
55261da177e4SLinus Torvalds {
55278dea0d02SFUJITA Tomonori 	return 1;
55288dea0d02SFUJITA Tomonori }
55291da177e4SLinus Torvalds 
55308dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
55318dea0d02SFUJITA Tomonori 	.name = "pseudo",
55328dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
55338dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
55348dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
553582069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
55368dea0d02SFUJITA Tomonori };
5537